@yomotech/view-toolkit 1.0.19 → 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.
@@ -1,4 +1,4 @@
1
- import * as i5 from '@angular/common';
1
+ import * as i9 from '@angular/common';
2
2
  import { CommonModule, NgIf } from '@angular/common';
3
3
  import * as i0 from '@angular/core';
4
4
  import { EventEmitter, HostListener, Output, Input, Component, signal, Injectable, Directive, inject, Pipe, ElementRef, NgZone, ViewChild, HostBinding, NgModule, effect, DestroyRef } from '@angular/core';
@@ -13,7 +13,7 @@ import * as i13 from 'ng-zorro-antd/button';
13
13
  import { NzButtonModule } from 'ng-zorro-antd/button';
14
14
  import * as i4 from 'ng-zorro-antd/date-picker';
15
15
  import { NzDatePickerModule } from 'ng-zorro-antd/date-picker';
16
- import * as i5$1 from 'ng-zorro-antd/modal';
16
+ import * as i5 from 'ng-zorro-antd/modal';
17
17
  import { NzModalModule } from 'ng-zorro-antd/modal';
18
18
  import * as i12 from 'primeng/datepicker';
19
19
  import { DatePickerModule } from 'primeng/datepicker';
@@ -39,7 +39,7 @@ import * as i3 from 'ng-zorro-antd/select';
39
39
  import { NzSelectModule } from 'ng-zorro-antd/select';
40
40
  import * as i7$1 from 'ng-zorro-antd/table';
41
41
  import { NzTableModule } from 'ng-zorro-antd/table';
42
- import * as i9 from 'primeng/button';
42
+ import * as i9$1 from 'primeng/button';
43
43
  import { ButtonModule } from 'primeng/button';
44
44
  import * as i11$2 from 'ng-zorro-antd/dropdown';
45
45
  import { NzDropDownModule } from 'ng-zorro-antd/dropdown';
@@ -290,7 +290,7 @@ class PaginationComponent {
290
290
  this.onGoToPage.emit(page);
291
291
  }
292
292
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.2", ngImport: i0, type: PaginationComponent, deps: [{ token: i1.Platform }], target: i0.ɵɵFactoryTarget.Component });
293
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.2", type: PaginationComponent, isStandalone: true, selector: "vl-pagination", inputs: { itemInfo: "itemInfo", pageSize: "pageSize", currentPage: "currentPage", selectedLanguageInfo: "selectedLanguageInfo", pages: "pages" }, outputs: { pageSizeChange: "pageSizeChange", onGoToPage: "onGoToPage" }, host: { listeners: { "window:resize": "onWindowResize()" } }, ngImport: i0, template: "<div [ngStyle]=\"paginationStyle\">\r\n\r\n <ul [ngStyle]=\"listStyle\" [style.z-index]=\"'auto'\">\r\n\r\n <!-- Existing desktop pagination: unchanged -->\r\n <ng-container *ngIf=\"!isMobile\">\r\n\r\n <li (click)=\"invokeGoToPage(0)\" [ngStyle]=\"getPageItemStyle(undefined, currentPage === 0)\">\r\n \u00AB\u00AB\r\n </li>\r\n\r\n <li (click)=\"invokeGoToPage(currentPage - 1)\" [ngStyle]=\"getPageItemStyle(undefined, currentPage === 0)\">\r\n \u00AB\r\n </li>\r\n\r\n <li *ngFor=\"let page of pages\" (click)=\"invokeGoToPage(page)\" [ngStyle]=\"getPageItemStyle(page)\">\r\n {{ page + 1 }}\r\n </li>\r\n\r\n <li (click)=\"invokeGoToPage(currentPage + 1)\" [ngStyle]=\"\r\n getPageItemStyle(\r\n undefined,\r\n currentPage === pages.length - 1\r\n )\r\n \">\r\n \u00BB\r\n </li>\r\n\r\n <li (click)=\"invokeGoToPage(pages.length - 1)\" [ngStyle]=\"\r\n getPageItemStyle(\r\n undefined,\r\n currentPage === pages.length - 1\r\n )\r\n \">\r\n \u00BB\u00BB\r\n </li>\r\n\r\n </ng-container>\r\n\r\n <!-- Compact mobile pagination -->\r\n <ng-container *ngIf=\"isMobile\">\r\n\r\n <!-- First -->\r\n <li (click)=\"invokeGoToPage(0)\" [ngStyle]=\"getPageItemStyle(undefined, isFirstPage)\">\r\n \u00AB\u00AB\r\n </li>\r\n\r\n <!-- Previous -->\r\n <li (click)=\"invokeGoToPage(currentPage - 1)\" [ngStyle]=\"getPageItemStyle(undefined, isFirstPage)\">\r\n \u00AB\r\n </li>\r\n\r\n <!-- Current page / total pages -->\r\n <li [ngStyle]=\"pageSummaryStyle\">\r\n {{ currentPage + 1 }} / {{ pages.length }}\r\n </li>\r\n\r\n <!-- Next -->\r\n <li (click)=\"invokeGoToPage(currentPage + 1)\" [ngStyle]=\"getPageItemStyle(undefined, isLastPage)\">\r\n \u00BB\r\n </li>\r\n\r\n <!-- Last -->\r\n <li (click)=\"invokeGoToPage(pages.length - 1)\" [ngStyle]=\"getPageItemStyle(undefined, isLastPage)\">\r\n \u00BB\u00BB\r\n </li>\r\n\r\n </ng-container>\r\n\r\n </ul>\r\n\r\n <div *ngIf=\"itemInfo?.layoutSchema?.pagination?.pageSize\" [ngStyle]=\"sizeControlStyle\">\r\n <label for=\"pageSize\" [ngStyle]=\"labelStyle\">\r\n {{ getPaginationCaption() }}\r\n </label>\r\n\r\n <select id=\"pageSize\" [(ngModel)]=\"pageSize\" (change)=\"invokeOnPageSizeChange(pageSize)\"\r\n [ngStyle]=\"selectStyle\">\r\n <option *ngFor=\"\r\n let size of\r\n itemInfo?.layoutSchema\r\n ?.pagination?.pageSizeOptions ||\r\n [5, 10, 15, 20]\r\n \" [value]=\"size\">\r\n {{ size }}\r\n </option>\r\n </select>\r\n </div>\r\n\r\n</div>", styles: [":host{display:block;width:100%;min-width:0;box-sizing:border-box}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i5.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i5.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i5.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i2.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i2.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: PlatformModule }] });
293
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.2", type: PaginationComponent, isStandalone: true, selector: "vl-pagination", inputs: { itemInfo: "itemInfo", pageSize: "pageSize", currentPage: "currentPage", selectedLanguageInfo: "selectedLanguageInfo", pages: "pages" }, outputs: { pageSizeChange: "pageSizeChange", onGoToPage: "onGoToPage" }, host: { listeners: { "window:resize": "onWindowResize()" } }, ngImport: i0, template: "<div [ngStyle]=\"paginationStyle\">\r\n\r\n <ul [ngStyle]=\"listStyle\" [style.z-index]=\"'auto'\">\r\n\r\n <!-- Existing desktop pagination: unchanged -->\r\n <ng-container *ngIf=\"!isMobile\">\r\n\r\n <li (click)=\"invokeGoToPage(0)\" [ngStyle]=\"getPageItemStyle(undefined, currentPage === 0)\">\r\n \u00AB\u00AB\r\n </li>\r\n\r\n <li (click)=\"invokeGoToPage(currentPage - 1)\" [ngStyle]=\"getPageItemStyle(undefined, currentPage === 0)\">\r\n \u00AB\r\n </li>\r\n\r\n <li *ngFor=\"let page of pages\" (click)=\"invokeGoToPage(page)\" [ngStyle]=\"getPageItemStyle(page)\">\r\n {{ page + 1 }}\r\n </li>\r\n\r\n <li (click)=\"invokeGoToPage(currentPage + 1)\" [ngStyle]=\"\r\n getPageItemStyle(\r\n undefined,\r\n currentPage === pages.length - 1\r\n )\r\n \">\r\n \u00BB\r\n </li>\r\n\r\n <li (click)=\"invokeGoToPage(pages.length - 1)\" [ngStyle]=\"\r\n getPageItemStyle(\r\n undefined,\r\n currentPage === pages.length - 1\r\n )\r\n \">\r\n \u00BB\u00BB\r\n </li>\r\n\r\n </ng-container>\r\n\r\n <!-- Compact mobile pagination -->\r\n <ng-container *ngIf=\"isMobile\">\r\n\r\n <!-- First -->\r\n <li (click)=\"invokeGoToPage(0)\" [ngStyle]=\"getPageItemStyle(undefined, isFirstPage)\">\r\n \u00AB\u00AB\r\n </li>\r\n\r\n <!-- Previous -->\r\n <li (click)=\"invokeGoToPage(currentPage - 1)\" [ngStyle]=\"getPageItemStyle(undefined, isFirstPage)\">\r\n \u00AB\r\n </li>\r\n\r\n <!-- Current page / total pages -->\r\n <li [ngStyle]=\"pageSummaryStyle\">\r\n {{ currentPage + 1 }} / {{ pages.length }}\r\n </li>\r\n\r\n <!-- Next -->\r\n <li (click)=\"invokeGoToPage(currentPage + 1)\" [ngStyle]=\"getPageItemStyle(undefined, isLastPage)\">\r\n \u00BB\r\n </li>\r\n\r\n <!-- Last -->\r\n <li (click)=\"invokeGoToPage(pages.length - 1)\" [ngStyle]=\"getPageItemStyle(undefined, isLastPage)\">\r\n \u00BB\u00BB\r\n </li>\r\n\r\n </ng-container>\r\n\r\n </ul>\r\n\r\n <div *ngIf=\"itemInfo?.layoutSchema?.pagination?.pageSize\" [ngStyle]=\"sizeControlStyle\">\r\n <label for=\"pageSize\" [ngStyle]=\"labelStyle\">\r\n {{ getPaginationCaption() }}\r\n </label>\r\n\r\n <select id=\"pageSize\" [(ngModel)]=\"pageSize\" (change)=\"invokeOnPageSizeChange(pageSize)\"\r\n [ngStyle]=\"selectStyle\">\r\n <option *ngFor=\"\r\n let size of\r\n itemInfo?.layoutSchema\r\n ?.pagination?.pageSizeOptions ||\r\n [5, 10, 15, 20]\r\n \" [value]=\"size\">\r\n {{ size }}\r\n </option>\r\n </select>\r\n </div>\r\n\r\n</div>", styles: [":host{display:block;width:100%;min-width:0;box-sizing:border-box}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i9.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i9.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i9.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i2.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i2.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: PlatformModule }] });
294
294
  }
295
295
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.2", ngImport: i0, type: PaginationComponent, decorators: [{
296
296
  type: Component,
@@ -1975,11 +1975,16 @@ class UtilityService {
1975
1975
  authorizationBaseUrl: environment.login.mobile.authorizationBaseUrl,
1976
1976
  accessTokenEndpoint: environment.login.mobile.accessTokenEndpoint,
1977
1977
  redirectUrl: environment.login.mobile.redirectUrl,
1978
- scope: environment.login.mobile.scope,
1978
+ scope: this.oauthScope(environment.login.mobile.scope),
1979
1979
  responseType: environment.login.mobile.responseType,
1980
1980
  pkceEnabled: environment.login.mobile.pkceEnabled
1981
1981
  };
1982
1982
  }
1983
+ /** OAuth scope as the space separated string the OAuth2 plugin expects. */
1984
+ oauthScope(scope) {
1985
+ const value = Array.isArray(scope) ? scope.join(' ') : scope;
1986
+ return value?.trim() || 'openid profile email';
1987
+ }
1983
1988
  async setupStripePaymentForm(environment, form, onCardChange) {
1984
1989
  let hasCreditCard = false;
1985
1990
  if (form.layoutSchema?.formSections) {
@@ -3536,6 +3541,16 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.2", ngImpor
3536
3541
  }]
3537
3542
  }], ctorParameters: () => [{ type: Couchdb }, { type: UtilityService }, { type: i1.Platform }] });
3538
3543
 
3544
+ // Faramarz Yousefian and Agent Toni (Claude Opus 5.5) 2026-10-14
3545
+ // - fix: white cards on the luv2shop start page (signed out / after logout): the untranslated
3546
+ // layout copy was taken while the layout was still empty, and the language pass then wrote the
3547
+ // empty copy over the real layout. The copy is renewed once the layout has content
3548
+ // - fix: a failed save of a time recording in the web (webSaveDb) left the loader turning without
3549
+ // any message; it now stops the loader and shows one. (The CORS cause - P5 sends no CORS
3550
+ // headers - is solved by the backend proxy, shuaib#162/#154)
3551
+ // Faramarz Yousefian and Agent Toni (Claude Opus 5.5) 2026-10-13
3552
+ // - fix: getHorizontalLayoutCaption read layout.label.caption; a horizontal layout without label
3553
+ // threw in the template and the cards stayed half drawn (luv2shop start page: no texts)
3539
3554
  // Faramarz Yousefian and Agent Toni (Claude Opus 5.5) 2026-10-13
3540
3555
  // - new: fields with a backend source (option.autocomplete) load their list through
3541
3556
  // RemoteListService - autocomplete suggestions, dropdown/combobox items; the autocompletes of this
@@ -3672,13 +3687,24 @@ class CardComponent {
3672
3687
  if (isNativePhone()) {
3673
3688
  this.mobileDisplay = true;
3674
3689
  }
3675
- if (changes['itemInfo']) {
3690
+ /*
3691
+ * The untranslated copies the language is applied to. The app fills layoutSchema, header and
3692
+ * footer into the same itemInfo after it arrived (empty) - so a copy taken then stayed empty,
3693
+ * and the next language pass wrote that empty copy over the real layout: white cards (luv2shop
3694
+ * start page). A copy is therefore also taken while it is still empty and the source is not.
3695
+ */
3696
+ const hasContent = (value) => !!value && Object.keys(value).length > 0;
3697
+ if (changes['itemInfo'] || (!hasContent(this.layoutSchemaCopy) && hasContent(this.itemInfo?.layoutSchema))) {
3676
3698
  if (this.itemInfo.layoutSchema) {
3677
3699
  this.layoutSchemaCopy = JSON.parse(JSON.stringify(this.itemInfo.layoutSchema));
3678
3700
  }
3701
+ }
3702
+ if (changes['itemInfo'] || (!hasContent(this.headerSchemaCopy) && hasContent(this.itemInfo?.header))) {
3679
3703
  if (this.itemInfo.header) {
3680
3704
  this.headerSchemaCopy = JSON.parse(JSON.stringify(this.itemInfo.header));
3681
3705
  }
3706
+ }
3707
+ if (changes['itemInfo'] || (!hasContent(this.footerSchemaCopy) && hasContent(this.itemInfo?.footer))) {
3682
3708
  if (this.itemInfo.footer) {
3683
3709
  this.footerSchemaCopy = JSON.parse(JSON.stringify(this.itemInfo.footer));
3684
3710
  }
@@ -3819,7 +3845,7 @@ class CardComponent {
3819
3845
  }
3820
3846
  getHorizontalLayoutCaption(layout) {
3821
3847
  let lang = this.selectedLanguageInfo?.selectedLanguage;
3822
- let caption = layout.label.caption
3848
+ let caption = layout?.label?.caption
3823
3849
  ? layout.label.caption
3824
3850
  : this.itemInfo.propertySchema[this.getScope(layout.scope?.reference)]?.[layout.scope?.reference.split('/').pop()]?.caption;
3825
3851
  return lang && lang[caption] ? lang[caption] : caption;
@@ -4155,6 +4181,12 @@ class CardComponent {
4155
4181
  else {
4156
4182
  this.deleteAllRecord();
4157
4183
  }
4184
+ },
4185
+ error: (error) => {
4186
+ // The loader kept turning and the record stayed without any message.
4187
+ this.safeUpdate(() => this.isLoading = false);
4188
+ console.error('Failed to save time recording', error);
4189
+ this.notificationService.error(this.selectedLanguageInfo?.selectedLanguage?.['saveFailed'] ?? 'The record could not be saved.');
4158
4190
  }
4159
4191
  });
4160
4192
  }
@@ -4319,8 +4351,79 @@ class CardComponent {
4319
4351
  }
4320
4352
  return scope.substring(start, end);
4321
4353
  }
4322
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.2", ngImport: i0, type: CardComponent, deps: [{ token: UtilityService }, { token: i1.Platform }, { token: i1$1.HttpClient }, { token: ConfigService }, { token: i0.ChangeDetectorRef }, { token: i0.NgZone }, { token: i5$1.NzModalService }, { token: NotificationService }, { token: i7.OAuthService }, { token: RequestService }], target: i0.ɵɵFactoryTarget.Component });
4323
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.2", type: CardComponent, isStandalone: true, selector: "vl-card", inputs: { itemInfo: "itemInfo", currentPage: "currentPage", pageSize: "pageSize", selectedLanguageInfo: "selectedLanguageInfo", mobileDisplay: "mobileDisplay", scrollPagination: "scrollPagination", pages: "pages", paginationMode: "paginationMode", paginationLoading: "paginationLoading" }, outputs: { cardButtonClick: "cardButtonClick", cardHeaderButtonClick: "cardHeaderButtonClick", linkDetails: "linkDetails", imageDetails: "imageDetails", onPageSizeChange: "onPageSizeChange", onPageChange: "onPageChange", cardDataChange: "cardDataChange" }, host: { listeners: { "window:resize": "onWindowResize()" } }, viewQueries: [{ propertyName: "scrollPaginationSentinel", first: true, predicate: ["scrollPaginationSentinel"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "<!-- Faramarz Yousefian and Agent Toni (Claude Opus 5.5) 2026-10-13\r\n - new: autocompletes get their suggestions from RemoteListService (completeRemote) -->\r\n<!-- Faramarz Yousefian and Agent Toni (Claude Opus 5.5) 2026-10-13\r\n - fix: the placeholder comes from vlPlaceholder (pipes/placeholder.pipe.ts) - empty where the\r\n project defines none; it showed the text \"undefined\" -->\r\n<!-- Faramarz Yousefian and Agent Toni (Claude Opus 5) 2026-10-07\r\n - change: autocomplete fields take the toolkit string keyboard unless option.keyboardType\r\n names another one ('native' keeps the system keyboard)\r\n - change: the date filter uses the shared picker markup (picker-field, DateTimePickerService) -->\r\n\r\n<!-- shuaib 2026-09-24\r\n - change: card field switches use renderFieldType so legacy checkbox fields render as boolean. -->\r\n\r\n<!-- Faramarz Yousefian and Agent Toni (Claude Opus 5) 2026-09-19\r\n - new: a @contract comment naming the types this container does not render. It carries four\r\n ngSwitch blocks, so the gap belongs to the container and not to one of them -->\r\n\r\n<!-- @contract gap: dateRange, quantity, credit card\r\n reality: a card renders string, number, image, date, time, dropdown, boolean and\r\n autocomplete. Legacy checkbox fields normalize to boolean. dropdown and boolean arrived on 2026-09-18; before that a card\r\n dropped them silently.\r\n failure: a field of a missing type renders empty, with no error.\r\n instead: quantity is grid-only by design; for a dateRange or a credit card use a modal.\r\n seen: this file carries four switch blocks (lines 23, 94, 267, 488) and none of them has\r\n a case for those three - the gap belongs to the container, not to one block -->\r\n\r\n<!-- Loader Spinner -->\r\n\r\n<div *ngIf=\"isLoading\" class=\"loader-overlay\">\r\n <div class=\"spinner\"></div>\r\n</div>\r\n<div class=\"vl-card-runtime\">\r\n <!-- top pagination on card -->\r\n <div *ngIf=\"\r\n itemInfo?.layoutSchema?.pagination?.visible &&\r\n itemInfo?.layoutSchema?.pagination?.top\r\n \" class=\"card-pagination-wrapper\">\r\n <vl-pagination [itemInfo]=\"itemInfo\"\r\n [selectedLanguageInfo]=\"selectedLanguageInfo\" [pageSize]=\"pageSize\"\r\n [currentPage]=\"currentPage\" [pages]=\"pages\"\r\n (pageSizeChange)=\"invokeOnPageSizeChange($event)\"\r\n (onGoToPage)=\"invokeGoToPage($event)\">\r\n </vl-pagination>\r\n </div>\r\n <div *ngIf=\"itemInfo?.header?.elements?.length\" [ngStyle]=\"getHeaderStyle()\"\r\n [class]=\"getStyleWithoutClasses(\r\n itemInfo?.header?.style\r\n ).classes\">\r\n <div *ngFor=\"let element of itemInfo.header?.elements; let c = index\"\r\n [ngStyle]=\"getHeaderElementWrapperStyle(element)\"\r\n [class]=\"element.option?.innerAction && element.option?.innerAction === 'saveAll' && !displayedRecords?.length ? \r\n 'hidden' :getStyleWithoutClasses(element?.wrapperStyle).classes\">\r\n <ng-container\r\n [ngSwitch]=\"renderFieldType(element.scope?.reference && itemInfo.propertySchema[getScope(element.scope?.reference)] ? itemInfo.propertySchema[getScope(element.scope?.reference)][element.scope?.reference.split('/').pop()]?.type : 'default')\">\r\n\r\n <!-- String Control -->\r\n <div *ngSwitchCase=\"'string'\"\r\n [class]=\"element.option?.visible ? 'card-field-wrapper' : 'hidden'\">\r\n\r\n <!-- LABEL -->\r\n <span *ngIf=\"element.label?.caption\"\r\n [style]=\"getStyleWithoutClasses(element.label?.style).style\"\r\n [class]=\"element.label?.style?.classes?.[0]\">\r\n {{ element.label.caption }}\r\n </span>\r\n </div>\r\n\r\n <!-- Date control -->\r\n <div *ngSwitchCase=\"'date'\" class=\"mb-3\">\r\n <span *ngIf=\"element.option.protected\"\r\n [style]=\"getStyleWithoutClasses(element?.label?.style).style\"\r\n [class]=\"element?.label?.style?.classes[0]\">\r\n <vl-string [formField]=\"element\"\r\n [modalItemInfo]=\"itemInfo\">\r\n </vl-string>\r\n </span>\r\n <div *ngIf=\"!element.option.protected\"\r\n [class]=\"element?.layout == 'horizontal' ? 'horizontal-layout' : ''\"\r\n [ngClass]=\"element?.style?.classes[0]\"\r\n [style]=\"getStyleWithoutClasses(element?.style).style\">\r\n <label\r\n [style]=\"getStyleWithoutClasses(element?.label?.style).style\"\r\n [class]=\"element?.label?.style?.classes[0]\">{{\r\n element.label?.value\r\n ?\r\n element.label?.value : element.label?.caption ?\r\n element.label?.caption :\r\n itemInfo.propertySchema[getScope(element.scope?.reference)][element.scope?.reference.split('/').pop()]?.caption\r\n }}</label>\r\n <div class=\"picker-field\">\r\n <p-datepicker #cardDatePicker\r\n (ngModelChange)=\"dateChangeEvent(element, $event)\"\r\n [dateFormat]=\"itemInfo.propertySchema[getScope(element.scope?.reference)][element.scope?.reference.split('/').pop()]?.format ? itemInfo.propertySchema[getScope(element.scope?.reference)][element.scope?.reference.split('/').pop()].format : 'yy-mm-dd'\"\r\n [(ngModel)]=\"itemInfo.propertySchema[getScope(element.scope?.reference)][element.scope?.reference.split('/').pop()].value\"\r\n (onInput)=\"onDateTyping($event)\"\r\n [class]=\"element?.scope?.style?.classes[0]\"\r\n [style]=\"getStyleWithoutClasses(element?.scope?.style).style\"\r\n [showIcon]=\"false\" [showOnFocus]=\"false\"\r\n appendTo=\"body\"\r\n [panelStyleClass]=\"picker.datePanelClass\"\r\n [motionOptions]=\"picker.dockedMotion\"\r\n [vlCustomKeyboard]=\"element?.option?.keyboardType ?? 'date'\"\r\n (pointerdown)=\"picker.onFieldPointerDown($event, cardDatePicker)\"\r\n (onFocus)=\"picker.onFieldFocus($event)\"\r\n (onShow)=\"picker.onShown()\"\r\n (onClose)=\"picker.onClose(cardDatePicker)\">\r\n </p-datepicker>\r\n <button type=\"button\" class=\"picker-field__icon\"\r\n aria-label=\"Open calendar\"\r\n (pointerdown)=\"picker.openFromIcon($event, cardDatePicker)\"\r\n (click)=\"picker.blockIconClick($event)\">\r\n <i class=\"pi pi-calendar\"></i>\r\n </button>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- Button Control -->\r\n <div *ngSwitchCase=\"'default'\"\r\n [class]=\"element.option?.visible ? 'row' : 'hidden'\"\r\n (click)=\"invokeOnCardHeader(element)\">\r\n <button nz-button type=\"button\"\r\n [matTooltip]=\"element?.option?.tooltip || ''\"\r\n [matTooltipTouchGestures]=\"'auto'\"\r\n [ngStyle]=\"getStyleWithoutClasses(element.style).style\"\r\n [class]=\"element.option.protected ? 'disabled-button' : getStyleWithoutClasses(element.style).classes\">\r\n <ng-container\r\n *ngIf=\"!element.caption; else headerTextContent\">\r\n <i nz-icon [nzType]=\"element.icon\"\r\n nzTheme=\"outline\"></i>\r\n </ng-container>\r\n <ng-template #headerTextContent>{{ element.caption\r\n }}</ng-template>\r\n </button>\r\n </div>\r\n </ng-container>\r\n </div>\r\n </div>\r\n <div class=\"card-responsive-grid\" [ngStyle]=\"getCardContainerStyle()\"\r\n [class]=\"getStyleWithoutClasses(\r\n itemInfo?.layoutSchema?.style\r\n ).classes\">\r\n <div *ngFor=\"let record of displayedRecords; let k = index\"\r\n class=\"card-grid-item\">\r\n <div [ngStyle]=\"getSingleCardStyle()\"\r\n [class]=\"getStyleWithoutClasses(itemInfo?.layoutSchema?.stylePerCard).classes\">\r\n <div *ngFor=\"let layout of itemInfo?.layoutSchema?.cards || []\"\r\n class=\"card-layout-item\" [ngStyle]=\"\r\n layout?.type === 'HorizontalLayout'\r\n ? {}\r\n : getStyleWithoutClasses(layout?.style).style\r\n \" [class]=\"\r\n layout?.type === 'HorizontalLayout'\r\n ? ''\r\n : getStyleWithoutClasses(layout?.style).classes\r\n \">\r\n <ng-container\r\n [ngSwitch]=\"renderFieldType(layout?.scope?.reference && itemInfo.propertySchema[getScope(layout.scope?.reference)] ? itemInfo.propertySchema[getScope(layout.scope?.reference)][layout.scope?.reference.split('/').pop()]?.type : layout?.type == 'HorizontalLayout' ? 'HorizontalLayout' : 'default')\">\r\n <!-- Image Control -->\r\n <div *ngSwitchCase=\"'image'\"\r\n [class]=\"layout.option?.visible ? 'row' : 'hidden'\">\r\n <img\r\n [class]=\"getStyleWithoutClasses(layout?.scope?.style).classes\"\r\n [style]=\"getStyleWithoutClasses(layout?.scope?.style).style\"\r\n [src]=\"layout?.option?.src ? layout?.option?.src : record[layout.scope?.reference.split('/').pop()]\"\r\n alt=\"{{ layout.label ? layout.label : getProperty(layout.scope?.reference).productSchema.caption }}\"\r\n (click)=\"showImageDetails(layout.option, record)\" />\r\n </div>\r\n\r\n <!-- String Control -->\r\n <div *ngSwitchCase=\"'string'\"\r\n [class]=\"layout.option?.visible ? 'card-field-wrapper' : 'hidden'\"\r\n [style]=\"getStyleWithoutClasses(layout?.scope?.style).style\">\r\n\r\n <!-- LABEL -->\r\n <span\r\n [ngStyle]=\"getStyleWithoutClasses(layout.label?.style).style\"\r\n [class]=\"getStyleWithoutClasses(layout.label?.style).classes\">\r\n {{ getHorizontalLayoutCaption(layout) }}\r\n </span>\r\n\r\n <!-- VALUE -->\r\n @if(layout.option && layout.option.control &&\r\n !layout.option.protected){\r\n @switch (layout.option.control) {\r\n @case ('textInput') {\r\n <p\r\n *ngIf=\"layout.option?.protected && layout.option?.visible\"\r\n [ngStyle]=\"getStyleWithoutClasses(layout?.scope?.style).style\"\r\n [class]=\"getStyleWithoutClasses(layout?.scope?.style).classes\"\r\n (click)=\"showLinkDetails(layout.option, record)\">\r\n {{\r\n record?.[layout.scope?.reference.split('/').pop()]\r\n ??\r\n itemInfo.propertySchema[getScope(layout.scope?.reference)]?.[layout.scope?.reference.split('/').pop()]?.default\r\n ??\r\n '--'\r\n }}\r\n </p>\r\n }\r\n @case ('password') {\r\n <span>Switch not supported yet</span>\r\n\r\n }\r\n @case ('combobox') {\r\n <span>Combobox not supported yet</span>\r\n }\r\n @case('textArea'){\r\n <span>TextArea not supported yet</span>\r\n }\r\n @case ('switch') {\r\n <span>Switch not supported yet</span>\r\n }\r\n\r\n @case('radiobutton') {\r\n <span>Radiobutton not supported yet</span>\r\n }\r\n\r\n @case ('dropdown') {\r\n <select id=\"dynamic-dropdown\"\r\n #dropdownField=\"ngModel\"\r\n [ngClass]=\"getStyleWithoutClasses(layout?.scope?.style)?.classes\"\r\n [ngStyle]=\"getStyleWithoutClasses(layout?.scope?.style)?.style\"\r\n [name]=\"layout.scope?.reference\"\r\n [(ngModel)]=\"\r\n itemInfo.propertySchema[getScope(layout.scope?.reference)][\r\n layout.scope?.reference.split('/').pop()\r\n ].value\r\n \">\r\n <option *ngFor=\"\r\n let item of itemInfo.propertySchema[getScope(layout.scope?.reference)]?.[\r\n layout.scope?.reference.split('/').pop()\r\n ]?.data\r\n \"\r\n [value]=\"item[layout?.option?.optionValue]\">\r\n {{ item[layout?.option?.optionLabel] }}\r\n </option>\r\n </select>\r\n }\r\n\r\n @case ('autocomplete') {\r\n <p-autocomplete [suggestions]=\"remoteSuggestions[layout.scope?.reference] ?? []\" (completeMethod)=\"completeRemote($event, layout)\" #autocompleteField=\"ngModel\"\r\n [required]=\"layout.option.required\"\r\n [name]=\"layout.scope?.reference\"\r\n styleClass=\"custom-autocomplete\"\r\n [(ngModel)]=\"itemInfo.propertySchema[getScope(layout.scope?.reference)][layout.scope?.reference.split('/').pop()].value\"\r\n [style]=\"getStyleWithoutClasses(layout?.scope?.style).style\"\r\n [class]=\"layout?.scope?.style?.classes ? layout?.scope?.style?.classes[0] : ''\"\r\n [dropdown]=\"true\"\r\n [optionLabel]=\"layout.option.autocomplete.response.label\"\r\n [placeholder]=\"itemInfo.propertySchema | vlPlaceholder: layout.scope?.reference\"\r\n [vlCustomKeyboard]=\"layout?.option?.keyboardType ?? 'string'\">\r\n </p-autocomplete>\r\n }\r\n }\r\n }@else {\r\n <p\r\n *ngIf=\"layout.option?.protected && layout.option?.visible\"\r\n [ngStyle]=\"getStyleWithoutClasses(layout?.scope?.style).style\"\r\n [class]=\"getStyleWithoutClasses(layout?.scope?.style).classes\"\r\n (click)=\"showLinkDetails(layout.option, record)\">\r\n {{\r\n record?.[layout.scope?.reference.split('/').pop()]\r\n ??\r\n itemInfo.propertySchema[getScope(layout.scope?.reference)]?.[layout.scope?.reference.split('/').pop()]?.default\r\n ??\r\n '--'\r\n }}\r\n </p>\r\n }\r\n\r\n </div>\r\n\r\n <!-- Date Control -->\r\n <div *ngSwitchCase=\"'date'\"\r\n [class]=\"layout.option?.visible ? 'card-field-wrapper' : 'hidden'\"\r\n [style]=\"getStyleWithoutClasses(layout?.scope?.style).style\">\r\n <!-- LABEL -->\r\n <span *ngIf=\"layout?.label?.caption\"\r\n [class]=\"layout.label?.style?.classes?.[0]\">\r\n {{ layout.label.caption }}\r\n </span>\r\n\r\n <!-- VALUE -->\r\n <p\r\n *ngIf=\"layout.option?.protected && layout.option?.visible\"\r\n [class]=\"getStyleWithoutClasses(layout?.scope?.style).classes\"\r\n (click)=\"showLinkDetails(layout.option, record)\">\r\n {{\r\n record?.[layout.scope?.reference.split('/').pop()]\r\n ?? itemInfo.propertySchema[\r\n getScope(layout.scope?.reference)\r\n ]?.[layout.scope?.reference.split('/').pop()]?.default\r\n ?? '--'\r\n }}\r\n </p>\r\n </div>\r\n\r\n <!-- Time Control -->\r\n <div *ngSwitchCase=\"'time'\"\r\n [class]=\"layout.option?.visible ? 'card-field-wrapper' : 'hidden'\"\r\n [style]=\"getStyleWithoutClasses(layout?.scope?.style).style\">\r\n\r\n <!-- LABEL -->\r\n <span *ngIf=\"layout?.label?.caption\"\r\n [class]=\"layout.label?.style?.classes?.[0]\">\r\n {{ layout.label.caption }}\r\n </span>\r\n\r\n <!-- VALUE -->\r\n <p\r\n *ngIf=\"layout.option?.protected && layout.option?.visible\"\r\n [class]=\"getStyleWithoutClasses(layout?.scope?.style).classes\"\r\n (click)=\"showLinkDetails(layout.option, record)\">\r\n {{\r\n record?.[layout.scope?.reference.split('/').pop()]\r\n ?? itemInfo.propertySchema[\r\n getScope(layout.scope?.reference)\r\n ]?.[layout.scope?.reference.split('/').pop()]?.default\r\n ?? '--'\r\n }}\r\n </p>\r\n </div>\r\n\r\n <!-- number Control -->\r\n <div *ngSwitchCase=\"'number'\"\r\n [class]=\"layout.option?.visible ? 'row' : 'hidden'\">\r\n <!-- VALUE -->\r\n @if(layout.option && layout.option.control &&\r\n !layout.option.protected){\r\n @switch (layout.option.control) {\r\n @case ('textInput') {\r\n <h3\r\n *ngIf=\"itemInfo.propertySchema[getScope(layout.scope?.reference)] && itemInfo.propertySchema[getScope(layout.scope?.reference)][layout.scope?.reference.split('/').pop()]?.format.currency\"\r\n [class]=\"getStyleWithoutClasses(layout?.scope?.style).classes\"\r\n [style]=\"getStyleWithoutClasses(layout?.scope?.style).style\">\r\n {{\r\n record[layout.scope?.reference.split('/').pop()]\r\n | currency: layout.option?.currency\r\n ?\r\n layout.option.currency\r\n :\r\n 'USD' }}\r\n </h3>\r\n }\r\n @case ('slider') {\r\n <p>Slider not Implemented yet</p>\r\n\r\n }\r\n @case ('spinner') {\r\n <p>Spinner not Implemented yet</p>\r\n }\r\n }\r\n } @else{\r\n <h3\r\n *ngIf=\"itemInfo.propertySchema[getScope(layout.scope?.reference)] && itemInfo.propertySchema[getScope(layout.scope?.reference)][layout.scope?.reference.split('/').pop()]?.format.currency\"\r\n [class]=\"getStyleWithoutClasses(layout?.scope?.style).classes\"\r\n [style]=\"getStyleWithoutClasses(layout?.scope?.style).style\">\r\n {{\r\n record[layout.scope?.reference.split('/').pop()]\r\n | currency: layout.option?.currency\r\n ?\r\n layout.option.currency\r\n :\r\n 'USD' }}\r\n </h3>\r\n }\r\n\r\n </div>\r\n\r\n <!-- dropdown Control -->\r\n <div *ngSwitchCase=\"'dropdown'\"\r\n [class]=\"layout.option?.visible ? 'row' : 'hidden'\">\r\n <h3\r\n *ngIf=\"itemInfo.propertySchema[getScope(layout.scope?.reference)] && itemInfo.propertySchema[getScope(layout.scope?.reference)][layout.scope?.reference.split('/').pop()]?.format.currency\"\r\n [class]=\"getStyleWithoutClasses(layout?.scope?.style).classes\"\r\n [style]=\"getStyleWithoutClasses(layout?.scope?.style).style\">\r\n <select id=\"dynamic-dropdown\"\r\n #dropdownField=\"ngModel\"\r\n [ngClass]=\"getStyleWithoutClasses(layout?.scope?.style)?.classes\"\r\n [ngStyle]=\"getStyleWithoutClasses(layout?.scope?.style)?.style\"\r\n [name]=\"layout.scope?.reference\"\r\n [(ngModel)]=\"\r\n itemInfo.propertySchema[getScope(layout.scope?.reference)][\r\n layout.scope?.reference.split('/').pop()\r\n ].value\r\n \">\r\n <option *ngFor=\"\r\n let item of itemInfo.propertySchema[getScope(layout.scope?.reference)]?.[\r\n layout.scope?.reference.split('/').pop()\r\n ]?.data\r\n \"\r\n [value]=\"item[layout?.option?.optionValue]\">\r\n {{ item[layout?.option?.optionLabel]\r\n }}\r\n </option>\r\n </select>\r\n </h3>\r\n </div>\r\n\r\n <!-- autocomplete Control -->\r\n <div *ngSwitchCase=\"'autocomplete'\"\r\n [class]=\"layout.option?.visible ? 'row' : 'hidden'\">\r\n <h3\r\n *ngIf=\"itemInfo.propertySchema[getScope(layout.scope?.reference)] && itemInfo.propertySchema[getScope(layout.scope?.reference)][layout.scope?.reference.split('/').pop()]?.format.currency\"\r\n [class]=\"getStyleWithoutClasses(layout?.scope?.style).classes\"\r\n [style]=\"getStyleWithoutClasses(layout?.scope?.style).style\">\r\n <p-autocomplete [suggestions]=\"remoteSuggestions[layout.scope?.reference] ?? []\" (completeMethod)=\"completeRemote($event, layout)\" #autocompleteField=\"ngModel\"\r\n [required]=\"layout.option.required\"\r\n [name]=\"layout.scope?.reference\"\r\n styleClass=\"custom-autocomplete\"\r\n [(ngModel)]=\"itemInfo.propertySchema[getScope(layout.scope?.reference)][layout.scope?.reference.split('/').pop()].value\"\r\n [style]=\"getStyleWithoutClasses(layout?.scope?.style).style\"\r\n [class]=\"layout?.scope?.style?.classes ? layout?.scope?.style?.classes[0] : ''\"\r\n [dropdown]=\"true\"\r\n [optionLabel]=\"layout.option.autocomplete.response.label\"\r\n [placeholder]=\"itemInfo.propertySchema | vlPlaceholder: layout.scope?.reference\"\r\n [vlCustomKeyboard]=\"layout?.option?.keyboardType ?? 'string'\">\r\n </p-autocomplete>\r\n </h3>\r\n </div>\r\n\r\n <!-- checkbox Control -->\r\n <div *ngSwitchCase=\"'boolean'\"\r\n [class]=\"layout.option?.visible ? 'row' : 'hidden'\">\r\n <h3\r\n *ngIf=\"itemInfo.propertySchema[getScope(layout.scope?.reference)] && itemInfo.propertySchema[getScope(layout.scope?.reference)][layout.scope?.reference.split('/').pop()]\"\r\n [class]=\"getStyleWithoutClasses(layout?.scope?.style).classes\"\r\n [style]=\"getStyleWithoutClasses(layout?.scope?.style).style\">\r\n <input type=\"checkbox\"\r\n class=\"form-check-input mr-2\"\r\n [(ngModel)]=\"\r\n itemInfo.propertySchema[getScope(layout.scope?.reference)][\r\n layout.scope?.reference.split('/').pop()\r\n ].value\r\n \"\r\n [name]=\"layout.scope?.reference\" />\r\n </h3>\r\n </div>\r\n\r\n <!-- Button Control -->\r\n <div *ngSwitchCase=\"'default'\"\r\n [class]=\"layout.option?.visible ? 'row' : 'hidden'\">\r\n <button\r\n [style]=\"getStyleWithoutClasses(layout?.style).style\"\r\n [class]=\"layout.option.protected ? 'disabled-button' : getStyleWithoutClasses(layout?.style).classes\"\r\n (click)=\"\r\n invokeButtonClick(\r\n layout,\r\n record,\r\n getRecordIndex(record)\r\n )\r\n\">\r\n <ng-container\r\n *ngIf=\"!layout.caption; else textContent\">\r\n <i nz-icon [nzType]=\"layout.icon\"\r\n nzTheme=\"outline\"></i>\r\n </ng-container>\r\n <ng-template #textContent>\r\n {{ layout.caption }}\r\n </ng-template>\r\n </button>\r\n </div>\r\n\r\n <!-- HorizontalLayout Control -->\r\n <div *ngSwitchCase=\"'HorizontalLayout'\">\r\n <div class=\"card-horizontal-layout\"\r\n [class]=\"getStyleWithoutClasses(\r\n layout?.style\r\n ).classes\" [ngStyle]=\"getHorizontalLayoutStyle(layout)\">\r\n <ng-container\r\n *ngFor=\"let innerLayout of layout.elements\">\r\n <ng-container\r\n [ngSwitch]=\"renderFieldType(innerLayout.scope?.reference && itemInfo.propertySchema[getScope(innerLayout.scope?.reference)] ? itemInfo.propertySchema[getScope(innerLayout.scope?.reference)][innerLayout.scope?.reference.split('/').pop()]?.type : 'default')\">\r\n <!-- Image Control -->\r\n <div *ngSwitchCase=\"'image'\"\r\n [class]=\"innerLayout.option?.visible ? 'row' : 'hidden'\">\r\n <img\r\n [class]=\"getStyleWithoutClasses(innerLayout?.scope?.style).classes\"\r\n [style]=\"getStyleWithoutClasses(innerLayout?.scope?.style).style\"\r\n [src]=\"innerLayout?.option?.src ? innerLayout?.option?.src : record[innerLayout.scope?.reference.split('/').pop()]\"\r\n alt=\"{{ innerLayout.label ? innerLayout.label : getProperty(innerLayout.scope?.reference).productSchema.caption }}\"\r\n (click)=\"showImageDetails(innerLayout.option, record)\" />\r\n </div>\r\n\r\n <!-- String Control -->\r\n <div *ngSwitchCase=\"'string'\"\r\n [ngClass]=\"[innerLayout?.option?.visible ? 'card-field-wrapper' : 'hidden',getStyleWithoutClasses(innerLayout?.style).classes]\"\r\n [ngStyle]=\"getStyleWithoutClasses(innerLayout?.style).style\">\r\n\r\n <!-- LABEL -->\r\n <span\r\n [ngStyle]=\"getStyleWithoutClasses(innerLayout.label?.style).style\"\r\n [class]=\"getStyleWithoutClasses(innerLayout.label?.style).classes\">\r\n {{\r\n getHorizontalLayoutCaption(innerLayout)\r\n }}\r\n </span>\r\n\r\n <!-- VALUE -->\r\n @if(innerLayout.option &&\r\n innerLayout.option.control &&\r\n !innerLayout.option.protected){\r\n @switch\r\n (innerLayout.option.control)\r\n {\r\n @case ('textInput') {\r\n <h3\r\n *ngIf=\"innerLayout.option?.protected && innerLayout.option?.visible\"\r\n [class]=\"getStyleWithoutClasses(innerLayout?.scope?.style).classes\"\r\n [ngStyle]=\"getStyleWithoutClasses(innerLayout?.scope?.style).style\"\r\n (click)=\"showLinkDetails(innerLayout.option, record)\">\r\n\r\n <!-- DATE FORMAT -->\r\n <ng-container\r\n *ngIf=\"innerLayout.option?.dateFormat; else checkInnerTime\">\r\n {{\r\n record?.[innerLayout.scope?.reference.split('/').pop()]\r\n ?\r\n (record[innerLayout.scope?.reference.split('/').pop()]\r\n | date:\r\n innerLayout.option.dateFormat)\r\n : '--' }}\r\n </ng-container>\r\n\r\n <!-- TIME FORMAT -->\r\n <ng-template\r\n #checkInnerTime>\r\n <ng-container\r\n *ngIf=\"innerLayout.option?.timeFormat; else normalInnerValue\">\r\n {{\r\n record?.[innerLayout.scope?.reference.split('/').pop()]\r\n ?\r\n (record[innerLayout.scope?.reference.split('/').pop()]\r\n |\r\n date:\r\n innerLayout.option.timeFormat)\r\n : '--' }}\r\n </ng-container>\r\n </ng-template>\r\n\r\n <!-- NORMAL STRING -->\r\n <ng-template\r\n #normalInnerValue>\r\n {{\r\n record?.[innerLayout.scope?.reference.split('/').pop()]\r\n ??\r\n '--' }}\r\n </ng-template>\r\n </h3>\r\n }\r\n @case ('password') {\r\n <span>Switch not supported\r\n yet</span>\r\n\r\n }\r\n @case ('combobox') {\r\n <span>Combobox not supported\r\n yet</span>\r\n }\r\n @case('textArea'){\r\n <span>TextArea not supported\r\n yet</span>\r\n }\r\n @case ('switch') {\r\n <span>Switch not supported\r\n yet</span>\r\n }\r\n\r\n @case('radiobutton') {\r\n <span>Radiobutton not supported\r\n yet</span>\r\n }\r\n\r\n @case ('dropdown') {\r\n <select id=\"dynamic-dropdown\"\r\n #dropdownField=\"ngModel\"\r\n [ngClass]=\"getStyleWithoutClasses(innerLayout?.scope?.style)?.classes\"\r\n [ngStyle]=\"getStyleWithoutClasses(innerLayout?.scope?.style)?.style\"\r\n [name]=\"innerLayout.scope?.reference\"\r\n [(ngModel)]=\"\r\n itemInfo.propertySchema[getScope(innerLayout.scope?.reference)][\r\n innerLayout.scope?.reference.split('/').pop()\r\n ].value\r\n \">\r\n <option *ngFor=\"\r\n let item of itemInfo.propertySchema[getScope(innerLayout.scope?.reference)]?.[\r\n innerLayout.scope?.reference.split('/').pop()\r\n ]?.data\r\n \"\r\n [value]=\"item[innerLayout?.option?.optionValue]\">\r\n {{\r\n item[innerLayout?.option?.optionLabel]\r\n }}\r\n </option>\r\n </select>\r\n }\r\n\r\n @case ('autocomplete') {\r\n\r\n <p-autocomplete [suggestions]=\"remoteSuggestions[innerLayout.scope?.reference] ?? []\" (completeMethod)=\"completeRemote($event, innerLayout)\"\r\n #autocompleteField=\"ngModel\"\r\n [required]=\"innerLayout.option.required\"\r\n [name]=\"innerLayout.scope?.reference\"\r\n styleClass=\"custom-autocomplete\"\r\n [(ngModel)]=\"itemInfo.propertySchema[getScope(innerLayout.scope?.reference)][innerLayout.scope?.reference.split('/').pop()].value\"\r\n [style]=\"getStyleWithoutClasses(innerLayout?.scope?.style).style\"\r\n [class]=\"innerLayout?.scope?.style?.classes ? innerLayout?.scope?.style?.classes[0] : ''\"\r\n [dropdown]=\"true\"\r\n [optionLabel]=\"innerLayout.option.autocomplete.response.label\"\r\n [placeholder]=\"itemInfo.propertySchema | vlPlaceholder: innerLayout.scope?.reference\"\r\n [vlCustomKeyboard]=\"innerLayout?.option?.keyboardType ?? 'string'\">\r\n </p-autocomplete>\r\n }\r\n }\r\n }@else{\r\n\r\n <h3\r\n *ngIf=\"innerLayout.option?.protected && innerLayout.option?.visible\"\r\n [class]=\"getStyleWithoutClasses(innerLayout?.scope?.style).classes\"\r\n [ngStyle]=\"getStyleWithoutClasses(innerLayout?.scope?.style).style\"\r\n (click)=\"showLinkDetails(innerLayout.option, record)\">\r\n\r\n <!-- DATE FORMAT -->\r\n <ng-container\r\n *ngIf=\"innerLayout.option?.dateFormat; else checkInnerTime\">\r\n {{\r\n record?.[innerLayout.scope?.reference.split('/').pop()]\r\n ?\r\n (record[innerLayout.scope?.reference.split('/').pop()]\r\n | date:\r\n innerLayout.option.dateFormat)\r\n : '--' }}\r\n </ng-container>\r\n\r\n <!-- TIME FORMAT -->\r\n <ng-template\r\n #checkInnerTime>\r\n <ng-container\r\n *ngIf=\"innerLayout.option?.timeFormat; else normalInnerValue\">\r\n {{\r\n record?.[innerLayout.scope?.reference.split('/').pop()]\r\n ?\r\n (record[innerLayout.scope?.reference.split('/').pop()]\r\n |\r\n date:\r\n innerLayout.option.timeFormat)\r\n : '--' }}\r\n </ng-container>\r\n </ng-template>\r\n\r\n <!-- NORMAL STRING -->\r\n <ng-template\r\n #normalInnerValue>\r\n {{\r\n record?.[innerLayout.scope?.reference.split('/').pop()]\r\n ??\r\n '--' }}\r\n </ng-template>\r\n </h3>\r\n }\r\n\r\n </div>\r\n\r\n <!-- number Control -->\r\n <div *ngSwitchCase=\"'number'\"\r\n [ngClass]=\"[innerLayout?.option?.visible ? 'card-field-wrapper' : 'hidden',getStyleWithoutClasses(innerLayout?.style).classes]\"\r\n [ngStyle]=\"getStyleWithoutClasses(innerLayout?.style).style\">\r\n <h3\r\n *ngIf=\"itemInfo.propertySchema[getScope(innerLayout.scope?.reference)] && itemInfo.propertySchema[getScope(innerLayout.scope?.reference)][innerLayout.scope?.reference.split('/').pop()]?.format?.currency\"\r\n [class]=\"getStyleWithoutClasses(innerLayout?.scope?.style).classes\"\r\n [ngStyle]=\"getStyleWithoutClasses(innerLayout?.scope?.style).style\">\r\n {{\r\n record[innerLayout.scope?.reference.split('/').pop()]\r\n | currency:\r\n innerLayout.option?.currency\r\n ?\r\n innerLayout.option.currency\r\n :\r\n 'USD'\r\n }}\r\n </h3>\r\n </div>\r\n\r\n <!-- Date Control -->\r\n <div *ngSwitchCase=\"'date'\"\r\n [ngClass]=\"[innerLayout?.option?.visible ? 'card-field-wrapper' : 'hidden',getStyleWithoutClasses(innerLayout?.style).classes]\"\r\n [ngStyle]=\"getStyleWithoutClasses(innerLayout?.style).style\">\r\n <!-- LABEL -->\r\n <span\r\n [ngStyle]=\"getStyleWithoutClasses(innerLayout.label?.style).style\"\r\n [class]=\"getStyleWithoutClasses(innerLayout.label?.style).classes\">\r\n {{\r\n getHorizontalLayoutCaption(innerLayout)\r\n }}\r\n </span>\r\n\r\n <!-- VALUE -->\r\n <h3\r\n *ngIf=\"innerLayout.option?.protected && innerLayout.option?.visible\"\r\n [class]=\"getStyleWithoutClasses(innerLayout?.scope?.style).classes\"\r\n [ngStyle]=\"getStyleWithoutClasses(innerLayout?.scope?.style).style\"\r\n (click)=\"showLinkDetails(innerLayout.option, record)\">\r\n {{\r\n record?.[innerLayout.scope?.reference.split('/').pop()]\r\n ?\r\n (record[innerLayout.scope?.reference.split('/').pop()]\r\n | date:\r\n innerLayout.option?.dateFormat\r\n ?\r\n innerLayout.option?.dateFormat\r\n :\r\n itemInfo.propertySchema[getScope(innerLayout.scope?.reference)]?.[innerLayout.scope?.reference.split('/').pop()]?.format\r\n || 'yyyy-MM-dd') : '--' }}\r\n </h3>\r\n </div>\r\n\r\n <!-- Time Control -->\r\n <div *ngSwitchCase=\"'time'\"\r\n [ngClass]=\"[innerLayout?.option?.visible ? 'card-field-wrapper' : 'hidden',getStyleWithoutClasses(innerLayout?.style).classes]\"\r\n [ngStyle]=\"getStyleWithoutClasses(innerLayout?.style).style\">\r\n\r\n <!-- LABEL -->\r\n <span\r\n [ngStyle]=\"getStyleWithoutClasses(innerLayout.label?.style).style\"\r\n [class]=\"getStyleWithoutClasses(innerLayout.label?.style).classes\">\r\n {{\r\n getHorizontalLayoutCaption(innerLayout)\r\n }}\r\n </span>\r\n\r\n <!-- VALUE -->\r\n <h3\r\n *ngIf=\"innerLayout.option?.protected && innerLayout.option?.visible\"\r\n [class]=\"getStyleWithoutClasses(innerLayout?.scope?.style).classes\"\r\n [ngStyle]=\"getStyleWithoutClasses(innerLayout?.scope?.style).style\"\r\n (click)=\"showLinkDetails(innerLayout.option, record)\">\r\n {{\r\n record?.[innerLayout.scope?.reference.split('/').pop()]\r\n ?\r\n (record[innerLayout.scope?.reference.split('/').pop()]\r\n | date:\r\n innerLayout.option?.timeFormat\r\n ?\r\n innerLayout.option?.timeFormat\r\n :itemInfo.propertySchema[getScope(innerLayout.scope?.reference)]?.[innerLayout.scope?.reference.split('/').pop()]?.format\r\n || 'HH:mm') : '--' }}\r\n </h3>\r\n </div>\r\n\r\n <!-- dropdown Control -->\r\n <div *ngSwitchCase=\"'dropdown'\"\r\n [class]=\"innerLayout.option?.visible ? 'row' : 'hidden'\">\r\n <h3\r\n *ngIf=\"itemInfo.propertySchema[getScope(innerLayout.scope?.reference)] && itemInfo.propertySchema[getScope(innerLayout.scope?.reference)][innerLayout.scope?.reference.split('/').pop()]?.format.currency\"\r\n [class]=\"getStyleWithoutClasses(innerLayout?.scope?.style).classes\"\r\n [style]=\"getStyleWithoutClasses(innerLayout?.scope?.style).style\">\r\n <select\r\n id=\"dynamic-dropdown\"\r\n #dropdownField=\"ngModel\"\r\n [ngClass]=\"getStyleWithoutClasses(innerLayout?.scope?.style)?.classes\"\r\n [ngStyle]=\"getStyleWithoutClasses(innerLayout?.scope?.style)?.style\"\r\n [name]=\"innerLayout.scope?.reference\"\r\n [(ngModel)]=\"\r\n itemInfo.propertySchema[getScope(innerLayout.scope?.reference)][\r\n innerLayout.scope?.reference.split('/').pop()\r\n ].value\r\n \">\r\n <option *ngFor=\"\r\n let item of itemInfo.propertySchema[getScope(innerLayout.scope?.reference)]?.[\r\n innerLayout.scope?.reference.split('/').pop()\r\n ]?.data\r\n \"\r\n [value]=\"item[innerLayout?.option?.optionValue]\">\r\n {{\r\n item[innerLayout?.option?.optionLabel]\r\n }}\r\n </option>\r\n </select>\r\n </h3>\r\n </div>\r\n\r\n <!-- autocomplete Control -->\r\n <div *ngSwitchCase=\"'autocomplete'\"\r\n [class]=\"innerLayout.option?.visible ? 'row' : 'hidden'\">\r\n <h3\r\n *ngIf=\"itemInfo.propertySchema[getScope(innerLayout.scope?.reference)] && itemInfo.propertySchema[getScope(innerLayout.scope?.reference)][innerLayout.scope?.reference.split('/').pop()]?.format.currency\"\r\n [class]=\"getStyleWithoutClasses(innerLayout?.scope?.style).classes\"\r\n [style]=\"getStyleWithoutClasses(innerLayout?.scope?.style).style\">\r\n <p-autocomplete [suggestions]=\"remoteSuggestions[innerLayout.scope?.reference] ?? []\" (completeMethod)=\"completeRemote($event, innerLayout)\"\r\n #autocompleteField=\"ngModel\"\r\n [required]=\"innerLayout.option.required\"\r\n [name]=\"innerLayout.scope?.reference\"\r\n styleClass=\"custom-autocomplete\"\r\n [(ngModel)]=\"itemInfo.propertySchema[getScope(innerLayout.scope?.reference)][innerLayout.scope?.reference.split('/').pop()].value\"\r\n [style]=\"getStyleWithoutClasses(innerLayout?.scope?.style).style\"\r\n [class]=\"innerLayout?.scope?.style?.classes ? innerLayout?.scope?.style?.classes[0] : ''\"\r\n [dropdown]=\"true\"\r\n [optionLabel]=\"innerLayout.option.autocomplete.response.label\"\r\n [placeholder]=\"itemInfo.propertySchema | vlPlaceholder: innerLayout.scope?.reference\"\r\n [vlCustomKeyboard]=\"innerLayout?.option?.keyboardType ?? 'string'\">\r\n </p-autocomplete>\r\n </h3>\r\n </div>\r\n\r\n <!-- checkbox Control -->\r\n <div *ngSwitchCase=\"'boolean'\"\r\n [class]=\"innerLayout.option?.visible ? 'row' : 'hidden'\">\r\n <h3\r\n *ngIf=\"itemInfo.propertySchema[getScope(innerLayout.scope?.reference)] && itemInfo.propertySchema[getScope(innerLayout.scope?.reference)][innerLayout.scope?.reference.split('/').pop()]\"\r\n [class]=\"getStyleWithoutClasses(innerLayout?.scope?.style).classes\"\r\n [style]=\"getStyleWithoutClasses(innerLayout?.scope?.style).style\">\r\n <input type=\"checkbox\"\r\n class=\"form-check-input mr-2\"\r\n [(ngModel)]=\"\r\n itemInfo.propertySchema[getScope(innerLayout.scope?.reference)][\r\n innerLayout.scope?.reference.split('/').pop()\r\n ].value\r\n \"\r\n [name]=\"innerLayout.scope?.reference\" />\r\n </h3>\r\n </div>\r\n\r\n <!-- Button Control -->\r\n <div *ngSwitchCase=\"'default'\">\r\n <button nz-button\r\n [matTooltip]=\"getHorizontalLayoutTooltip(innerLayout)\"\r\n [matTooltipTouchGestures]=\"'auto'\"\r\n [style]=\"getStyleWithoutClasses(innerLayout?.style).style\"\r\n [class]=\"innerLayout.option?.visible ? innerLayout.option.protected ? 'disabled-button' : getStyleWithoutClasses(innerLayout?.style).classes : 'hidden'\"\r\n (click)=\"\r\n invokeButtonClick(\r\n innerLayout,\r\n record,\r\n getRecordIndex(record)\r\n )\r\n\">\r\n <span\r\n class=\"schema-btn-content\">\r\n <i\r\n *ngIf=\"showButtonIcon(innerLayout)\"\r\n nz-icon\r\n [nzType]=\"innerLayout.icon\"\r\n nzTheme=\"outline\">\r\n </i>\r\n\r\n <span\r\n *ngIf=\"showButtonCaption(innerLayout)\">\r\n {{\r\n innerLayout.caption\r\n }}\r\n </span>\r\n\r\n <span *ngIf=\"\r\n !showButtonIcon(innerLayout) &&\r\n !showButtonCaption(innerLayout)\r\n \">\r\n Button\r\n </span>\r\n </span>\r\n </button>\r\n </div>\r\n\r\n </ng-container>\r\n </ng-container>\r\n </div>\r\n </div>\r\n </ng-container>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n <div\r\n *ngIf=\"itemInfo?.footer?.elements && itemInfo?.data && itemInfo?.data.length\"\r\n [class]=\"getStyleWithoutClasses(itemInfo?.footer?.style).classes\">\r\n <span\r\n *ngFor=\"let element of itemInfo.footer?.elements; let c = index\">\r\n <ng-container\r\n [ngSwitch]=\"renderFieldType(element.scope?.reference && itemInfo.propertySchema[getScope(element.scope?.reference)] ? itemInfo.propertySchema[getScope(element.scope?.reference)][element.scope?.reference.split('/').pop()]?.type : 'default')\">\r\n\r\n <!-- Date control -->\r\n <div *ngSwitchCase=\"'date'\" class=\"form-group mb-3\">\r\n <span *ngIf=\"element.option.protected\"\r\n [style]=\"getStyleWithoutClasses(element?.label?.style).style\"\r\n [class]=\"element?.label?.style?.classes[0]\">\r\n <h5>{{\r\n itemInfo.propertySchema[getScope(element.scope?.reference)][element.scope?.reference.split('/').pop()]?.caption\r\n }}\r\n </h5>\r\n </span>\r\n <div *ngIf=\"!element.option.protected\">\r\n <div\r\n [class]=\"element?.layout == 'horizontal' ? 'horizontal-layout' : 'row'\">\r\n <label\r\n [style]=\"getStyleWithoutClasses(element?.label?.style).style\"\r\n [class]=\"element?.label?.style?.classes[0]\">{{\r\n element.label?.value\r\n ?\r\n element.label?.value :\r\n element.label?.caption ?\r\n element.label?.caption :\r\n itemInfo.propertySchema[getScope(element.scope?.reference)][element.scope?.reference.split('/').pop()]?.caption\r\n }}</label>\r\n\r\n <nz-date-picker\r\n [required]=\"element.option.required\"\r\n [name]=\"element.scope?.reference\"\r\n [nzDisabled]=\"element?.option?.disabled\"\r\n (ngModelChange)=\"dateChangeEvent(element, $event)\"\r\n [nzFormat]=\"itemInfo.propertySchema[getScope(element.scope?.reference)][element.scope?.reference.split('/').pop()]?.format ? itemInfo.propertySchema[getScope(element.scope?.reference)][element.scope?.reference.split('/').pop()]?.format : 'yyyy-MM-dd'\"\r\n [(ngModel)]=\"itemInfo.propertySchema[getScope(element.scope?.reference)][element.scope?.reference.split('/').pop()].value\"\r\n [style]=\"getStyleWithoutClasses(element?.style).style\"></nz-date-picker>\r\n </div>\r\n\r\n </div>\r\n </div>\r\n\r\n <!-- Button Control -->\r\n <div *ngSwitchCase=\"'default'\"\r\n [class]=\"element.option?.visible ? 'row' : 'hidden'\"\r\n (click)=\"invokeOnCardFooter(element)\">\r\n <button nz-button\r\n [style]=\"getStyleWithoutClasses(element.style).style\"\r\n [class]=\"element.option.protected ? 'disabled-button' : getStyleWithoutClasses(element.style).classes\">\r\n <ng-container\r\n *ngIf=\"!element.caption; else textContent\">\r\n <i nz-icon [nzType]=\"element.icon\"\r\n nzTheme=\"outline\"></i>\r\n </ng-container>\r\n <ng-template #textContent>\r\n {{ element.caption }}\r\n </ng-template>\r\n </button>\r\n </div>\r\n </ng-container>\r\n </span>\r\n </div>\r\n <!-- bottom pagination on card -->\r\n <div *ngIf=\"\r\n itemInfo?.data.length && \r\n itemInfo?.layoutSchema?.pagination?.visible &&\r\n !itemInfo?.layoutSchema?.pagination?.top &&\r\n !scrollPagination\r\n \" class=\"card-pagination-wrapper\">\r\n <vl-pagination [itemInfo]=\"itemInfo\"\r\n [selectedLanguageInfo]=\"selectedLanguageInfo\"\r\n [pageSize]=\"pageSize\"\r\n [currentPage]=\"currentPage\" [pages]=\"pages\"\r\n (pageSizeChange)=\"invokeOnPageSizeChange($event)\"\r\n (onGoToPage)=\"invokeGoToPage($event)\">\r\n </vl-pagination>\r\n </div>\r\n\r\n @if (scrollPagination) {\r\n <div #scrollPaginationSentinel class=\"scroll-pagination-sentinel\"\r\n aria-hidden=\"true\">\r\n </div>\r\n }\r\n</div>\r\n", styles: [":host{display:block;width:100%;min-width:0}.vl-card-runtime{min-width:0;box-sizing:border-box}.card-responsive-grid{width:100%;min-width:0;box-sizing:border-box}.scroll-pagination-sentinel{width:100%;height:1px}.card-grid-item,.card-layout-item,.card-horizontal-layout,.card-field-wrapper{width:100%;min-width:0;box-sizing:border-box}.card-field-wrapper{overflow-wrap:anywhere}.card-field-wrapper p,.card-field-wrapper h3{margin:0;min-width:0}.card-layout-item img{display:block;max-width:100%;height:auto}.card-layout-item button{max-width:100%;box-sizing:border-box}.schema-btn-content{display:inline-flex;align-items:center;justify-content:center;gap:6px;min-width:0}.hidden{display:none!important}.card-pagination-wrapper{width:100%;min-width:0;box-sizing:border-box;padding:0 10px}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i5.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i5.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i5.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i5.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "directive", type: i5.NgSwitch, selector: "[ngSwitch]", inputs: ["ngSwitch"] }, { kind: "directive", type: i5.NgSwitchCase, selector: "[ngSwitchCase]", inputs: ["ngSwitchCase"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i2.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i2.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { kind: "directive", type: i2.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: NzIconModule }, { kind: "directive", type: i11.NzIconDirective, selector: "nz-icon,[nz-icon]", inputs: ["nzSpin", "nzRotate", "nzType", "nzTheme", "nzTwotoneColor", "nzIconfont"], exportAs: ["nzIcon"] }, { kind: "ngmodule", type: DatePickerModule }, { kind: "component", type: i12.DatePicker, selector: "p-datePicker, p-datepicker, p-date-picker", inputs: ["iconDisplay", "styleClass", "inputStyle", "inputId", "inputStyleClass", "placeholder", "ariaLabelledBy", "ariaLabel", "iconAriaLabel", "dateFormat", "multipleSeparator", "rangeSeparator", "inline", "showOtherMonths", "selectOtherMonths", "showIcon", "icon", "readonlyInput", "shortYearCutoff", "hourFormat", "timeOnly", "stepHour", "stepMinute", "stepSecond", "showSeconds", "showOnFocus", "showWeek", "startWeekFromFirstDayOfYear", "showClear", "dataType", "selectionMode", "maxDateCount", "showButtonBar", "todayButtonStyleClass", "clearButtonStyleClass", "autofocus", "autoZIndex", "baseZIndex", "panelStyleClass", "panelStyle", "keepInvalid", "hideOnDateTimeSelect", "touchUI", "timeSeparator", "focusTrap", "showTransitionOptions", "hideTransitionOptions", "tabindex", "minDate", "maxDate", "disabledDates", "disabledDays", "showTime", "responsiveOptions", "numberOfMonths", "firstDayOfWeek", "view", "defaultDate", "appendTo", "motionOptions"], outputs: ["onFocus", "onBlur", "onClose", "onSelect", "onClear", "onInput", "onTodayClick", "onClearClick", "onMonthChange", "onYearChange", "onClickOutside", "onShow"] }, { kind: "ngmodule", type: NzButtonModule }, { kind: "component", type: i13.NzButtonComponent, selector: "button[nz-button], a[nz-button]", inputs: ["nzBlock", "nzGhost", "nzSearch", "nzLoading", "nzDanger", "disabled", "tabIndex", "nzType", "nzShape", "nzSize"], exportAs: ["nzButton"] }, { kind: "directive", type: i14.ɵNzTransitionPatchDirective, selector: "[nz-button], [nz-icon], nz-icon, [nz-menu-item], [nz-submenu], nz-select-top-control, nz-select-placeholder, nz-input-group", inputs: ["hidden"] }, { kind: "directive", type: i15.NzWaveDirective, selector: "[nz-wave],button[nz-button]:not([nzType=\"link\"]):not([nzType=\"text\"])", inputs: ["nzWaveExtraNode"], exportAs: ["nzWave"] }, { kind: "ngmodule", type: NzDatePickerModule }, { kind: "component", type: i4.NzDatePickerComponent, selector: "nz-date-picker,nz-week-picker,nz-month-picker,nz-quarter-picker,nz-year-picker,nz-range-picker", inputs: ["nzInline", "nzAllowClear", "nzAutoFocus", "nzDisabled", "nzInputReadOnly", "nzOpen", "nzDisabledDate", "nzLocale", "nzPlaceHolder", "nzPopupStyle", "nzDropdownClassName", "nzSize", "nzStatus", "nzFormat", "nzVariant", "nzDateRender", "nzDisabledTime", "nzRenderExtraFooter", "nzShowToday", "nzMode", "nzShowNow", "nzRanges", "nzDefaultPickerValue", "nzSeparator", "nzSuffixIcon", "nzBackdrop", "nzId", "nzPlacement", "nzShowWeekNumber", "nzShowTime"], outputs: ["nzOnPanelChange", "nzOnCalendarChange", "nzOnOk", "nzOnOpenChange"], exportAs: ["nzDatePicker"] }, { kind: "ngmodule", type: NzModalModule }, { kind: "component", type: PaginationComponent, selector: "vl-pagination", inputs: ["itemInfo", "pageSize", "currentPage", "selectedLanguageInfo", "pages"], outputs: ["pageSizeChange", "onGoToPage"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i17.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "component", type: String$1, selector: "vl-string", inputs: ["formField", "modalItemInfo"] }, { kind: "ngmodule", type: AutoCompleteModule }, { kind: "component", type: i18.AutoComplete, selector: "p-autoComplete, p-autocomplete, p-auto-complete", inputs: ["minLength", "minQueryLength", "delay", "panelStyle", "styleClass", "panelStyleClass", "inputStyle", "inputId", "inputStyleClass", "placeholder", "readonly", "scrollHeight", "lazy", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "autoHighlight", "forceSelection", "type", "autoZIndex", "baseZIndex", "ariaLabel", "dropdownAriaLabel", "ariaLabelledBy", "dropdownIcon", "unique", "group", "completeOnFocus", "showClear", "dropdown", "showEmptyMessage", "dropdownMode", "multiple", "addOnTab", "tabindex", "dataKey", "emptyMessage", "showTransitionOptions", "hideTransitionOptions", "autofocus", "autocomplete", "optionGroupChildren", "optionGroupLabel", "overlayOptions", "suggestions", "optionLabel", "optionValue", "id", "searchMessage", "emptySelectionMessage", "selectionMessage", "autoOptionFocus", "selectOnFocus", "searchLocale", "optionDisabled", "focusOnHover", "typeahead", "addOnBlur", "separator", "appendTo", "motionOptions"], outputs: ["completeMethod", "onSelect", "onUnselect", "onAdd", "onFocus", "onBlur", "onDropdownClick", "onClear", "onInputKeydown", "onKeyUp", "onShow", "onHide", "onLazyLoad"] }, { kind: "ngmodule", type: InputTextModule }, { kind: "directive", type: CustomKeyboardDirective, selector: "[vlCustomKeyboard]", inputs: ["vlCustomKeyboard"] }, { kind: "pipe", type: PlaceholderPipe, name: "vlPlaceholder" }, { kind: "pipe", type: i5.CurrencyPipe, name: "currency" }, { kind: "pipe", type: i5.DatePipe, name: "date" }] });
4354
+ getMediaSource(layout, record) {
4355
+ const field = layout?.scope?.reference?.split('/').pop();
4356
+ const value = layout?.option?.src || (field ? record?.[field] : '');
4357
+ return typeof value === 'string' ? value.trim() : '';
4358
+ }
4359
+ getMediaLabel(layout) {
4360
+ const label = layout?.label;
4361
+ if (typeof label === 'string' && label.trim()) {
4362
+ return label;
4363
+ }
4364
+ const reference = layout?.scope?.reference;
4365
+ const field = reference?.split('/').pop();
4366
+ const scope = reference ? this.getScope(reference) : '';
4367
+ return label?.caption
4368
+ || this.itemInfo?.propertySchema?.[scope]?.[field]?.caption
4369
+ || 'Media';
4370
+ }
4371
+ getMediaKind(layout, record) {
4372
+ const source = this.getMediaSource(layout, record);
4373
+ // Base64 sources can identify their type without a filename.
4374
+ const mime = /^data:([^;,]+)/i.exec(source)?.[1]?.toLowerCase();
4375
+ if (mime?.startsWith('image/'))
4376
+ return 'image';
4377
+ if (mime?.startsWith('video/'))
4378
+ return 'video';
4379
+ if (mime?.startsWith('audio/'))
4380
+ return 'audio';
4381
+ if (mime === 'application/pdf')
4382
+ return 'pdf';
4383
+ // Blob and Base64 URLs may have no extension.
4384
+ // Try the original filename/reference as well.
4385
+ const field = layout?.scope?.reference?.split('/').pop();
4386
+ const originalValue = field ? record?.[field] : undefined;
4387
+ const candidates = [
4388
+ source,
4389
+ layout?.option?.fileName,
4390
+ originalValue
4391
+ ];
4392
+ const videos = ['mp4', 'm4v', 'webm', 'mov', 'ogv', 'avi', 'mkv'];
4393
+ const audios = ['mp3', 'wav', 'ogg', 'oga', 'm4a', 'aac', 'flac', 'opus'];
4394
+ const files = [
4395
+ 'doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx',
4396
+ 'txt', 'csv', 'zip', 'rar', '7z'
4397
+ ];
4398
+ for (const candidate of candidates) {
4399
+ if (typeof candidate !== 'string')
4400
+ continue;
4401
+ if (/^(data|blob):/i.test(candidate))
4402
+ continue;
4403
+ // Ignore URL query parameters and fragments.
4404
+ let path = candidate.split(/[?#]/)[0];
4405
+ try {
4406
+ path = decodeURIComponent(path);
4407
+ }
4408
+ catch {
4409
+ // Keep the original path when URL encoding is invalid.
4410
+ }
4411
+ const extension = /\.([a-z0-9]+)$/i.exec(path)?.[1]?.toLowerCase();
4412
+ if (!extension)
4413
+ continue;
4414
+ if (videos.includes(extension))
4415
+ return 'video';
4416
+ if (audios.includes(extension))
4417
+ return 'audio';
4418
+ if (extension === 'pdf')
4419
+ return 'pdf';
4420
+ if (files.includes(extension))
4421
+ return 'file';
4422
+ }
4423
+ return 'image';
4424
+ }
4425
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.2", ngImport: i0, type: CardComponent, deps: [{ token: UtilityService }, { token: i1.Platform }, { token: i1$1.HttpClient }, { token: ConfigService }, { token: i0.ChangeDetectorRef }, { token: i0.NgZone }, { token: i5.NzModalService }, { token: NotificationService }, { token: i7.OAuthService }, { token: RequestService }], target: i0.ɵɵFactoryTarget.Component });
4426
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.2", type: CardComponent, isStandalone: true, selector: "vl-card", inputs: { itemInfo: "itemInfo", currentPage: "currentPage", pageSize: "pageSize", selectedLanguageInfo: "selectedLanguageInfo", mobileDisplay: "mobileDisplay", scrollPagination: "scrollPagination", pages: "pages", paginationMode: "paginationMode", paginationLoading: "paginationLoading" }, outputs: { cardButtonClick: "cardButtonClick", cardHeaderButtonClick: "cardHeaderButtonClick", linkDetails: "linkDetails", imageDetails: "imageDetails", onPageSizeChange: "onPageSizeChange", onPageChange: "onPageChange", cardDataChange: "cardDataChange" }, host: { listeners: { "window:resize": "onWindowResize()" } }, viewQueries: [{ propertyName: "scrollPaginationSentinel", first: true, predicate: ["scrollPaginationSentinel"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "<!-- Faramarz Yousefian and Agent Toni (Claude Opus 5.5) 2026-10-13\r\n - fix: the bottom pagination read itemInfo?.data.length; before the records arrive data is\r\n undefined, the template threw and the cards stayed half drawn (luv2shop start page: one\r\n card without texts)\r\n - fix: the price fields read ...?.format.currency; a property without format threw the same\r\n way (luv2shop: no prices, cards cut off) -->\r\n<!-- Faramarz Yousefian and Agent Toni (Claude Opus 5.5) 2026-10-13\r\n - new: autocompletes get their suggestions from RemoteListService (completeRemote) -->\r\n<!-- Faramarz Yousefian and Agent Toni (Claude Opus 5.5) 2026-10-13\r\n - fix: the placeholder comes from vlPlaceholder (pipes/placeholder.pipe.ts) - empty where the\r\n project defines none; it showed the text \"undefined\" -->\r\n<!-- Faramarz Yousefian and Agent Toni (Claude Opus 5) 2026-10-07\r\n - change: autocomplete fields take the toolkit string keyboard unless option.keyboardType\r\n names another one ('native' keeps the system keyboard)\r\n - change: the date filter uses the shared picker markup (picker-field, DateTimePickerService) -->\r\n\r\n<!-- shuaib 2026-09-24\r\n - change: card field switches use renderFieldType so legacy checkbox fields render as boolean. -->\r\n\r\n<!-- Faramarz Yousefian and Agent Toni (Claude Opus 5) 2026-09-19\r\n - new: a @contract comment naming the types this container does not render. It carries four\r\n ngSwitch blocks, so the gap belongs to the container and not to one of them -->\r\n\r\n<!-- @contract gap: dateRange, quantity, credit card\r\n reality: a card renders string, number, image, date, time, dropdown, boolean and\r\n autocomplete. Legacy checkbox fields normalize to boolean. dropdown and boolean arrived on 2026-09-18; before that a card\r\n dropped them silently.\r\n failure: a field of a missing type renders empty, with no error.\r\n instead: quantity is grid-only by design; for a dateRange or a credit card use a modal.\r\n seen: this file carries four switch blocks (lines 23, 94, 267, 488) and none of them has\r\n a case for those three - the gap belongs to the container, not to one block -->\r\n\r\n<!-- Loader Spinner -->\r\n\r\n<div *ngIf=\"isLoading\" class=\"loader-overlay\">\r\n <div class=\"spinner\"></div>\r\n</div>\r\n<div class=\"vl-card-runtime\">\r\n <!-- top pagination on card -->\r\n <div *ngIf=\"\r\n itemInfo?.layoutSchema?.pagination?.visible &&\r\n itemInfo?.layoutSchema?.pagination?.top\r\n \" class=\"card-pagination-wrapper\">\r\n <vl-pagination [itemInfo]=\"itemInfo\"\r\n [selectedLanguageInfo]=\"selectedLanguageInfo\" [pageSize]=\"pageSize\"\r\n [currentPage]=\"currentPage\" [pages]=\"pages\"\r\n (pageSizeChange)=\"invokeOnPageSizeChange($event)\"\r\n (onGoToPage)=\"invokeGoToPage($event)\">\r\n </vl-pagination>\r\n </div>\r\n <div *ngIf=\"itemInfo?.header?.elements?.length\" [ngStyle]=\"getHeaderStyle()\"\r\n [class]=\"getStyleWithoutClasses(\r\n itemInfo?.header?.style\r\n ).classes\">\r\n <div *ngFor=\"let element of itemInfo.header?.elements; let c = index\"\r\n [ngStyle]=\"getHeaderElementWrapperStyle(element)\"\r\n [class]=\"element.option?.innerAction && element.option?.innerAction === 'saveAll' && !displayedRecords?.length ? \r\n 'hidden' :getStyleWithoutClasses(element?.wrapperStyle).classes\">\r\n <ng-container\r\n [ngSwitch]=\"renderFieldType(element.scope?.reference && itemInfo.propertySchema[getScope(element.scope?.reference)] ? itemInfo.propertySchema[getScope(element.scope?.reference)][element.scope?.reference.split('/').pop()]?.type : 'default')\">\r\n\r\n <!-- String Control -->\r\n <div *ngSwitchCase=\"'string'\"\r\n [class]=\"element.option?.visible ? 'card-field-wrapper' : 'hidden'\">\r\n\r\n <!-- LABEL -->\r\n <span *ngIf=\"element.label?.caption\"\r\n [style]=\"getStyleWithoutClasses(element.label?.style).style\"\r\n [class]=\"element.label?.style?.classes?.[0]\">\r\n {{ element.label.caption }}\r\n </span>\r\n </div>\r\n\r\n <!-- Date control -->\r\n <div *ngSwitchCase=\"'date'\" class=\"mb-3\">\r\n <span *ngIf=\"element.option.protected\"\r\n [style]=\"getStyleWithoutClasses(element?.label?.style).style\"\r\n [class]=\"element?.label?.style?.classes[0]\">\r\n <vl-string [formField]=\"element\"\r\n [modalItemInfo]=\"itemInfo\">\r\n </vl-string>\r\n </span>\r\n <div *ngIf=\"!element.option.protected\"\r\n [class]=\"element?.layout == 'horizontal' ? 'horizontal-layout' : ''\"\r\n [ngClass]=\"element?.style?.classes[0]\"\r\n [style]=\"getStyleWithoutClasses(element?.style).style\">\r\n <label\r\n [style]=\"getStyleWithoutClasses(element?.label?.style).style\"\r\n [class]=\"element?.label?.style?.classes[0]\">{{\r\n element.label?.value\r\n ?\r\n element.label?.value : element.label?.caption ?\r\n element.label?.caption :\r\n itemInfo.propertySchema[getScope(element.scope?.reference)][element.scope?.reference.split('/').pop()]?.caption\r\n }}</label>\r\n <div class=\"picker-field\">\r\n <p-datepicker #cardDatePicker\r\n (ngModelChange)=\"dateChangeEvent(element, $event)\"\r\n [dateFormat]=\"itemInfo.propertySchema[getScope(element.scope?.reference)][element.scope?.reference.split('/').pop()]?.format ? itemInfo.propertySchema[getScope(element.scope?.reference)][element.scope?.reference.split('/').pop()].format : 'yy-mm-dd'\"\r\n [(ngModel)]=\"itemInfo.propertySchema[getScope(element.scope?.reference)][element.scope?.reference.split('/').pop()].value\"\r\n (onInput)=\"onDateTyping($event)\"\r\n [class]=\"element?.scope?.style?.classes[0]\"\r\n [style]=\"getStyleWithoutClasses(element?.scope?.style).style\"\r\n [showIcon]=\"false\" [showOnFocus]=\"false\"\r\n appendTo=\"body\"\r\n [panelStyleClass]=\"picker.datePanelClass\"\r\n [motionOptions]=\"picker.dockedMotion\"\r\n [vlCustomKeyboard]=\"element?.option?.keyboardType ?? 'date'\"\r\n (pointerdown)=\"picker.onFieldPointerDown($event, cardDatePicker)\"\r\n (onFocus)=\"picker.onFieldFocus($event)\"\r\n (onShow)=\"picker.onShown()\"\r\n (onClose)=\"picker.onClose(cardDatePicker)\">\r\n </p-datepicker>\r\n <button type=\"button\" class=\"picker-field__icon\"\r\n aria-label=\"Open calendar\"\r\n (pointerdown)=\"picker.openFromIcon($event, cardDatePicker)\"\r\n (click)=\"picker.blockIconClick($event)\">\r\n <i class=\"pi pi-calendar\"></i>\r\n </button>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- Button Control -->\r\n <div *ngSwitchCase=\"'default'\"\r\n [class]=\"element.option?.visible ? 'row' : 'hidden'\"\r\n (click)=\"invokeOnCardHeader(element)\">\r\n <button nz-button type=\"button\"\r\n [matTooltip]=\"element?.option?.tooltip || ''\"\r\n [matTooltipTouchGestures]=\"'auto'\"\r\n [ngStyle]=\"getStyleWithoutClasses(element.style).style\"\r\n [class]=\"element.option.protected ? 'disabled-button' : getStyleWithoutClasses(element.style).classes\">\r\n <ng-container\r\n *ngIf=\"!element.caption; else headerTextContent\">\r\n <i nz-icon [nzType]=\"element.icon\"\r\n nzTheme=\"outline\"></i>\r\n </ng-container>\r\n <ng-template #headerTextContent>{{ element.caption\r\n }}</ng-template>\r\n </button>\r\n </div>\r\n </ng-container>\r\n </div>\r\n </div>\r\n <div class=\"card-responsive-grid\" [ngStyle]=\"getCardContainerStyle()\"\r\n [class]=\"getStyleWithoutClasses(\r\n itemInfo?.layoutSchema?.style\r\n ).classes\">\r\n <div *ngFor=\"let record of displayedRecords; let k = index\"\r\n class=\"card-grid-item\">\r\n <div [ngStyle]=\"getSingleCardStyle()\"\r\n [class]=\"getStyleWithoutClasses(itemInfo?.layoutSchema?.stylePerCard).classes\">\r\n <div *ngFor=\"let layout of itemInfo?.layoutSchema?.cards || []\"\r\n class=\"card-layout-item\" [ngStyle]=\"\r\n layout?.type === 'HorizontalLayout'\r\n ? {}\r\n : getStyleWithoutClasses(layout?.style).style\r\n \" [class]=\"\r\n layout?.type === 'HorizontalLayout'\r\n ? ''\r\n : getStyleWithoutClasses(layout?.style).classes\r\n \">\r\n <ng-container\r\n [ngSwitch]=\"renderFieldType(layout?.scope?.reference && itemInfo.propertySchema[getScope(layout.scope?.reference)] ? itemInfo.propertySchema[getScope(layout.scope?.reference)][layout.scope?.reference.split('/').pop()]?.type : layout?.type == 'HorizontalLayout' ? 'HorizontalLayout' : 'default')\">\r\n <!-- Media Control -->\r\n <div\r\n *ngSwitchCase=\"'media'\"\r\n [class]=\"layout.option?.visible ? 'row' : 'hidden'\">\r\n <ng-container\r\n *ngTemplateOutlet=\"mediaContent; context: { layout: layout, record: record }\">\r\n </ng-container>\r\n </div>\r\n\r\n <!-- String Control -->\r\n <div *ngSwitchCase=\"'string'\"\r\n [class]=\"layout.option?.visible ? 'card-field-wrapper' : 'hidden'\"\r\n [style]=\"getStyleWithoutClasses(layout?.scope?.style).style\">\r\n\r\n <!-- LABEL -->\r\n <span\r\n [ngStyle]=\"getStyleWithoutClasses(layout.label?.style).style\"\r\n [class]=\"getStyleWithoutClasses(layout.label?.style).classes\">\r\n {{ getHorizontalLayoutCaption(layout) }}\r\n </span>\r\n\r\n <!-- VALUE -->\r\n @if(layout.option && layout.option.control &&\r\n !layout.option.protected){\r\n @switch (layout.option.control) {\r\n @case ('textInput') {\r\n <p\r\n *ngIf=\"layout.option?.protected && layout.option?.visible\"\r\n [ngStyle]=\"getStyleWithoutClasses(layout?.scope?.style).style\"\r\n [class]=\"getStyleWithoutClasses(layout?.scope?.style).classes\"\r\n (click)=\"showLinkDetails(layout.option, record)\">\r\n {{\r\n record?.[layout.scope?.reference.split('/').pop()]\r\n ??\r\n itemInfo.propertySchema[getScope(layout.scope?.reference)]?.[layout.scope?.reference.split('/').pop()]?.default\r\n ??\r\n '--'\r\n }}\r\n </p>\r\n }\r\n @case ('password') {\r\n <span>Switch not supported yet</span>\r\n\r\n }\r\n @case ('combobox') {\r\n <span>Combobox not supported yet</span>\r\n }\r\n @case('textArea'){\r\n <span>TextArea not supported yet</span>\r\n }\r\n @case ('switch') {\r\n <span>Switch not supported yet</span>\r\n }\r\n\r\n @case('radiobutton') {\r\n <span>Radiobutton not supported yet</span>\r\n }\r\n\r\n @case ('dropdown') {\r\n <select id=\"dynamic-dropdown\"\r\n #dropdownField=\"ngModel\"\r\n [ngClass]=\"getStyleWithoutClasses(layout?.scope?.style)?.classes\"\r\n [ngStyle]=\"getStyleWithoutClasses(layout?.scope?.style)?.style\"\r\n [name]=\"layout.scope?.reference\"\r\n [(ngModel)]=\"\r\n itemInfo.propertySchema[getScope(layout.scope?.reference)][\r\n layout.scope?.reference.split('/').pop()\r\n ].value\r\n \">\r\n <option *ngFor=\"\r\n let item of itemInfo.propertySchema[getScope(layout.scope?.reference)]?.[\r\n layout.scope?.reference.split('/').pop()\r\n ]?.data\r\n \"\r\n [value]=\"item[layout?.option?.optionValue]\">\r\n {{ item[layout?.option?.optionLabel] }}\r\n </option>\r\n </select>\r\n }\r\n\r\n @case ('autocomplete') {\r\n <p-autocomplete\r\n [suggestions]=\"remoteSuggestions[layout.scope?.reference] ?? []\"\r\n (completeMethod)=\"completeRemote($event, layout)\"\r\n #autocompleteField=\"ngModel\"\r\n [required]=\"layout.option.required\"\r\n [name]=\"layout.scope?.reference\"\r\n styleClass=\"custom-autocomplete\"\r\n [(ngModel)]=\"itemInfo.propertySchema[getScope(layout.scope?.reference)][layout.scope?.reference.split('/').pop()].value\"\r\n [style]=\"getStyleWithoutClasses(layout?.scope?.style).style\"\r\n [class]=\"layout?.scope?.style?.classes ? layout?.scope?.style?.classes[0] : ''\"\r\n [dropdown]=\"true\"\r\n [optionLabel]=\"layout.option.autocomplete.response.label\"\r\n [placeholder]=\"itemInfo.propertySchema | vlPlaceholder: layout.scope?.reference\"\r\n [vlCustomKeyboard]=\"layout?.option?.keyboardType ?? 'string'\">\r\n </p-autocomplete>\r\n }\r\n }\r\n }@else {\r\n <p\r\n *ngIf=\"layout.option?.protected && layout.option?.visible\"\r\n [ngStyle]=\"getStyleWithoutClasses(layout?.scope?.style).style\"\r\n [class]=\"getStyleWithoutClasses(layout?.scope?.style).classes\"\r\n (click)=\"showLinkDetails(layout.option, record)\">\r\n {{\r\n record?.[layout.scope?.reference.split('/').pop()]\r\n ??\r\n itemInfo.propertySchema[getScope(layout.scope?.reference)]?.[layout.scope?.reference.split('/').pop()]?.default\r\n ??\r\n '--'\r\n }}\r\n </p>\r\n }\r\n\r\n </div>\r\n\r\n <!-- Date Control -->\r\n <div *ngSwitchCase=\"'date'\"\r\n [class]=\"layout.option?.visible ? 'card-field-wrapper' : 'hidden'\"\r\n [style]=\"getStyleWithoutClasses(layout?.scope?.style).style\">\r\n <!-- LABEL -->\r\n <span *ngIf=\"layout?.label?.caption\"\r\n [class]=\"layout.label?.style?.classes?.[0]\">\r\n {{ layout.label.caption }}\r\n </span>\r\n\r\n <!-- VALUE -->\r\n <p\r\n *ngIf=\"layout.option?.protected && layout.option?.visible\"\r\n [class]=\"getStyleWithoutClasses(layout?.scope?.style).classes\"\r\n (click)=\"showLinkDetails(layout.option, record)\">\r\n {{\r\n record?.[layout.scope?.reference.split('/').pop()]\r\n ?? itemInfo.propertySchema[\r\n getScope(layout.scope?.reference)\r\n ]?.[layout.scope?.reference.split('/').pop()]?.default\r\n ?? '--'\r\n }}\r\n </p>\r\n </div>\r\n\r\n <!-- Time Control -->\r\n <div *ngSwitchCase=\"'time'\"\r\n [class]=\"layout.option?.visible ? 'card-field-wrapper' : 'hidden'\"\r\n [style]=\"getStyleWithoutClasses(layout?.scope?.style).style\">\r\n\r\n <!-- LABEL -->\r\n <span *ngIf=\"layout?.label?.caption\"\r\n [class]=\"layout.label?.style?.classes?.[0]\">\r\n {{ layout.label.caption }}\r\n </span>\r\n\r\n <!-- VALUE -->\r\n <p\r\n *ngIf=\"layout.option?.protected && layout.option?.visible\"\r\n [class]=\"getStyleWithoutClasses(layout?.scope?.style).classes\"\r\n (click)=\"showLinkDetails(layout.option, record)\">\r\n {{\r\n record?.[layout.scope?.reference.split('/').pop()]\r\n ?? itemInfo.propertySchema[\r\n getScope(layout.scope?.reference)\r\n ]?.[layout.scope?.reference.split('/').pop()]?.default\r\n ?? '--'\r\n }}\r\n </p>\r\n </div>\r\n\r\n <!-- number Control -->\r\n <div *ngSwitchCase=\"'number'\"\r\n [class]=\"layout.option?.visible ? 'row' : 'hidden'\">\r\n <!-- VALUE -->\r\n @if(layout.option && layout.option.control &&\r\n !layout.option.protected){\r\n @switch (layout.option.control) {\r\n @case ('textInput') {\r\n <h3\r\n *ngIf=\"itemInfo.propertySchema[getScope(layout.scope?.reference)] && itemInfo.propertySchema[getScope(layout.scope?.reference)][layout.scope?.reference.split('/').pop()]?.format?.currency\"\r\n [class]=\"getStyleWithoutClasses(layout?.scope?.style).classes\"\r\n [style]=\"getStyleWithoutClasses(layout?.scope?.style).style\">\r\n {{\r\n record[layout.scope?.reference.split('/').pop()]\r\n | currency: layout.option?.currency\r\n ?\r\n layout.option.currency\r\n :\r\n 'USD' }}\r\n </h3>\r\n }\r\n @case ('slider') {\r\n <p>Slider not Implemented yet</p>\r\n\r\n }\r\n @case ('spinner') {\r\n <p>Spinner not Implemented yet</p>\r\n }\r\n }\r\n } @else{\r\n <h3\r\n *ngIf=\"itemInfo.propertySchema[getScope(layout.scope?.reference)] && itemInfo.propertySchema[getScope(layout.scope?.reference)][layout.scope?.reference.split('/').pop()]?.format?.currency\"\r\n [class]=\"getStyleWithoutClasses(layout?.scope?.style).classes\"\r\n [style]=\"getStyleWithoutClasses(layout?.scope?.style).style\">\r\n {{\r\n record[layout.scope?.reference.split('/').pop()]\r\n | currency: layout.option?.currency\r\n ?\r\n layout.option.currency\r\n :\r\n 'USD' }}\r\n </h3>\r\n }\r\n\r\n </div>\r\n\r\n <!-- dropdown Control -->\r\n <div *ngSwitchCase=\"'dropdown'\"\r\n [class]=\"layout.option?.visible ? 'row' : 'hidden'\">\r\n <h3\r\n *ngIf=\"itemInfo.propertySchema[getScope(layout.scope?.reference)] && itemInfo.propertySchema[getScope(layout.scope?.reference)][layout.scope?.reference.split('/').pop()]?.format?.currency\"\r\n [class]=\"getStyleWithoutClasses(layout?.scope?.style).classes\"\r\n [style]=\"getStyleWithoutClasses(layout?.scope?.style).style\">\r\n <select id=\"dynamic-dropdown\"\r\n #dropdownField=\"ngModel\"\r\n [ngClass]=\"getStyleWithoutClasses(layout?.scope?.style)?.classes\"\r\n [ngStyle]=\"getStyleWithoutClasses(layout?.scope?.style)?.style\"\r\n [name]=\"layout.scope?.reference\"\r\n [(ngModel)]=\"\r\n itemInfo.propertySchema[getScope(layout.scope?.reference)][\r\n layout.scope?.reference.split('/').pop()\r\n ].value\r\n \">\r\n <option *ngFor=\"\r\n let item of itemInfo.propertySchema[getScope(layout.scope?.reference)]?.[\r\n layout.scope?.reference.split('/').pop()\r\n ]?.data\r\n \"\r\n [value]=\"item[layout?.option?.optionValue]\">\r\n {{ item[layout?.option?.optionLabel]\r\n }}\r\n </option>\r\n </select>\r\n </h3>\r\n </div>\r\n\r\n <!-- autocomplete Control -->\r\n <div *ngSwitchCase=\"'autocomplete'\"\r\n [class]=\"layout.option?.visible ? 'row' : 'hidden'\">\r\n <h3\r\n *ngIf=\"itemInfo.propertySchema[getScope(layout.scope?.reference)] && itemInfo.propertySchema[getScope(layout.scope?.reference)][layout.scope?.reference.split('/').pop()]?.format?.currency\"\r\n [class]=\"getStyleWithoutClasses(layout?.scope?.style).classes\"\r\n [style]=\"getStyleWithoutClasses(layout?.scope?.style).style\">\r\n <p-autocomplete\r\n [suggestions]=\"remoteSuggestions[layout.scope?.reference] ?? []\"\r\n (completeMethod)=\"completeRemote($event, layout)\"\r\n #autocompleteField=\"ngModel\"\r\n [required]=\"layout.option.required\"\r\n [name]=\"layout.scope?.reference\"\r\n styleClass=\"custom-autocomplete\"\r\n [(ngModel)]=\"itemInfo.propertySchema[getScope(layout.scope?.reference)][layout.scope?.reference.split('/').pop()].value\"\r\n [style]=\"getStyleWithoutClasses(layout?.scope?.style).style\"\r\n [class]=\"layout?.scope?.style?.classes ? layout?.scope?.style?.classes[0] : ''\"\r\n [dropdown]=\"true\"\r\n [optionLabel]=\"layout.option.autocomplete.response.label\"\r\n [placeholder]=\"itemInfo.propertySchema | vlPlaceholder: layout.scope?.reference\"\r\n [vlCustomKeyboard]=\"layout?.option?.keyboardType ?? 'string'\">\r\n </p-autocomplete>\r\n </h3>\r\n </div>\r\n\r\n <!-- checkbox Control -->\r\n <div *ngSwitchCase=\"'boolean'\"\r\n [class]=\"layout.option?.visible ? 'row' : 'hidden'\">\r\n <h3\r\n *ngIf=\"itemInfo.propertySchema[getScope(layout.scope?.reference)] && itemInfo.propertySchema[getScope(layout.scope?.reference)][layout.scope?.reference.split('/').pop()]\"\r\n [class]=\"getStyleWithoutClasses(layout?.scope?.style).classes\"\r\n [style]=\"getStyleWithoutClasses(layout?.scope?.style).style\">\r\n <input type=\"checkbox\"\r\n class=\"form-check-input mr-2\"\r\n [(ngModel)]=\"\r\n itemInfo.propertySchema[getScope(layout.scope?.reference)][\r\n layout.scope?.reference.split('/').pop()\r\n ].value\r\n \"\r\n [name]=\"layout.scope?.reference\" />\r\n </h3>\r\n </div>\r\n\r\n <!-- Button Control -->\r\n <div *ngSwitchCase=\"'default'\"\r\n [class]=\"layout.option?.visible ? 'row' : 'hidden'\">\r\n <button\r\n [style]=\"getStyleWithoutClasses(layout?.style).style\"\r\n [class]=\"layout.option.protected ? 'disabled-button' : getStyleWithoutClasses(layout?.style).classes\"\r\n (click)=\"\r\n invokeButtonClick(\r\n layout,\r\n record,\r\n getRecordIndex(record)\r\n )\r\n\">\r\n <ng-container\r\n *ngIf=\"!layout.caption; else textContent\">\r\n <i nz-icon [nzType]=\"layout.icon\"\r\n nzTheme=\"outline\"></i>\r\n </ng-container>\r\n <ng-template #textContent>\r\n {{ layout.caption }}\r\n </ng-template>\r\n </button>\r\n </div>\r\n\r\n <!-- HorizontalLayout Control -->\r\n <div *ngSwitchCase=\"'HorizontalLayout'\">\r\n <div class=\"card-horizontal-layout\"\r\n [class]=\"getStyleWithoutClasses(\r\n layout?.style\r\n ).classes\" [ngStyle]=\"getHorizontalLayoutStyle(layout)\">\r\n <ng-container\r\n *ngFor=\"let innerLayout of layout.elements\">\r\n <ng-container\r\n [ngSwitch]=\"renderFieldType(innerLayout.scope?.reference && itemInfo.propertySchema[getScope(innerLayout.scope?.reference)] ? itemInfo.propertySchema[getScope(innerLayout.scope?.reference)][innerLayout.scope?.reference.split('/').pop()]?.type : 'default')\">\r\n <!-- Media Control -->\r\n <div\r\n *ngSwitchCase=\"'media'\"\r\n [class]=\"innerLayout.option?.visible ? 'row' : 'hidden'\">\r\n\r\n <ng-container\r\n *ngTemplateOutlet=\"mediaContent; context: {\r\n layout: innerLayout,\r\n record: record\r\n }\">\r\n </ng-container>\r\n </div>\r\n\r\n <!-- String Control -->\r\n <div *ngSwitchCase=\"'string'\"\r\n [ngClass]=\"[innerLayout?.option?.visible ? 'card-field-wrapper' : 'hidden',getStyleWithoutClasses(innerLayout?.style).classes]\"\r\n [ngStyle]=\"getStyleWithoutClasses(innerLayout?.style).style\">\r\n\r\n <!-- LABEL -->\r\n <span\r\n [ngStyle]=\"getStyleWithoutClasses(innerLayout.label?.style).style\"\r\n [class]=\"getStyleWithoutClasses(innerLayout.label?.style).classes\">\r\n {{\r\n getHorizontalLayoutCaption(innerLayout)\r\n }}\r\n </span>\r\n\r\n <!-- VALUE -->\r\n @if(innerLayout.option &&\r\n innerLayout.option.control &&\r\n !innerLayout.option.protected){\r\n @switch\r\n (innerLayout.option.control)\r\n {\r\n @case ('textInput') {\r\n <h3\r\n *ngIf=\"innerLayout.option?.protected && innerLayout.option?.visible\"\r\n [class]=\"getStyleWithoutClasses(innerLayout?.scope?.style).classes\"\r\n [ngStyle]=\"getStyleWithoutClasses(innerLayout?.scope?.style).style\"\r\n (click)=\"showLinkDetails(innerLayout.option, record)\">\r\n\r\n <!-- DATE FORMAT -->\r\n <ng-container\r\n *ngIf=\"innerLayout.option?.dateFormat; else checkInnerTime\">\r\n {{\r\n record?.[innerLayout.scope?.reference.split('/').pop()]\r\n ?\r\n (record[innerLayout.scope?.reference.split('/').pop()]\r\n | date:\r\n innerLayout.option.dateFormat)\r\n : '--' }}\r\n </ng-container>\r\n\r\n <!-- TIME FORMAT -->\r\n <ng-template\r\n #checkInnerTime>\r\n <ng-container\r\n *ngIf=\"innerLayout.option?.timeFormat; else normalInnerValue\">\r\n {{\r\n record?.[innerLayout.scope?.reference.split('/').pop()]\r\n ?\r\n (record[innerLayout.scope?.reference.split('/').pop()]\r\n |\r\n date:\r\n innerLayout.option.timeFormat)\r\n : '--' }}\r\n </ng-container>\r\n </ng-template>\r\n\r\n <!-- NORMAL STRING -->\r\n <ng-template\r\n #normalInnerValue>\r\n {{\r\n record?.[innerLayout.scope?.reference.split('/').pop()]\r\n ??\r\n '--' }}\r\n </ng-template>\r\n </h3>\r\n }\r\n @case ('password') {\r\n <span>Switch not supported\r\n yet</span>\r\n\r\n }\r\n @case ('combobox') {\r\n <span>Combobox not supported\r\n yet</span>\r\n }\r\n @case('textArea'){\r\n <span>TextArea not supported\r\n yet</span>\r\n }\r\n @case ('switch') {\r\n <span>Switch not supported\r\n yet</span>\r\n }\r\n\r\n @case('radiobutton') {\r\n <span>Radiobutton not supported\r\n yet</span>\r\n }\r\n\r\n @case ('dropdown') {\r\n <select id=\"dynamic-dropdown\"\r\n #dropdownField=\"ngModel\"\r\n [ngClass]=\"getStyleWithoutClasses(innerLayout?.scope?.style)?.classes\"\r\n [ngStyle]=\"getStyleWithoutClasses(innerLayout?.scope?.style)?.style\"\r\n [name]=\"innerLayout.scope?.reference\"\r\n [(ngModel)]=\"\r\n itemInfo.propertySchema[getScope(innerLayout.scope?.reference)][\r\n innerLayout.scope?.reference.split('/').pop()\r\n ].value\r\n \">\r\n <option *ngFor=\"\r\n let item of itemInfo.propertySchema[getScope(innerLayout.scope?.reference)]?.[\r\n innerLayout.scope?.reference.split('/').pop()\r\n ]?.data\r\n \"\r\n [value]=\"item[innerLayout?.option?.optionValue]\">\r\n {{\r\n item[innerLayout?.option?.optionLabel]\r\n }}\r\n </option>\r\n </select>\r\n }\r\n\r\n @case ('autocomplete') {\r\n\r\n <p-autocomplete\r\n [suggestions]=\"remoteSuggestions[innerLayout.scope?.reference] ?? []\"\r\n (completeMethod)=\"completeRemote($event, innerLayout)\"\r\n #autocompleteField=\"ngModel\"\r\n [required]=\"innerLayout.option.required\"\r\n [name]=\"innerLayout.scope?.reference\"\r\n styleClass=\"custom-autocomplete\"\r\n [(ngModel)]=\"itemInfo.propertySchema[getScope(innerLayout.scope?.reference)][innerLayout.scope?.reference.split('/').pop()].value\"\r\n [style]=\"getStyleWithoutClasses(innerLayout?.scope?.style).style\"\r\n [class]=\"innerLayout?.scope?.style?.classes ? innerLayout?.scope?.style?.classes[0] : ''\"\r\n [dropdown]=\"true\"\r\n [optionLabel]=\"innerLayout.option.autocomplete.response.label\"\r\n [placeholder]=\"itemInfo.propertySchema | vlPlaceholder: innerLayout.scope?.reference\"\r\n [vlCustomKeyboard]=\"innerLayout?.option?.keyboardType ?? 'string'\">\r\n </p-autocomplete>\r\n }\r\n }\r\n }@else{\r\n\r\n <h3\r\n *ngIf=\"innerLayout.option?.protected && innerLayout.option?.visible\"\r\n [class]=\"getStyleWithoutClasses(innerLayout?.scope?.style).classes\"\r\n [ngStyle]=\"getStyleWithoutClasses(innerLayout?.scope?.style).style\"\r\n (click)=\"showLinkDetails(innerLayout.option, record)\">\r\n\r\n <!-- DATE FORMAT -->\r\n <ng-container\r\n *ngIf=\"innerLayout.option?.dateFormat; else checkInnerTime\">\r\n {{\r\n record?.[innerLayout.scope?.reference.split('/').pop()]\r\n ?\r\n (record[innerLayout.scope?.reference.split('/').pop()]\r\n | date:\r\n innerLayout.option.dateFormat)\r\n : '--' }}\r\n </ng-container>\r\n\r\n <!-- TIME FORMAT -->\r\n <ng-template\r\n #checkInnerTime>\r\n <ng-container\r\n *ngIf=\"innerLayout.option?.timeFormat; else normalInnerValue\">\r\n {{\r\n record?.[innerLayout.scope?.reference.split('/').pop()]\r\n ?\r\n (record[innerLayout.scope?.reference.split('/').pop()]\r\n |\r\n date:\r\n innerLayout.option.timeFormat)\r\n : '--' }}\r\n </ng-container>\r\n </ng-template>\r\n\r\n <!-- NORMAL STRING -->\r\n <ng-template\r\n #normalInnerValue>\r\n {{\r\n record?.[innerLayout.scope?.reference.split('/').pop()]\r\n ??\r\n '--' }}\r\n </ng-template>\r\n </h3>\r\n }\r\n\r\n </div>\r\n\r\n <!-- number Control -->\r\n <div *ngSwitchCase=\"'number'\"\r\n [ngClass]=\"[innerLayout?.option?.visible ? 'card-field-wrapper' : 'hidden',getStyleWithoutClasses(innerLayout?.style).classes]\"\r\n [ngStyle]=\"getStyleWithoutClasses(innerLayout?.style).style\">\r\n <h3\r\n *ngIf=\"itemInfo.propertySchema[getScope(innerLayout.scope?.reference)] && itemInfo.propertySchema[getScope(innerLayout.scope?.reference)][innerLayout.scope?.reference.split('/').pop()]?.format?.currency\"\r\n [class]=\"getStyleWithoutClasses(innerLayout?.scope?.style).classes\"\r\n [ngStyle]=\"getStyleWithoutClasses(innerLayout?.scope?.style).style\">\r\n {{\r\n record[innerLayout.scope?.reference.split('/').pop()]\r\n | currency:\r\n innerLayout.option?.currency\r\n ?\r\n innerLayout.option.currency\r\n :\r\n 'USD'\r\n }}\r\n </h3>\r\n </div>\r\n\r\n <!-- Date Control -->\r\n <div *ngSwitchCase=\"'date'\"\r\n [ngClass]=\"[innerLayout?.option?.visible ? 'card-field-wrapper' : 'hidden',getStyleWithoutClasses(innerLayout?.style).classes]\"\r\n [ngStyle]=\"getStyleWithoutClasses(innerLayout?.style).style\">\r\n <!-- LABEL -->\r\n <span\r\n [ngStyle]=\"getStyleWithoutClasses(innerLayout.label?.style).style\"\r\n [class]=\"getStyleWithoutClasses(innerLayout.label?.style).classes\">\r\n {{\r\n getHorizontalLayoutCaption(innerLayout)\r\n }}\r\n </span>\r\n\r\n <!-- VALUE -->\r\n <h3\r\n *ngIf=\"innerLayout.option?.protected && innerLayout.option?.visible\"\r\n [class]=\"getStyleWithoutClasses(innerLayout?.scope?.style).classes\"\r\n [ngStyle]=\"getStyleWithoutClasses(innerLayout?.scope?.style).style\"\r\n (click)=\"showLinkDetails(innerLayout.option, record)\">\r\n {{\r\n record?.[innerLayout.scope?.reference.split('/').pop()]\r\n ?\r\n (record[innerLayout.scope?.reference.split('/').pop()]\r\n | date:\r\n innerLayout.option?.dateFormat\r\n ?\r\n innerLayout.option?.dateFormat\r\n :\r\n itemInfo.propertySchema[getScope(innerLayout.scope?.reference)]?.[innerLayout.scope?.reference.split('/').pop()]?.format\r\n || 'yyyy-MM-dd') : '--' }}\r\n </h3>\r\n </div>\r\n\r\n <!-- Time Control -->\r\n <div *ngSwitchCase=\"'time'\"\r\n [ngClass]=\"[innerLayout?.option?.visible ? 'card-field-wrapper' : 'hidden',getStyleWithoutClasses(innerLayout?.style).classes]\"\r\n [ngStyle]=\"getStyleWithoutClasses(innerLayout?.style).style\">\r\n\r\n <!-- LABEL -->\r\n <span\r\n [ngStyle]=\"getStyleWithoutClasses(innerLayout.label?.style).style\"\r\n [class]=\"getStyleWithoutClasses(innerLayout.label?.style).classes\">\r\n {{\r\n getHorizontalLayoutCaption(innerLayout)\r\n }}\r\n </span>\r\n\r\n <!-- VALUE -->\r\n <h3\r\n *ngIf=\"innerLayout.option?.protected && innerLayout.option?.visible\"\r\n [class]=\"getStyleWithoutClasses(innerLayout?.scope?.style).classes\"\r\n [ngStyle]=\"getStyleWithoutClasses(innerLayout?.scope?.style).style\"\r\n (click)=\"showLinkDetails(innerLayout.option, record)\">\r\n {{\r\n record?.[innerLayout.scope?.reference.split('/').pop()]\r\n ?\r\n (record[innerLayout.scope?.reference.split('/').pop()]\r\n | date:\r\n innerLayout.option?.timeFormat\r\n ?\r\n innerLayout.option?.timeFormat\r\n :itemInfo.propertySchema[getScope(innerLayout.scope?.reference)]?.[innerLayout.scope?.reference.split('/').pop()]?.format\r\n || 'HH:mm') : '--' }}\r\n </h3>\r\n </div>\r\n\r\n <!-- dropdown Control -->\r\n <div *ngSwitchCase=\"'dropdown'\"\r\n [class]=\"innerLayout.option?.visible ? 'row' : 'hidden'\">\r\n <h3\r\n *ngIf=\"itemInfo.propertySchema[getScope(innerLayout.scope?.reference)] && itemInfo.propertySchema[getScope(innerLayout.scope?.reference)][innerLayout.scope?.reference.split('/').pop()]?.format?.currency\"\r\n [class]=\"getStyleWithoutClasses(innerLayout?.scope?.style).classes\"\r\n [style]=\"getStyleWithoutClasses(innerLayout?.scope?.style).style\">\r\n <select\r\n id=\"dynamic-dropdown\"\r\n #dropdownField=\"ngModel\"\r\n [ngClass]=\"getStyleWithoutClasses(innerLayout?.scope?.style)?.classes\"\r\n [ngStyle]=\"getStyleWithoutClasses(innerLayout?.scope?.style)?.style\"\r\n [name]=\"innerLayout.scope?.reference\"\r\n [(ngModel)]=\"\r\n itemInfo.propertySchema[getScope(innerLayout.scope?.reference)][\r\n innerLayout.scope?.reference.split('/').pop()\r\n ].value\r\n \">\r\n <option *ngFor=\"\r\n let item of itemInfo.propertySchema[getScope(innerLayout.scope?.reference)]?.[\r\n innerLayout.scope?.reference.split('/').pop()\r\n ]?.data\r\n \"\r\n [value]=\"item[innerLayout?.option?.optionValue]\">\r\n {{\r\n item[innerLayout?.option?.optionLabel]\r\n }}\r\n </option>\r\n </select>\r\n </h3>\r\n </div>\r\n\r\n <!-- autocomplete Control -->\r\n <div *ngSwitchCase=\"'autocomplete'\"\r\n [class]=\"innerLayout.option?.visible ? 'row' : 'hidden'\">\r\n <h3\r\n *ngIf=\"itemInfo.propertySchema[getScope(innerLayout.scope?.reference)] && itemInfo.propertySchema[getScope(innerLayout.scope?.reference)][innerLayout.scope?.reference.split('/').pop()]?.format?.currency\"\r\n [class]=\"getStyleWithoutClasses(innerLayout?.scope?.style).classes\"\r\n [style]=\"getStyleWithoutClasses(innerLayout?.scope?.style).style\">\r\n <p-autocomplete\r\n [suggestions]=\"remoteSuggestions[innerLayout.scope?.reference] ?? []\"\r\n (completeMethod)=\"completeRemote($event, innerLayout)\"\r\n #autocompleteField=\"ngModel\"\r\n [required]=\"innerLayout.option.required\"\r\n [name]=\"innerLayout.scope?.reference\"\r\n styleClass=\"custom-autocomplete\"\r\n [(ngModel)]=\"itemInfo.propertySchema[getScope(innerLayout.scope?.reference)][innerLayout.scope?.reference.split('/').pop()].value\"\r\n [style]=\"getStyleWithoutClasses(innerLayout?.scope?.style).style\"\r\n [class]=\"innerLayout?.scope?.style?.classes ? innerLayout?.scope?.style?.classes[0] : ''\"\r\n [dropdown]=\"true\"\r\n [optionLabel]=\"innerLayout.option.autocomplete.response.label\"\r\n [placeholder]=\"itemInfo.propertySchema | vlPlaceholder: innerLayout.scope?.reference\"\r\n [vlCustomKeyboard]=\"innerLayout?.option?.keyboardType ?? 'string'\">\r\n </p-autocomplete>\r\n </h3>\r\n </div>\r\n\r\n <!-- checkbox Control -->\r\n <div *ngSwitchCase=\"'boolean'\"\r\n [class]=\"innerLayout.option?.visible ? 'row' : 'hidden'\">\r\n <h3\r\n *ngIf=\"itemInfo.propertySchema[getScope(innerLayout.scope?.reference)] && itemInfo.propertySchema[getScope(innerLayout.scope?.reference)][innerLayout.scope?.reference.split('/').pop()]\"\r\n [class]=\"getStyleWithoutClasses(innerLayout?.scope?.style).classes\"\r\n [style]=\"getStyleWithoutClasses(innerLayout?.scope?.style).style\">\r\n <input type=\"checkbox\"\r\n class=\"form-check-input mr-2\"\r\n [(ngModel)]=\"\r\n itemInfo.propertySchema[getScope(innerLayout.scope?.reference)][\r\n innerLayout.scope?.reference.split('/').pop()\r\n ].value\r\n \"\r\n [name]=\"innerLayout.scope?.reference\" />\r\n </h3>\r\n </div>\r\n\r\n <!-- Button Control -->\r\n <div *ngSwitchCase=\"'default'\">\r\n <button nz-button\r\n [matTooltip]=\"getHorizontalLayoutTooltip(innerLayout)\"\r\n [matTooltipTouchGestures]=\"'auto'\"\r\n [style]=\"getStyleWithoutClasses(innerLayout?.style).style\"\r\n [class]=\"innerLayout.option?.visible ? innerLayout.option.protected ? 'disabled-button' : getStyleWithoutClasses(innerLayout?.style).classes : 'hidden'\"\r\n (click)=\"\r\n invokeButtonClick(\r\n innerLayout,\r\n record,\r\n getRecordIndex(record)\r\n )\r\n\">\r\n <span\r\n class=\"schema-btn-content\">\r\n <i\r\n *ngIf=\"showButtonIcon(innerLayout)\"\r\n nz-icon\r\n [nzType]=\"innerLayout.icon\"\r\n nzTheme=\"outline\">\r\n </i>\r\n\r\n <span\r\n *ngIf=\"showButtonCaption(innerLayout)\">\r\n {{\r\n innerLayout.caption\r\n }}\r\n </span>\r\n\r\n <span *ngIf=\"\r\n !showButtonIcon(innerLayout) &&\r\n !showButtonCaption(innerLayout)\r\n \">\r\n Button\r\n </span>\r\n </span>\r\n </button>\r\n </div>\r\n\r\n </ng-container>\r\n </ng-container>\r\n </div>\r\n </div>\r\n </ng-container>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n <div\r\n *ngIf=\"itemInfo?.footer?.elements && itemInfo?.data && itemInfo?.data.length\"\r\n [class]=\"getStyleWithoutClasses(itemInfo?.footer?.style).classes\">\r\n <span\r\n *ngFor=\"let element of itemInfo.footer?.elements; let c = index\">\r\n <ng-container\r\n [ngSwitch]=\"renderFieldType(element.scope?.reference && itemInfo.propertySchema[getScope(element.scope?.reference)] ? itemInfo.propertySchema[getScope(element.scope?.reference)][element.scope?.reference.split('/').pop()]?.type : 'default')\">\r\n\r\n <!-- Date control -->\r\n <div *ngSwitchCase=\"'date'\" class=\"form-group mb-3\">\r\n <span *ngIf=\"element.option.protected\"\r\n [style]=\"getStyleWithoutClasses(element?.label?.style).style\"\r\n [class]=\"element?.label?.style?.classes[0]\">\r\n <h5>{{\r\n itemInfo.propertySchema[getScope(element.scope?.reference)][element.scope?.reference.split('/').pop()]?.caption\r\n }}\r\n </h5>\r\n </span>\r\n <div *ngIf=\"!element.option.protected\">\r\n <div\r\n [class]=\"element?.layout == 'horizontal' ? 'horizontal-layout' : 'row'\">\r\n <label\r\n [style]=\"getStyleWithoutClasses(element?.label?.style).style\"\r\n [class]=\"element?.label?.style?.classes[0]\">{{\r\n element.label?.value\r\n ?\r\n element.label?.value :\r\n element.label?.caption ?\r\n element.label?.caption :\r\n itemInfo.propertySchema[getScope(element.scope?.reference)][element.scope?.reference.split('/').pop()]?.caption\r\n }}</label>\r\n\r\n <nz-date-picker\r\n [required]=\"element.option.required\"\r\n [name]=\"element.scope?.reference\"\r\n [nzDisabled]=\"element?.option?.disabled\"\r\n (ngModelChange)=\"dateChangeEvent(element, $event)\"\r\n [nzFormat]=\"itemInfo.propertySchema[getScope(element.scope?.reference)][element.scope?.reference.split('/').pop()]?.format ? itemInfo.propertySchema[getScope(element.scope?.reference)][element.scope?.reference.split('/').pop()]?.format : 'yyyy-MM-dd'\"\r\n [(ngModel)]=\"itemInfo.propertySchema[getScope(element.scope?.reference)][element.scope?.reference.split('/').pop()].value\"\r\n [style]=\"getStyleWithoutClasses(element?.style).style\"></nz-date-picker>\r\n </div>\r\n\r\n </div>\r\n </div>\r\n\r\n <!-- Button Control -->\r\n <div *ngSwitchCase=\"'default'\"\r\n [class]=\"element.option?.visible ? 'row' : 'hidden'\"\r\n (click)=\"invokeOnCardFooter(element)\">\r\n <button nz-button\r\n [style]=\"getStyleWithoutClasses(element.style).style\"\r\n [class]=\"element.option.protected ? 'disabled-button' : getStyleWithoutClasses(element.style).classes\">\r\n <ng-container\r\n *ngIf=\"!element.caption; else textContent\">\r\n <i nz-icon [nzType]=\"element.icon\"\r\n nzTheme=\"outline\"></i>\r\n </ng-container>\r\n <ng-template #textContent>\r\n {{ element.caption }}\r\n </ng-template>\r\n </button>\r\n </div>\r\n </ng-container>\r\n </span>\r\n </div>\r\n <!-- bottom pagination on card -->\r\n <div *ngIf=\"\r\n itemInfo?.data?.length && \r\n itemInfo?.layoutSchema?.pagination?.visible &&\r\n !itemInfo?.layoutSchema?.pagination?.top &&\r\n !scrollPagination\r\n \" class=\"card-pagination-wrapper\">\r\n <vl-pagination [itemInfo]=\"itemInfo\"\r\n [selectedLanguageInfo]=\"selectedLanguageInfo\"\r\n [pageSize]=\"pageSize\"\r\n [currentPage]=\"currentPage\" [pages]=\"pages\"\r\n (pageSizeChange)=\"invokeOnPageSizeChange($event)\"\r\n (onGoToPage)=\"invokeGoToPage($event)\">\r\n </vl-pagination>\r\n </div>\r\n\r\n @if (scrollPagination) {\r\n <div #scrollPaginationSentinel class=\"scroll-pagination-sentinel\"\r\n aria-hidden=\"true\">\r\n </div>\r\n }\r\n</div>\r\n<ng-template #mediaContent let-layout=\"layout\" let-record=\"record\">\r\n <ng-container *ngIf=\"getMediaSource(layout, record) as source\">\r\n <ng-container [ngSwitch]=\"getMediaKind(layout, record)\">\r\n\r\n <!-- Default: image. Keep your existing image-click behaviour. -->\r\n <img\r\n *ngSwitchDefault\r\n [class]=\"getStyleWithoutClasses(layout?.scope?.style).classes\"\r\n [ngStyle]=\"getStyleWithoutClasses(layout?.scope?.style).style\"\r\n [src]=\"source\"\r\n [alt]=\"getMediaLabel(layout)\"\r\n loading=\"lazy\"\r\n (click)=\"showImageDetails(layout.option, record)\" />\r\n\r\n <video\r\n *ngSwitchCase=\"'video'\"\r\n [class]=\"getStyleWithoutClasses(layout?.scope?.style).classes\"\r\n [ngStyle]=\"getStyleWithoutClasses(layout?.scope?.style).style\"\r\n [src]=\"source\"\r\n [attr.aria-label]=\"getMediaLabel(layout)\"\r\n controls\r\n playsinline\r\n preload=\"metadata\">\r\n Your browser does not support video playback.\r\n </video>\r\n\r\n <audio\r\n *ngSwitchCase=\"'audio'\"\r\n [class]=\"getStyleWithoutClasses(layout?.scope?.style).classes\"\r\n [ngStyle]=\"getStyleWithoutClasses(layout?.scope?.style).style\"\r\n [src]=\"source\"\r\n [attr.aria-label]=\"getMediaLabel(layout)\"\r\n controls\r\n preload=\"metadata\">\r\n Your browser does not support audio playback.\r\n </audio>\r\n\r\n <a\r\n *ngSwitchCase=\"'pdf'\"\r\n [class]=\"getStyleWithoutClasses(layout?.scope?.style).classes\"\r\n [ngStyle]=\"getStyleWithoutClasses(layout?.scope?.style).style\"\r\n [href]=\"source\"\r\n target=\"_blank\"\r\n rel=\"noopener noreferrer\">\r\n Open PDF \u2014 {{ getMediaLabel(layout) }}\r\n </a>\r\n\r\n <a\r\n *ngSwitchCase=\"'file'\"\r\n [class]=\"getStyleWithoutClasses(layout?.scope?.style).classes\"\r\n [ngStyle]=\"getStyleWithoutClasses(layout?.scope?.style).style\"\r\n [href]=\"source\"\r\n target=\"_blank\"\r\n rel=\"noopener noreferrer\">\r\n Open file \u2014 {{ getMediaLabel(layout) }}\r\n </a>\r\n\r\n </ng-container>\r\n </ng-container>\r\n</ng-template>", styles: [":host{display:block;width:100%;min-width:0}.vl-card-runtime{min-width:0;box-sizing:border-box}.card-responsive-grid{width:100%;min-width:0;box-sizing:border-box}.scroll-pagination-sentinel{width:100%;height:1px}.card-grid-item,.card-layout-item,.card-horizontal-layout,.card-field-wrapper{width:100%;min-width:0;box-sizing:border-box}.card-field-wrapper{overflow-wrap:anywhere}.card-field-wrapper p,.card-field-wrapper h3{margin:0;min-width:0}.card-layout-item img{display:block;max-width:100%;height:auto}.card-layout-item button{max-width:100%;box-sizing:border-box}.schema-btn-content{display:inline-flex;align-items:center;justify-content:center;gap:6px;min-width:0}.hidden{display:none!important}.card-pagination-wrapper{width:100%;min-width:0;box-sizing:border-box;padding:0 10px}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i9.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i9.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i9.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i9.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: i9.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "directive", type: i9.NgSwitch, selector: "[ngSwitch]", inputs: ["ngSwitch"] }, { kind: "directive", type: i9.NgSwitchCase, selector: "[ngSwitchCase]", inputs: ["ngSwitchCase"] }, { kind: "directive", type: i9.NgSwitchDefault, selector: "[ngSwitchDefault]" }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i2.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i2.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { kind: "directive", type: i2.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: NzIconModule }, { kind: "directive", type: i11.NzIconDirective, selector: "nz-icon,[nz-icon]", inputs: ["nzSpin", "nzRotate", "nzType", "nzTheme", "nzTwotoneColor", "nzIconfont"], exportAs: ["nzIcon"] }, { kind: "ngmodule", type: DatePickerModule }, { kind: "component", type: i12.DatePicker, selector: "p-datePicker, p-datepicker, p-date-picker", inputs: ["iconDisplay", "styleClass", "inputStyle", "inputId", "inputStyleClass", "placeholder", "ariaLabelledBy", "ariaLabel", "iconAriaLabel", "dateFormat", "multipleSeparator", "rangeSeparator", "inline", "showOtherMonths", "selectOtherMonths", "showIcon", "icon", "readonlyInput", "shortYearCutoff", "hourFormat", "timeOnly", "stepHour", "stepMinute", "stepSecond", "showSeconds", "showOnFocus", "showWeek", "startWeekFromFirstDayOfYear", "showClear", "dataType", "selectionMode", "maxDateCount", "showButtonBar", "todayButtonStyleClass", "clearButtonStyleClass", "autofocus", "autoZIndex", "baseZIndex", "panelStyleClass", "panelStyle", "keepInvalid", "hideOnDateTimeSelect", "touchUI", "timeSeparator", "focusTrap", "showTransitionOptions", "hideTransitionOptions", "tabindex", "minDate", "maxDate", "disabledDates", "disabledDays", "showTime", "responsiveOptions", "numberOfMonths", "firstDayOfWeek", "view", "defaultDate", "appendTo", "motionOptions"], outputs: ["onFocus", "onBlur", "onClose", "onSelect", "onClear", "onInput", "onTodayClick", "onClearClick", "onMonthChange", "onYearChange", "onClickOutside", "onShow"] }, { kind: "ngmodule", type: NzButtonModule }, { kind: "component", type: i13.NzButtonComponent, selector: "button[nz-button], a[nz-button]", inputs: ["nzBlock", "nzGhost", "nzSearch", "nzLoading", "nzDanger", "disabled", "tabIndex", "nzType", "nzShape", "nzSize"], exportAs: ["nzButton"] }, { kind: "directive", type: i14.ɵNzTransitionPatchDirective, selector: "[nz-button], [nz-icon], nz-icon, [nz-menu-item], [nz-submenu], nz-select-top-control, nz-select-placeholder, nz-input-group", inputs: ["hidden"] }, { kind: "directive", type: i15.NzWaveDirective, selector: "[nz-wave],button[nz-button]:not([nzType=\"link\"]):not([nzType=\"text\"])", inputs: ["nzWaveExtraNode"], exportAs: ["nzWave"] }, { kind: "ngmodule", type: NzDatePickerModule }, { kind: "component", type: i4.NzDatePickerComponent, selector: "nz-date-picker,nz-week-picker,nz-month-picker,nz-quarter-picker,nz-year-picker,nz-range-picker", inputs: ["nzInline", "nzAllowClear", "nzAutoFocus", "nzDisabled", "nzInputReadOnly", "nzOpen", "nzDisabledDate", "nzLocale", "nzPlaceHolder", "nzPopupStyle", "nzDropdownClassName", "nzSize", "nzStatus", "nzFormat", "nzVariant", "nzDateRender", "nzDisabledTime", "nzRenderExtraFooter", "nzShowToday", "nzMode", "nzShowNow", "nzRanges", "nzDefaultPickerValue", "nzSeparator", "nzSuffixIcon", "nzBackdrop", "nzId", "nzPlacement", "nzShowWeekNumber", "nzShowTime"], outputs: ["nzOnPanelChange", "nzOnCalendarChange", "nzOnOk", "nzOnOpenChange"], exportAs: ["nzDatePicker"] }, { kind: "ngmodule", type: NzModalModule }, { kind: "component", type: PaginationComponent, selector: "vl-pagination", inputs: ["itemInfo", "pageSize", "currentPage", "selectedLanguageInfo", "pages"], outputs: ["pageSizeChange", "onGoToPage"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i17.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "component", type: String$1, selector: "vl-string", inputs: ["formField", "modalItemInfo"] }, { kind: "ngmodule", type: AutoCompleteModule }, { kind: "component", type: i18.AutoComplete, selector: "p-autoComplete, p-autocomplete, p-auto-complete", inputs: ["minLength", "minQueryLength", "delay", "panelStyle", "styleClass", "panelStyleClass", "inputStyle", "inputId", "inputStyleClass", "placeholder", "readonly", "scrollHeight", "lazy", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "autoHighlight", "forceSelection", "type", "autoZIndex", "baseZIndex", "ariaLabel", "dropdownAriaLabel", "ariaLabelledBy", "dropdownIcon", "unique", "group", "completeOnFocus", "showClear", "dropdown", "showEmptyMessage", "dropdownMode", "multiple", "addOnTab", "tabindex", "dataKey", "emptyMessage", "showTransitionOptions", "hideTransitionOptions", "autofocus", "autocomplete", "optionGroupChildren", "optionGroupLabel", "overlayOptions", "suggestions", "optionLabel", "optionValue", "id", "searchMessage", "emptySelectionMessage", "selectionMessage", "autoOptionFocus", "selectOnFocus", "searchLocale", "optionDisabled", "focusOnHover", "typeahead", "addOnBlur", "separator", "appendTo", "motionOptions"], outputs: ["completeMethod", "onSelect", "onUnselect", "onAdd", "onFocus", "onBlur", "onDropdownClick", "onClear", "onInputKeydown", "onKeyUp", "onShow", "onHide", "onLazyLoad"] }, { kind: "ngmodule", type: InputTextModule }, { kind: "directive", type: CustomKeyboardDirective, selector: "[vlCustomKeyboard]", inputs: ["vlCustomKeyboard"] }, { kind: "pipe", type: PlaceholderPipe, name: "vlPlaceholder" }, { kind: "pipe", type: i9.CurrencyPipe, name: "currency" }, { kind: "pipe", type: i9.DatePipe, name: "date" }] });
4324
4427
  }
4325
4428
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.2", ngImport: i0, type: CardComponent, decorators: [{
4326
4429
  type: Component,
@@ -4338,8 +4441,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.2", ngImpor
4338
4441
  AutoCompleteModule,
4339
4442
  InputTextModule,
4340
4443
  CustomKeyboardDirective,
4341
- ], standalone: true, template: "<!-- Faramarz Yousefian and Agent Toni (Claude Opus 5.5) 2026-10-13\r\n - new: autocompletes get their suggestions from RemoteListService (completeRemote) -->\r\n<!-- Faramarz Yousefian and Agent Toni (Claude Opus 5.5) 2026-10-13\r\n - fix: the placeholder comes from vlPlaceholder (pipes/placeholder.pipe.ts) - empty where the\r\n project defines none; it showed the text \"undefined\" -->\r\n<!-- Faramarz Yousefian and Agent Toni (Claude Opus 5) 2026-10-07\r\n - change: autocomplete fields take the toolkit string keyboard unless option.keyboardType\r\n names another one ('native' keeps the system keyboard)\r\n - change: the date filter uses the shared picker markup (picker-field, DateTimePickerService) -->\r\n\r\n<!-- shuaib 2026-09-24\r\n - change: card field switches use renderFieldType so legacy checkbox fields render as boolean. -->\r\n\r\n<!-- Faramarz Yousefian and Agent Toni (Claude Opus 5) 2026-09-19\r\n - new: a @contract comment naming the types this container does not render. It carries four\r\n ngSwitch blocks, so the gap belongs to the container and not to one of them -->\r\n\r\n<!-- @contract gap: dateRange, quantity, credit card\r\n reality: a card renders string, number, image, date, time, dropdown, boolean and\r\n autocomplete. Legacy checkbox fields normalize to boolean. dropdown and boolean arrived on 2026-09-18; before that a card\r\n dropped them silently.\r\n failure: a field of a missing type renders empty, with no error.\r\n instead: quantity is grid-only by design; for a dateRange or a credit card use a modal.\r\n seen: this file carries four switch blocks (lines 23, 94, 267, 488) and none of them has\r\n a case for those three - the gap belongs to the container, not to one block -->\r\n\r\n<!-- Loader Spinner -->\r\n\r\n<div *ngIf=\"isLoading\" class=\"loader-overlay\">\r\n <div class=\"spinner\"></div>\r\n</div>\r\n<div class=\"vl-card-runtime\">\r\n <!-- top pagination on card -->\r\n <div *ngIf=\"\r\n itemInfo?.layoutSchema?.pagination?.visible &&\r\n itemInfo?.layoutSchema?.pagination?.top\r\n \" class=\"card-pagination-wrapper\">\r\n <vl-pagination [itemInfo]=\"itemInfo\"\r\n [selectedLanguageInfo]=\"selectedLanguageInfo\" [pageSize]=\"pageSize\"\r\n [currentPage]=\"currentPage\" [pages]=\"pages\"\r\n (pageSizeChange)=\"invokeOnPageSizeChange($event)\"\r\n (onGoToPage)=\"invokeGoToPage($event)\">\r\n </vl-pagination>\r\n </div>\r\n <div *ngIf=\"itemInfo?.header?.elements?.length\" [ngStyle]=\"getHeaderStyle()\"\r\n [class]=\"getStyleWithoutClasses(\r\n itemInfo?.header?.style\r\n ).classes\">\r\n <div *ngFor=\"let element of itemInfo.header?.elements; let c = index\"\r\n [ngStyle]=\"getHeaderElementWrapperStyle(element)\"\r\n [class]=\"element.option?.innerAction && element.option?.innerAction === 'saveAll' && !displayedRecords?.length ? \r\n 'hidden' :getStyleWithoutClasses(element?.wrapperStyle).classes\">\r\n <ng-container\r\n [ngSwitch]=\"renderFieldType(element.scope?.reference && itemInfo.propertySchema[getScope(element.scope?.reference)] ? itemInfo.propertySchema[getScope(element.scope?.reference)][element.scope?.reference.split('/').pop()]?.type : 'default')\">\r\n\r\n <!-- String Control -->\r\n <div *ngSwitchCase=\"'string'\"\r\n [class]=\"element.option?.visible ? 'card-field-wrapper' : 'hidden'\">\r\n\r\n <!-- LABEL -->\r\n <span *ngIf=\"element.label?.caption\"\r\n [style]=\"getStyleWithoutClasses(element.label?.style).style\"\r\n [class]=\"element.label?.style?.classes?.[0]\">\r\n {{ element.label.caption }}\r\n </span>\r\n </div>\r\n\r\n <!-- Date control -->\r\n <div *ngSwitchCase=\"'date'\" class=\"mb-3\">\r\n <span *ngIf=\"element.option.protected\"\r\n [style]=\"getStyleWithoutClasses(element?.label?.style).style\"\r\n [class]=\"element?.label?.style?.classes[0]\">\r\n <vl-string [formField]=\"element\"\r\n [modalItemInfo]=\"itemInfo\">\r\n </vl-string>\r\n </span>\r\n <div *ngIf=\"!element.option.protected\"\r\n [class]=\"element?.layout == 'horizontal' ? 'horizontal-layout' : ''\"\r\n [ngClass]=\"element?.style?.classes[0]\"\r\n [style]=\"getStyleWithoutClasses(element?.style).style\">\r\n <label\r\n [style]=\"getStyleWithoutClasses(element?.label?.style).style\"\r\n [class]=\"element?.label?.style?.classes[0]\">{{\r\n element.label?.value\r\n ?\r\n element.label?.value : element.label?.caption ?\r\n element.label?.caption :\r\n itemInfo.propertySchema[getScope(element.scope?.reference)][element.scope?.reference.split('/').pop()]?.caption\r\n }}</label>\r\n <div class=\"picker-field\">\r\n <p-datepicker #cardDatePicker\r\n (ngModelChange)=\"dateChangeEvent(element, $event)\"\r\n [dateFormat]=\"itemInfo.propertySchema[getScope(element.scope?.reference)][element.scope?.reference.split('/').pop()]?.format ? itemInfo.propertySchema[getScope(element.scope?.reference)][element.scope?.reference.split('/').pop()].format : 'yy-mm-dd'\"\r\n [(ngModel)]=\"itemInfo.propertySchema[getScope(element.scope?.reference)][element.scope?.reference.split('/').pop()].value\"\r\n (onInput)=\"onDateTyping($event)\"\r\n [class]=\"element?.scope?.style?.classes[0]\"\r\n [style]=\"getStyleWithoutClasses(element?.scope?.style).style\"\r\n [showIcon]=\"false\" [showOnFocus]=\"false\"\r\n appendTo=\"body\"\r\n [panelStyleClass]=\"picker.datePanelClass\"\r\n [motionOptions]=\"picker.dockedMotion\"\r\n [vlCustomKeyboard]=\"element?.option?.keyboardType ?? 'date'\"\r\n (pointerdown)=\"picker.onFieldPointerDown($event, cardDatePicker)\"\r\n (onFocus)=\"picker.onFieldFocus($event)\"\r\n (onShow)=\"picker.onShown()\"\r\n (onClose)=\"picker.onClose(cardDatePicker)\">\r\n </p-datepicker>\r\n <button type=\"button\" class=\"picker-field__icon\"\r\n aria-label=\"Open calendar\"\r\n (pointerdown)=\"picker.openFromIcon($event, cardDatePicker)\"\r\n (click)=\"picker.blockIconClick($event)\">\r\n <i class=\"pi pi-calendar\"></i>\r\n </button>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- Button Control -->\r\n <div *ngSwitchCase=\"'default'\"\r\n [class]=\"element.option?.visible ? 'row' : 'hidden'\"\r\n (click)=\"invokeOnCardHeader(element)\">\r\n <button nz-button type=\"button\"\r\n [matTooltip]=\"element?.option?.tooltip || ''\"\r\n [matTooltipTouchGestures]=\"'auto'\"\r\n [ngStyle]=\"getStyleWithoutClasses(element.style).style\"\r\n [class]=\"element.option.protected ? 'disabled-button' : getStyleWithoutClasses(element.style).classes\">\r\n <ng-container\r\n *ngIf=\"!element.caption; else headerTextContent\">\r\n <i nz-icon [nzType]=\"element.icon\"\r\n nzTheme=\"outline\"></i>\r\n </ng-container>\r\n <ng-template #headerTextContent>{{ element.caption\r\n }}</ng-template>\r\n </button>\r\n </div>\r\n </ng-container>\r\n </div>\r\n </div>\r\n <div class=\"card-responsive-grid\" [ngStyle]=\"getCardContainerStyle()\"\r\n [class]=\"getStyleWithoutClasses(\r\n itemInfo?.layoutSchema?.style\r\n ).classes\">\r\n <div *ngFor=\"let record of displayedRecords; let k = index\"\r\n class=\"card-grid-item\">\r\n <div [ngStyle]=\"getSingleCardStyle()\"\r\n [class]=\"getStyleWithoutClasses(itemInfo?.layoutSchema?.stylePerCard).classes\">\r\n <div *ngFor=\"let layout of itemInfo?.layoutSchema?.cards || []\"\r\n class=\"card-layout-item\" [ngStyle]=\"\r\n layout?.type === 'HorizontalLayout'\r\n ? {}\r\n : getStyleWithoutClasses(layout?.style).style\r\n \" [class]=\"\r\n layout?.type === 'HorizontalLayout'\r\n ? ''\r\n : getStyleWithoutClasses(layout?.style).classes\r\n \">\r\n <ng-container\r\n [ngSwitch]=\"renderFieldType(layout?.scope?.reference && itemInfo.propertySchema[getScope(layout.scope?.reference)] ? itemInfo.propertySchema[getScope(layout.scope?.reference)][layout.scope?.reference.split('/').pop()]?.type : layout?.type == 'HorizontalLayout' ? 'HorizontalLayout' : 'default')\">\r\n <!-- Image Control -->\r\n <div *ngSwitchCase=\"'image'\"\r\n [class]=\"layout.option?.visible ? 'row' : 'hidden'\">\r\n <img\r\n [class]=\"getStyleWithoutClasses(layout?.scope?.style).classes\"\r\n [style]=\"getStyleWithoutClasses(layout?.scope?.style).style\"\r\n [src]=\"layout?.option?.src ? layout?.option?.src : record[layout.scope?.reference.split('/').pop()]\"\r\n alt=\"{{ layout.label ? layout.label : getProperty(layout.scope?.reference).productSchema.caption }}\"\r\n (click)=\"showImageDetails(layout.option, record)\" />\r\n </div>\r\n\r\n <!-- String Control -->\r\n <div *ngSwitchCase=\"'string'\"\r\n [class]=\"layout.option?.visible ? 'card-field-wrapper' : 'hidden'\"\r\n [style]=\"getStyleWithoutClasses(layout?.scope?.style).style\">\r\n\r\n <!-- LABEL -->\r\n <span\r\n [ngStyle]=\"getStyleWithoutClasses(layout.label?.style).style\"\r\n [class]=\"getStyleWithoutClasses(layout.label?.style).classes\">\r\n {{ getHorizontalLayoutCaption(layout) }}\r\n </span>\r\n\r\n <!-- VALUE -->\r\n @if(layout.option && layout.option.control &&\r\n !layout.option.protected){\r\n @switch (layout.option.control) {\r\n @case ('textInput') {\r\n <p\r\n *ngIf=\"layout.option?.protected && layout.option?.visible\"\r\n [ngStyle]=\"getStyleWithoutClasses(layout?.scope?.style).style\"\r\n [class]=\"getStyleWithoutClasses(layout?.scope?.style).classes\"\r\n (click)=\"showLinkDetails(layout.option, record)\">\r\n {{\r\n record?.[layout.scope?.reference.split('/').pop()]\r\n ??\r\n itemInfo.propertySchema[getScope(layout.scope?.reference)]?.[layout.scope?.reference.split('/').pop()]?.default\r\n ??\r\n '--'\r\n }}\r\n </p>\r\n }\r\n @case ('password') {\r\n <span>Switch not supported yet</span>\r\n\r\n }\r\n @case ('combobox') {\r\n <span>Combobox not supported yet</span>\r\n }\r\n @case('textArea'){\r\n <span>TextArea not supported yet</span>\r\n }\r\n @case ('switch') {\r\n <span>Switch not supported yet</span>\r\n }\r\n\r\n @case('radiobutton') {\r\n <span>Radiobutton not supported yet</span>\r\n }\r\n\r\n @case ('dropdown') {\r\n <select id=\"dynamic-dropdown\"\r\n #dropdownField=\"ngModel\"\r\n [ngClass]=\"getStyleWithoutClasses(layout?.scope?.style)?.classes\"\r\n [ngStyle]=\"getStyleWithoutClasses(layout?.scope?.style)?.style\"\r\n [name]=\"layout.scope?.reference\"\r\n [(ngModel)]=\"\r\n itemInfo.propertySchema[getScope(layout.scope?.reference)][\r\n layout.scope?.reference.split('/').pop()\r\n ].value\r\n \">\r\n <option *ngFor=\"\r\n let item of itemInfo.propertySchema[getScope(layout.scope?.reference)]?.[\r\n layout.scope?.reference.split('/').pop()\r\n ]?.data\r\n \"\r\n [value]=\"item[layout?.option?.optionValue]\">\r\n {{ item[layout?.option?.optionLabel] }}\r\n </option>\r\n </select>\r\n }\r\n\r\n @case ('autocomplete') {\r\n <p-autocomplete [suggestions]=\"remoteSuggestions[layout.scope?.reference] ?? []\" (completeMethod)=\"completeRemote($event, layout)\" #autocompleteField=\"ngModel\"\r\n [required]=\"layout.option.required\"\r\n [name]=\"layout.scope?.reference\"\r\n styleClass=\"custom-autocomplete\"\r\n [(ngModel)]=\"itemInfo.propertySchema[getScope(layout.scope?.reference)][layout.scope?.reference.split('/').pop()].value\"\r\n [style]=\"getStyleWithoutClasses(layout?.scope?.style).style\"\r\n [class]=\"layout?.scope?.style?.classes ? layout?.scope?.style?.classes[0] : ''\"\r\n [dropdown]=\"true\"\r\n [optionLabel]=\"layout.option.autocomplete.response.label\"\r\n [placeholder]=\"itemInfo.propertySchema | vlPlaceholder: layout.scope?.reference\"\r\n [vlCustomKeyboard]=\"layout?.option?.keyboardType ?? 'string'\">\r\n </p-autocomplete>\r\n }\r\n }\r\n }@else {\r\n <p\r\n *ngIf=\"layout.option?.protected && layout.option?.visible\"\r\n [ngStyle]=\"getStyleWithoutClasses(layout?.scope?.style).style\"\r\n [class]=\"getStyleWithoutClasses(layout?.scope?.style).classes\"\r\n (click)=\"showLinkDetails(layout.option, record)\">\r\n {{\r\n record?.[layout.scope?.reference.split('/').pop()]\r\n ??\r\n itemInfo.propertySchema[getScope(layout.scope?.reference)]?.[layout.scope?.reference.split('/').pop()]?.default\r\n ??\r\n '--'\r\n }}\r\n </p>\r\n }\r\n\r\n </div>\r\n\r\n <!-- Date Control -->\r\n <div *ngSwitchCase=\"'date'\"\r\n [class]=\"layout.option?.visible ? 'card-field-wrapper' : 'hidden'\"\r\n [style]=\"getStyleWithoutClasses(layout?.scope?.style).style\">\r\n <!-- LABEL -->\r\n <span *ngIf=\"layout?.label?.caption\"\r\n [class]=\"layout.label?.style?.classes?.[0]\">\r\n {{ layout.label.caption }}\r\n </span>\r\n\r\n <!-- VALUE -->\r\n <p\r\n *ngIf=\"layout.option?.protected && layout.option?.visible\"\r\n [class]=\"getStyleWithoutClasses(layout?.scope?.style).classes\"\r\n (click)=\"showLinkDetails(layout.option, record)\">\r\n {{\r\n record?.[layout.scope?.reference.split('/').pop()]\r\n ?? itemInfo.propertySchema[\r\n getScope(layout.scope?.reference)\r\n ]?.[layout.scope?.reference.split('/').pop()]?.default\r\n ?? '--'\r\n }}\r\n </p>\r\n </div>\r\n\r\n <!-- Time Control -->\r\n <div *ngSwitchCase=\"'time'\"\r\n [class]=\"layout.option?.visible ? 'card-field-wrapper' : 'hidden'\"\r\n [style]=\"getStyleWithoutClasses(layout?.scope?.style).style\">\r\n\r\n <!-- LABEL -->\r\n <span *ngIf=\"layout?.label?.caption\"\r\n [class]=\"layout.label?.style?.classes?.[0]\">\r\n {{ layout.label.caption }}\r\n </span>\r\n\r\n <!-- VALUE -->\r\n <p\r\n *ngIf=\"layout.option?.protected && layout.option?.visible\"\r\n [class]=\"getStyleWithoutClasses(layout?.scope?.style).classes\"\r\n (click)=\"showLinkDetails(layout.option, record)\">\r\n {{\r\n record?.[layout.scope?.reference.split('/').pop()]\r\n ?? itemInfo.propertySchema[\r\n getScope(layout.scope?.reference)\r\n ]?.[layout.scope?.reference.split('/').pop()]?.default\r\n ?? '--'\r\n }}\r\n </p>\r\n </div>\r\n\r\n <!-- number Control -->\r\n <div *ngSwitchCase=\"'number'\"\r\n [class]=\"layout.option?.visible ? 'row' : 'hidden'\">\r\n <!-- VALUE -->\r\n @if(layout.option && layout.option.control &&\r\n !layout.option.protected){\r\n @switch (layout.option.control) {\r\n @case ('textInput') {\r\n <h3\r\n *ngIf=\"itemInfo.propertySchema[getScope(layout.scope?.reference)] && itemInfo.propertySchema[getScope(layout.scope?.reference)][layout.scope?.reference.split('/').pop()]?.format.currency\"\r\n [class]=\"getStyleWithoutClasses(layout?.scope?.style).classes\"\r\n [style]=\"getStyleWithoutClasses(layout?.scope?.style).style\">\r\n {{\r\n record[layout.scope?.reference.split('/').pop()]\r\n | currency: layout.option?.currency\r\n ?\r\n layout.option.currency\r\n :\r\n 'USD' }}\r\n </h3>\r\n }\r\n @case ('slider') {\r\n <p>Slider not Implemented yet</p>\r\n\r\n }\r\n @case ('spinner') {\r\n <p>Spinner not Implemented yet</p>\r\n }\r\n }\r\n } @else{\r\n <h3\r\n *ngIf=\"itemInfo.propertySchema[getScope(layout.scope?.reference)] && itemInfo.propertySchema[getScope(layout.scope?.reference)][layout.scope?.reference.split('/').pop()]?.format.currency\"\r\n [class]=\"getStyleWithoutClasses(layout?.scope?.style).classes\"\r\n [style]=\"getStyleWithoutClasses(layout?.scope?.style).style\">\r\n {{\r\n record[layout.scope?.reference.split('/').pop()]\r\n | currency: layout.option?.currency\r\n ?\r\n layout.option.currency\r\n :\r\n 'USD' }}\r\n </h3>\r\n }\r\n\r\n </div>\r\n\r\n <!-- dropdown Control -->\r\n <div *ngSwitchCase=\"'dropdown'\"\r\n [class]=\"layout.option?.visible ? 'row' : 'hidden'\">\r\n <h3\r\n *ngIf=\"itemInfo.propertySchema[getScope(layout.scope?.reference)] && itemInfo.propertySchema[getScope(layout.scope?.reference)][layout.scope?.reference.split('/').pop()]?.format.currency\"\r\n [class]=\"getStyleWithoutClasses(layout?.scope?.style).classes\"\r\n [style]=\"getStyleWithoutClasses(layout?.scope?.style).style\">\r\n <select id=\"dynamic-dropdown\"\r\n #dropdownField=\"ngModel\"\r\n [ngClass]=\"getStyleWithoutClasses(layout?.scope?.style)?.classes\"\r\n [ngStyle]=\"getStyleWithoutClasses(layout?.scope?.style)?.style\"\r\n [name]=\"layout.scope?.reference\"\r\n [(ngModel)]=\"\r\n itemInfo.propertySchema[getScope(layout.scope?.reference)][\r\n layout.scope?.reference.split('/').pop()\r\n ].value\r\n \">\r\n <option *ngFor=\"\r\n let item of itemInfo.propertySchema[getScope(layout.scope?.reference)]?.[\r\n layout.scope?.reference.split('/').pop()\r\n ]?.data\r\n \"\r\n [value]=\"item[layout?.option?.optionValue]\">\r\n {{ item[layout?.option?.optionLabel]\r\n }}\r\n </option>\r\n </select>\r\n </h3>\r\n </div>\r\n\r\n <!-- autocomplete Control -->\r\n <div *ngSwitchCase=\"'autocomplete'\"\r\n [class]=\"layout.option?.visible ? 'row' : 'hidden'\">\r\n <h3\r\n *ngIf=\"itemInfo.propertySchema[getScope(layout.scope?.reference)] && itemInfo.propertySchema[getScope(layout.scope?.reference)][layout.scope?.reference.split('/').pop()]?.format.currency\"\r\n [class]=\"getStyleWithoutClasses(layout?.scope?.style).classes\"\r\n [style]=\"getStyleWithoutClasses(layout?.scope?.style).style\">\r\n <p-autocomplete [suggestions]=\"remoteSuggestions[layout.scope?.reference] ?? []\" (completeMethod)=\"completeRemote($event, layout)\" #autocompleteField=\"ngModel\"\r\n [required]=\"layout.option.required\"\r\n [name]=\"layout.scope?.reference\"\r\n styleClass=\"custom-autocomplete\"\r\n [(ngModel)]=\"itemInfo.propertySchema[getScope(layout.scope?.reference)][layout.scope?.reference.split('/').pop()].value\"\r\n [style]=\"getStyleWithoutClasses(layout?.scope?.style).style\"\r\n [class]=\"layout?.scope?.style?.classes ? layout?.scope?.style?.classes[0] : ''\"\r\n [dropdown]=\"true\"\r\n [optionLabel]=\"layout.option.autocomplete.response.label\"\r\n [placeholder]=\"itemInfo.propertySchema | vlPlaceholder: layout.scope?.reference\"\r\n [vlCustomKeyboard]=\"layout?.option?.keyboardType ?? 'string'\">\r\n </p-autocomplete>\r\n </h3>\r\n </div>\r\n\r\n <!-- checkbox Control -->\r\n <div *ngSwitchCase=\"'boolean'\"\r\n [class]=\"layout.option?.visible ? 'row' : 'hidden'\">\r\n <h3\r\n *ngIf=\"itemInfo.propertySchema[getScope(layout.scope?.reference)] && itemInfo.propertySchema[getScope(layout.scope?.reference)][layout.scope?.reference.split('/').pop()]\"\r\n [class]=\"getStyleWithoutClasses(layout?.scope?.style).classes\"\r\n [style]=\"getStyleWithoutClasses(layout?.scope?.style).style\">\r\n <input type=\"checkbox\"\r\n class=\"form-check-input mr-2\"\r\n [(ngModel)]=\"\r\n itemInfo.propertySchema[getScope(layout.scope?.reference)][\r\n layout.scope?.reference.split('/').pop()\r\n ].value\r\n \"\r\n [name]=\"layout.scope?.reference\" />\r\n </h3>\r\n </div>\r\n\r\n <!-- Button Control -->\r\n <div *ngSwitchCase=\"'default'\"\r\n [class]=\"layout.option?.visible ? 'row' : 'hidden'\">\r\n <button\r\n [style]=\"getStyleWithoutClasses(layout?.style).style\"\r\n [class]=\"layout.option.protected ? 'disabled-button' : getStyleWithoutClasses(layout?.style).classes\"\r\n (click)=\"\r\n invokeButtonClick(\r\n layout,\r\n record,\r\n getRecordIndex(record)\r\n )\r\n\">\r\n <ng-container\r\n *ngIf=\"!layout.caption; else textContent\">\r\n <i nz-icon [nzType]=\"layout.icon\"\r\n nzTheme=\"outline\"></i>\r\n </ng-container>\r\n <ng-template #textContent>\r\n {{ layout.caption }}\r\n </ng-template>\r\n </button>\r\n </div>\r\n\r\n <!-- HorizontalLayout Control -->\r\n <div *ngSwitchCase=\"'HorizontalLayout'\">\r\n <div class=\"card-horizontal-layout\"\r\n [class]=\"getStyleWithoutClasses(\r\n layout?.style\r\n ).classes\" [ngStyle]=\"getHorizontalLayoutStyle(layout)\">\r\n <ng-container\r\n *ngFor=\"let innerLayout of layout.elements\">\r\n <ng-container\r\n [ngSwitch]=\"renderFieldType(innerLayout.scope?.reference && itemInfo.propertySchema[getScope(innerLayout.scope?.reference)] ? itemInfo.propertySchema[getScope(innerLayout.scope?.reference)][innerLayout.scope?.reference.split('/').pop()]?.type : 'default')\">\r\n <!-- Image Control -->\r\n <div *ngSwitchCase=\"'image'\"\r\n [class]=\"innerLayout.option?.visible ? 'row' : 'hidden'\">\r\n <img\r\n [class]=\"getStyleWithoutClasses(innerLayout?.scope?.style).classes\"\r\n [style]=\"getStyleWithoutClasses(innerLayout?.scope?.style).style\"\r\n [src]=\"innerLayout?.option?.src ? innerLayout?.option?.src : record[innerLayout.scope?.reference.split('/').pop()]\"\r\n alt=\"{{ innerLayout.label ? innerLayout.label : getProperty(innerLayout.scope?.reference).productSchema.caption }}\"\r\n (click)=\"showImageDetails(innerLayout.option, record)\" />\r\n </div>\r\n\r\n <!-- String Control -->\r\n <div *ngSwitchCase=\"'string'\"\r\n [ngClass]=\"[innerLayout?.option?.visible ? 'card-field-wrapper' : 'hidden',getStyleWithoutClasses(innerLayout?.style).classes]\"\r\n [ngStyle]=\"getStyleWithoutClasses(innerLayout?.style).style\">\r\n\r\n <!-- LABEL -->\r\n <span\r\n [ngStyle]=\"getStyleWithoutClasses(innerLayout.label?.style).style\"\r\n [class]=\"getStyleWithoutClasses(innerLayout.label?.style).classes\">\r\n {{\r\n getHorizontalLayoutCaption(innerLayout)\r\n }}\r\n </span>\r\n\r\n <!-- VALUE -->\r\n @if(innerLayout.option &&\r\n innerLayout.option.control &&\r\n !innerLayout.option.protected){\r\n @switch\r\n (innerLayout.option.control)\r\n {\r\n @case ('textInput') {\r\n <h3\r\n *ngIf=\"innerLayout.option?.protected && innerLayout.option?.visible\"\r\n [class]=\"getStyleWithoutClasses(innerLayout?.scope?.style).classes\"\r\n [ngStyle]=\"getStyleWithoutClasses(innerLayout?.scope?.style).style\"\r\n (click)=\"showLinkDetails(innerLayout.option, record)\">\r\n\r\n <!-- DATE FORMAT -->\r\n <ng-container\r\n *ngIf=\"innerLayout.option?.dateFormat; else checkInnerTime\">\r\n {{\r\n record?.[innerLayout.scope?.reference.split('/').pop()]\r\n ?\r\n (record[innerLayout.scope?.reference.split('/').pop()]\r\n | date:\r\n innerLayout.option.dateFormat)\r\n : '--' }}\r\n </ng-container>\r\n\r\n <!-- TIME FORMAT -->\r\n <ng-template\r\n #checkInnerTime>\r\n <ng-container\r\n *ngIf=\"innerLayout.option?.timeFormat; else normalInnerValue\">\r\n {{\r\n record?.[innerLayout.scope?.reference.split('/').pop()]\r\n ?\r\n (record[innerLayout.scope?.reference.split('/').pop()]\r\n |\r\n date:\r\n innerLayout.option.timeFormat)\r\n : '--' }}\r\n </ng-container>\r\n </ng-template>\r\n\r\n <!-- NORMAL STRING -->\r\n <ng-template\r\n #normalInnerValue>\r\n {{\r\n record?.[innerLayout.scope?.reference.split('/').pop()]\r\n ??\r\n '--' }}\r\n </ng-template>\r\n </h3>\r\n }\r\n @case ('password') {\r\n <span>Switch not supported\r\n yet</span>\r\n\r\n }\r\n @case ('combobox') {\r\n <span>Combobox not supported\r\n yet</span>\r\n }\r\n @case('textArea'){\r\n <span>TextArea not supported\r\n yet</span>\r\n }\r\n @case ('switch') {\r\n <span>Switch not supported\r\n yet</span>\r\n }\r\n\r\n @case('radiobutton') {\r\n <span>Radiobutton not supported\r\n yet</span>\r\n }\r\n\r\n @case ('dropdown') {\r\n <select id=\"dynamic-dropdown\"\r\n #dropdownField=\"ngModel\"\r\n [ngClass]=\"getStyleWithoutClasses(innerLayout?.scope?.style)?.classes\"\r\n [ngStyle]=\"getStyleWithoutClasses(innerLayout?.scope?.style)?.style\"\r\n [name]=\"innerLayout.scope?.reference\"\r\n [(ngModel)]=\"\r\n itemInfo.propertySchema[getScope(innerLayout.scope?.reference)][\r\n innerLayout.scope?.reference.split('/').pop()\r\n ].value\r\n \">\r\n <option *ngFor=\"\r\n let item of itemInfo.propertySchema[getScope(innerLayout.scope?.reference)]?.[\r\n innerLayout.scope?.reference.split('/').pop()\r\n ]?.data\r\n \"\r\n [value]=\"item[innerLayout?.option?.optionValue]\">\r\n {{\r\n item[innerLayout?.option?.optionLabel]\r\n }}\r\n </option>\r\n </select>\r\n }\r\n\r\n @case ('autocomplete') {\r\n\r\n <p-autocomplete [suggestions]=\"remoteSuggestions[innerLayout.scope?.reference] ?? []\" (completeMethod)=\"completeRemote($event, innerLayout)\"\r\n #autocompleteField=\"ngModel\"\r\n [required]=\"innerLayout.option.required\"\r\n [name]=\"innerLayout.scope?.reference\"\r\n styleClass=\"custom-autocomplete\"\r\n [(ngModel)]=\"itemInfo.propertySchema[getScope(innerLayout.scope?.reference)][innerLayout.scope?.reference.split('/').pop()].value\"\r\n [style]=\"getStyleWithoutClasses(innerLayout?.scope?.style).style\"\r\n [class]=\"innerLayout?.scope?.style?.classes ? innerLayout?.scope?.style?.classes[0] : ''\"\r\n [dropdown]=\"true\"\r\n [optionLabel]=\"innerLayout.option.autocomplete.response.label\"\r\n [placeholder]=\"itemInfo.propertySchema | vlPlaceholder: innerLayout.scope?.reference\"\r\n [vlCustomKeyboard]=\"innerLayout?.option?.keyboardType ?? 'string'\">\r\n </p-autocomplete>\r\n }\r\n }\r\n }@else{\r\n\r\n <h3\r\n *ngIf=\"innerLayout.option?.protected && innerLayout.option?.visible\"\r\n [class]=\"getStyleWithoutClasses(innerLayout?.scope?.style).classes\"\r\n [ngStyle]=\"getStyleWithoutClasses(innerLayout?.scope?.style).style\"\r\n (click)=\"showLinkDetails(innerLayout.option, record)\">\r\n\r\n <!-- DATE FORMAT -->\r\n <ng-container\r\n *ngIf=\"innerLayout.option?.dateFormat; else checkInnerTime\">\r\n {{\r\n record?.[innerLayout.scope?.reference.split('/').pop()]\r\n ?\r\n (record[innerLayout.scope?.reference.split('/').pop()]\r\n | date:\r\n innerLayout.option.dateFormat)\r\n : '--' }}\r\n </ng-container>\r\n\r\n <!-- TIME FORMAT -->\r\n <ng-template\r\n #checkInnerTime>\r\n <ng-container\r\n *ngIf=\"innerLayout.option?.timeFormat; else normalInnerValue\">\r\n {{\r\n record?.[innerLayout.scope?.reference.split('/').pop()]\r\n ?\r\n (record[innerLayout.scope?.reference.split('/').pop()]\r\n |\r\n date:\r\n innerLayout.option.timeFormat)\r\n : '--' }}\r\n </ng-container>\r\n </ng-template>\r\n\r\n <!-- NORMAL STRING -->\r\n <ng-template\r\n #normalInnerValue>\r\n {{\r\n record?.[innerLayout.scope?.reference.split('/').pop()]\r\n ??\r\n '--' }}\r\n </ng-template>\r\n </h3>\r\n }\r\n\r\n </div>\r\n\r\n <!-- number Control -->\r\n <div *ngSwitchCase=\"'number'\"\r\n [ngClass]=\"[innerLayout?.option?.visible ? 'card-field-wrapper' : 'hidden',getStyleWithoutClasses(innerLayout?.style).classes]\"\r\n [ngStyle]=\"getStyleWithoutClasses(innerLayout?.style).style\">\r\n <h3\r\n *ngIf=\"itemInfo.propertySchema[getScope(innerLayout.scope?.reference)] && itemInfo.propertySchema[getScope(innerLayout.scope?.reference)][innerLayout.scope?.reference.split('/').pop()]?.format?.currency\"\r\n [class]=\"getStyleWithoutClasses(innerLayout?.scope?.style).classes\"\r\n [ngStyle]=\"getStyleWithoutClasses(innerLayout?.scope?.style).style\">\r\n {{\r\n record[innerLayout.scope?.reference.split('/').pop()]\r\n | currency:\r\n innerLayout.option?.currency\r\n ?\r\n innerLayout.option.currency\r\n :\r\n 'USD'\r\n }}\r\n </h3>\r\n </div>\r\n\r\n <!-- Date Control -->\r\n <div *ngSwitchCase=\"'date'\"\r\n [ngClass]=\"[innerLayout?.option?.visible ? 'card-field-wrapper' : 'hidden',getStyleWithoutClasses(innerLayout?.style).classes]\"\r\n [ngStyle]=\"getStyleWithoutClasses(innerLayout?.style).style\">\r\n <!-- LABEL -->\r\n <span\r\n [ngStyle]=\"getStyleWithoutClasses(innerLayout.label?.style).style\"\r\n [class]=\"getStyleWithoutClasses(innerLayout.label?.style).classes\">\r\n {{\r\n getHorizontalLayoutCaption(innerLayout)\r\n }}\r\n </span>\r\n\r\n <!-- VALUE -->\r\n <h3\r\n *ngIf=\"innerLayout.option?.protected && innerLayout.option?.visible\"\r\n [class]=\"getStyleWithoutClasses(innerLayout?.scope?.style).classes\"\r\n [ngStyle]=\"getStyleWithoutClasses(innerLayout?.scope?.style).style\"\r\n (click)=\"showLinkDetails(innerLayout.option, record)\">\r\n {{\r\n record?.[innerLayout.scope?.reference.split('/').pop()]\r\n ?\r\n (record[innerLayout.scope?.reference.split('/').pop()]\r\n | date:\r\n innerLayout.option?.dateFormat\r\n ?\r\n innerLayout.option?.dateFormat\r\n :\r\n itemInfo.propertySchema[getScope(innerLayout.scope?.reference)]?.[innerLayout.scope?.reference.split('/').pop()]?.format\r\n || 'yyyy-MM-dd') : '--' }}\r\n </h3>\r\n </div>\r\n\r\n <!-- Time Control -->\r\n <div *ngSwitchCase=\"'time'\"\r\n [ngClass]=\"[innerLayout?.option?.visible ? 'card-field-wrapper' : 'hidden',getStyleWithoutClasses(innerLayout?.style).classes]\"\r\n [ngStyle]=\"getStyleWithoutClasses(innerLayout?.style).style\">\r\n\r\n <!-- LABEL -->\r\n <span\r\n [ngStyle]=\"getStyleWithoutClasses(innerLayout.label?.style).style\"\r\n [class]=\"getStyleWithoutClasses(innerLayout.label?.style).classes\">\r\n {{\r\n getHorizontalLayoutCaption(innerLayout)\r\n }}\r\n </span>\r\n\r\n <!-- VALUE -->\r\n <h3\r\n *ngIf=\"innerLayout.option?.protected && innerLayout.option?.visible\"\r\n [class]=\"getStyleWithoutClasses(innerLayout?.scope?.style).classes\"\r\n [ngStyle]=\"getStyleWithoutClasses(innerLayout?.scope?.style).style\"\r\n (click)=\"showLinkDetails(innerLayout.option, record)\">\r\n {{\r\n record?.[innerLayout.scope?.reference.split('/').pop()]\r\n ?\r\n (record[innerLayout.scope?.reference.split('/').pop()]\r\n | date:\r\n innerLayout.option?.timeFormat\r\n ?\r\n innerLayout.option?.timeFormat\r\n :itemInfo.propertySchema[getScope(innerLayout.scope?.reference)]?.[innerLayout.scope?.reference.split('/').pop()]?.format\r\n || 'HH:mm') : '--' }}\r\n </h3>\r\n </div>\r\n\r\n <!-- dropdown Control -->\r\n <div *ngSwitchCase=\"'dropdown'\"\r\n [class]=\"innerLayout.option?.visible ? 'row' : 'hidden'\">\r\n <h3\r\n *ngIf=\"itemInfo.propertySchema[getScope(innerLayout.scope?.reference)] && itemInfo.propertySchema[getScope(innerLayout.scope?.reference)][innerLayout.scope?.reference.split('/').pop()]?.format.currency\"\r\n [class]=\"getStyleWithoutClasses(innerLayout?.scope?.style).classes\"\r\n [style]=\"getStyleWithoutClasses(innerLayout?.scope?.style).style\">\r\n <select\r\n id=\"dynamic-dropdown\"\r\n #dropdownField=\"ngModel\"\r\n [ngClass]=\"getStyleWithoutClasses(innerLayout?.scope?.style)?.classes\"\r\n [ngStyle]=\"getStyleWithoutClasses(innerLayout?.scope?.style)?.style\"\r\n [name]=\"innerLayout.scope?.reference\"\r\n [(ngModel)]=\"\r\n itemInfo.propertySchema[getScope(innerLayout.scope?.reference)][\r\n innerLayout.scope?.reference.split('/').pop()\r\n ].value\r\n \">\r\n <option *ngFor=\"\r\n let item of itemInfo.propertySchema[getScope(innerLayout.scope?.reference)]?.[\r\n innerLayout.scope?.reference.split('/').pop()\r\n ]?.data\r\n \"\r\n [value]=\"item[innerLayout?.option?.optionValue]\">\r\n {{\r\n item[innerLayout?.option?.optionLabel]\r\n }}\r\n </option>\r\n </select>\r\n </h3>\r\n </div>\r\n\r\n <!-- autocomplete Control -->\r\n <div *ngSwitchCase=\"'autocomplete'\"\r\n [class]=\"innerLayout.option?.visible ? 'row' : 'hidden'\">\r\n <h3\r\n *ngIf=\"itemInfo.propertySchema[getScope(innerLayout.scope?.reference)] && itemInfo.propertySchema[getScope(innerLayout.scope?.reference)][innerLayout.scope?.reference.split('/').pop()]?.format.currency\"\r\n [class]=\"getStyleWithoutClasses(innerLayout?.scope?.style).classes\"\r\n [style]=\"getStyleWithoutClasses(innerLayout?.scope?.style).style\">\r\n <p-autocomplete [suggestions]=\"remoteSuggestions[innerLayout.scope?.reference] ?? []\" (completeMethod)=\"completeRemote($event, innerLayout)\"\r\n #autocompleteField=\"ngModel\"\r\n [required]=\"innerLayout.option.required\"\r\n [name]=\"innerLayout.scope?.reference\"\r\n styleClass=\"custom-autocomplete\"\r\n [(ngModel)]=\"itemInfo.propertySchema[getScope(innerLayout.scope?.reference)][innerLayout.scope?.reference.split('/').pop()].value\"\r\n [style]=\"getStyleWithoutClasses(innerLayout?.scope?.style).style\"\r\n [class]=\"innerLayout?.scope?.style?.classes ? innerLayout?.scope?.style?.classes[0] : ''\"\r\n [dropdown]=\"true\"\r\n [optionLabel]=\"innerLayout.option.autocomplete.response.label\"\r\n [placeholder]=\"itemInfo.propertySchema | vlPlaceholder: innerLayout.scope?.reference\"\r\n [vlCustomKeyboard]=\"innerLayout?.option?.keyboardType ?? 'string'\">\r\n </p-autocomplete>\r\n </h3>\r\n </div>\r\n\r\n <!-- checkbox Control -->\r\n <div *ngSwitchCase=\"'boolean'\"\r\n [class]=\"innerLayout.option?.visible ? 'row' : 'hidden'\">\r\n <h3\r\n *ngIf=\"itemInfo.propertySchema[getScope(innerLayout.scope?.reference)] && itemInfo.propertySchema[getScope(innerLayout.scope?.reference)][innerLayout.scope?.reference.split('/').pop()]\"\r\n [class]=\"getStyleWithoutClasses(innerLayout?.scope?.style).classes\"\r\n [style]=\"getStyleWithoutClasses(innerLayout?.scope?.style).style\">\r\n <input type=\"checkbox\"\r\n class=\"form-check-input mr-2\"\r\n [(ngModel)]=\"\r\n itemInfo.propertySchema[getScope(innerLayout.scope?.reference)][\r\n innerLayout.scope?.reference.split('/').pop()\r\n ].value\r\n \"\r\n [name]=\"innerLayout.scope?.reference\" />\r\n </h3>\r\n </div>\r\n\r\n <!-- Button Control -->\r\n <div *ngSwitchCase=\"'default'\">\r\n <button nz-button\r\n [matTooltip]=\"getHorizontalLayoutTooltip(innerLayout)\"\r\n [matTooltipTouchGestures]=\"'auto'\"\r\n [style]=\"getStyleWithoutClasses(innerLayout?.style).style\"\r\n [class]=\"innerLayout.option?.visible ? innerLayout.option.protected ? 'disabled-button' : getStyleWithoutClasses(innerLayout?.style).classes : 'hidden'\"\r\n (click)=\"\r\n invokeButtonClick(\r\n innerLayout,\r\n record,\r\n getRecordIndex(record)\r\n )\r\n\">\r\n <span\r\n class=\"schema-btn-content\">\r\n <i\r\n *ngIf=\"showButtonIcon(innerLayout)\"\r\n nz-icon\r\n [nzType]=\"innerLayout.icon\"\r\n nzTheme=\"outline\">\r\n </i>\r\n\r\n <span\r\n *ngIf=\"showButtonCaption(innerLayout)\">\r\n {{\r\n innerLayout.caption\r\n }}\r\n </span>\r\n\r\n <span *ngIf=\"\r\n !showButtonIcon(innerLayout) &&\r\n !showButtonCaption(innerLayout)\r\n \">\r\n Button\r\n </span>\r\n </span>\r\n </button>\r\n </div>\r\n\r\n </ng-container>\r\n </ng-container>\r\n </div>\r\n </div>\r\n </ng-container>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n <div\r\n *ngIf=\"itemInfo?.footer?.elements && itemInfo?.data && itemInfo?.data.length\"\r\n [class]=\"getStyleWithoutClasses(itemInfo?.footer?.style).classes\">\r\n <span\r\n *ngFor=\"let element of itemInfo.footer?.elements; let c = index\">\r\n <ng-container\r\n [ngSwitch]=\"renderFieldType(element.scope?.reference && itemInfo.propertySchema[getScope(element.scope?.reference)] ? itemInfo.propertySchema[getScope(element.scope?.reference)][element.scope?.reference.split('/').pop()]?.type : 'default')\">\r\n\r\n <!-- Date control -->\r\n <div *ngSwitchCase=\"'date'\" class=\"form-group mb-3\">\r\n <span *ngIf=\"element.option.protected\"\r\n [style]=\"getStyleWithoutClasses(element?.label?.style).style\"\r\n [class]=\"element?.label?.style?.classes[0]\">\r\n <h5>{{\r\n itemInfo.propertySchema[getScope(element.scope?.reference)][element.scope?.reference.split('/').pop()]?.caption\r\n }}\r\n </h5>\r\n </span>\r\n <div *ngIf=\"!element.option.protected\">\r\n <div\r\n [class]=\"element?.layout == 'horizontal' ? 'horizontal-layout' : 'row'\">\r\n <label\r\n [style]=\"getStyleWithoutClasses(element?.label?.style).style\"\r\n [class]=\"element?.label?.style?.classes[0]\">{{\r\n element.label?.value\r\n ?\r\n element.label?.value :\r\n element.label?.caption ?\r\n element.label?.caption :\r\n itemInfo.propertySchema[getScope(element.scope?.reference)][element.scope?.reference.split('/').pop()]?.caption\r\n }}</label>\r\n\r\n <nz-date-picker\r\n [required]=\"element.option.required\"\r\n [name]=\"element.scope?.reference\"\r\n [nzDisabled]=\"element?.option?.disabled\"\r\n (ngModelChange)=\"dateChangeEvent(element, $event)\"\r\n [nzFormat]=\"itemInfo.propertySchema[getScope(element.scope?.reference)][element.scope?.reference.split('/').pop()]?.format ? itemInfo.propertySchema[getScope(element.scope?.reference)][element.scope?.reference.split('/').pop()]?.format : 'yyyy-MM-dd'\"\r\n [(ngModel)]=\"itemInfo.propertySchema[getScope(element.scope?.reference)][element.scope?.reference.split('/').pop()].value\"\r\n [style]=\"getStyleWithoutClasses(element?.style).style\"></nz-date-picker>\r\n </div>\r\n\r\n </div>\r\n </div>\r\n\r\n <!-- Button Control -->\r\n <div *ngSwitchCase=\"'default'\"\r\n [class]=\"element.option?.visible ? 'row' : 'hidden'\"\r\n (click)=\"invokeOnCardFooter(element)\">\r\n <button nz-button\r\n [style]=\"getStyleWithoutClasses(element.style).style\"\r\n [class]=\"element.option.protected ? 'disabled-button' : getStyleWithoutClasses(element.style).classes\">\r\n <ng-container\r\n *ngIf=\"!element.caption; else textContent\">\r\n <i nz-icon [nzType]=\"element.icon\"\r\n nzTheme=\"outline\"></i>\r\n </ng-container>\r\n <ng-template #textContent>\r\n {{ element.caption }}\r\n </ng-template>\r\n </button>\r\n </div>\r\n </ng-container>\r\n </span>\r\n </div>\r\n <!-- bottom pagination on card -->\r\n <div *ngIf=\"\r\n itemInfo?.data.length && \r\n itemInfo?.layoutSchema?.pagination?.visible &&\r\n !itemInfo?.layoutSchema?.pagination?.top &&\r\n !scrollPagination\r\n \" class=\"card-pagination-wrapper\">\r\n <vl-pagination [itemInfo]=\"itemInfo\"\r\n [selectedLanguageInfo]=\"selectedLanguageInfo\"\r\n [pageSize]=\"pageSize\"\r\n [currentPage]=\"currentPage\" [pages]=\"pages\"\r\n (pageSizeChange)=\"invokeOnPageSizeChange($event)\"\r\n (onGoToPage)=\"invokeGoToPage($event)\">\r\n </vl-pagination>\r\n </div>\r\n\r\n @if (scrollPagination) {\r\n <div #scrollPaginationSentinel class=\"scroll-pagination-sentinel\"\r\n aria-hidden=\"true\">\r\n </div>\r\n }\r\n</div>\r\n", styles: [":host{display:block;width:100%;min-width:0}.vl-card-runtime{min-width:0;box-sizing:border-box}.card-responsive-grid{width:100%;min-width:0;box-sizing:border-box}.scroll-pagination-sentinel{width:100%;height:1px}.card-grid-item,.card-layout-item,.card-horizontal-layout,.card-field-wrapper{width:100%;min-width:0;box-sizing:border-box}.card-field-wrapper{overflow-wrap:anywhere}.card-field-wrapper p,.card-field-wrapper h3{margin:0;min-width:0}.card-layout-item img{display:block;max-width:100%;height:auto}.card-layout-item button{max-width:100%;box-sizing:border-box}.schema-btn-content{display:inline-flex;align-items:center;justify-content:center;gap:6px;min-width:0}.hidden{display:none!important}.card-pagination-wrapper{width:100%;min-width:0;box-sizing:border-box;padding:0 10px}\n"] }]
4342
- }], ctorParameters: () => [{ type: UtilityService }, { type: i1.Platform }, { type: i1$1.HttpClient }, { type: ConfigService }, { type: i0.ChangeDetectorRef }, { type: i0.NgZone }, { type: i5$1.NzModalService }, { type: NotificationService }, { type: i7.OAuthService }, { type: RequestService }], propDecorators: { itemInfo: [{
4444
+ ], standalone: true, template: "<!-- Faramarz Yousefian and Agent Toni (Claude Opus 5.5) 2026-10-13\r\n - fix: the bottom pagination read itemInfo?.data.length; before the records arrive data is\r\n undefined, the template threw and the cards stayed half drawn (luv2shop start page: one\r\n card without texts)\r\n - fix: the price fields read ...?.format.currency; a property without format threw the same\r\n way (luv2shop: no prices, cards cut off) -->\r\n<!-- Faramarz Yousefian and Agent Toni (Claude Opus 5.5) 2026-10-13\r\n - new: autocompletes get their suggestions from RemoteListService (completeRemote) -->\r\n<!-- Faramarz Yousefian and Agent Toni (Claude Opus 5.5) 2026-10-13\r\n - fix: the placeholder comes from vlPlaceholder (pipes/placeholder.pipe.ts) - empty where the\r\n project defines none; it showed the text \"undefined\" -->\r\n<!-- Faramarz Yousefian and Agent Toni (Claude Opus 5) 2026-10-07\r\n - change: autocomplete fields take the toolkit string keyboard unless option.keyboardType\r\n names another one ('native' keeps the system keyboard)\r\n - change: the date filter uses the shared picker markup (picker-field, DateTimePickerService) -->\r\n\r\n<!-- shuaib 2026-09-24\r\n - change: card field switches use renderFieldType so legacy checkbox fields render as boolean. -->\r\n\r\n<!-- Faramarz Yousefian and Agent Toni (Claude Opus 5) 2026-09-19\r\n - new: a @contract comment naming the types this container does not render. It carries four\r\n ngSwitch blocks, so the gap belongs to the container and not to one of them -->\r\n\r\n<!-- @contract gap: dateRange, quantity, credit card\r\n reality: a card renders string, number, image, date, time, dropdown, boolean and\r\n autocomplete. Legacy checkbox fields normalize to boolean. dropdown and boolean arrived on 2026-09-18; before that a card\r\n dropped them silently.\r\n failure: a field of a missing type renders empty, with no error.\r\n instead: quantity is grid-only by design; for a dateRange or a credit card use a modal.\r\n seen: this file carries four switch blocks (lines 23, 94, 267, 488) and none of them has\r\n a case for those three - the gap belongs to the container, not to one block -->\r\n\r\n<!-- Loader Spinner -->\r\n\r\n<div *ngIf=\"isLoading\" class=\"loader-overlay\">\r\n <div class=\"spinner\"></div>\r\n</div>\r\n<div class=\"vl-card-runtime\">\r\n <!-- top pagination on card -->\r\n <div *ngIf=\"\r\n itemInfo?.layoutSchema?.pagination?.visible &&\r\n itemInfo?.layoutSchema?.pagination?.top\r\n \" class=\"card-pagination-wrapper\">\r\n <vl-pagination [itemInfo]=\"itemInfo\"\r\n [selectedLanguageInfo]=\"selectedLanguageInfo\" [pageSize]=\"pageSize\"\r\n [currentPage]=\"currentPage\" [pages]=\"pages\"\r\n (pageSizeChange)=\"invokeOnPageSizeChange($event)\"\r\n (onGoToPage)=\"invokeGoToPage($event)\">\r\n </vl-pagination>\r\n </div>\r\n <div *ngIf=\"itemInfo?.header?.elements?.length\" [ngStyle]=\"getHeaderStyle()\"\r\n [class]=\"getStyleWithoutClasses(\r\n itemInfo?.header?.style\r\n ).classes\">\r\n <div *ngFor=\"let element of itemInfo.header?.elements; let c = index\"\r\n [ngStyle]=\"getHeaderElementWrapperStyle(element)\"\r\n [class]=\"element.option?.innerAction && element.option?.innerAction === 'saveAll' && !displayedRecords?.length ? \r\n 'hidden' :getStyleWithoutClasses(element?.wrapperStyle).classes\">\r\n <ng-container\r\n [ngSwitch]=\"renderFieldType(element.scope?.reference && itemInfo.propertySchema[getScope(element.scope?.reference)] ? itemInfo.propertySchema[getScope(element.scope?.reference)][element.scope?.reference.split('/').pop()]?.type : 'default')\">\r\n\r\n <!-- String Control -->\r\n <div *ngSwitchCase=\"'string'\"\r\n [class]=\"element.option?.visible ? 'card-field-wrapper' : 'hidden'\">\r\n\r\n <!-- LABEL -->\r\n <span *ngIf=\"element.label?.caption\"\r\n [style]=\"getStyleWithoutClasses(element.label?.style).style\"\r\n [class]=\"element.label?.style?.classes?.[0]\">\r\n {{ element.label.caption }}\r\n </span>\r\n </div>\r\n\r\n <!-- Date control -->\r\n <div *ngSwitchCase=\"'date'\" class=\"mb-3\">\r\n <span *ngIf=\"element.option.protected\"\r\n [style]=\"getStyleWithoutClasses(element?.label?.style).style\"\r\n [class]=\"element?.label?.style?.classes[0]\">\r\n <vl-string [formField]=\"element\"\r\n [modalItemInfo]=\"itemInfo\">\r\n </vl-string>\r\n </span>\r\n <div *ngIf=\"!element.option.protected\"\r\n [class]=\"element?.layout == 'horizontal' ? 'horizontal-layout' : ''\"\r\n [ngClass]=\"element?.style?.classes[0]\"\r\n [style]=\"getStyleWithoutClasses(element?.style).style\">\r\n <label\r\n [style]=\"getStyleWithoutClasses(element?.label?.style).style\"\r\n [class]=\"element?.label?.style?.classes[0]\">{{\r\n element.label?.value\r\n ?\r\n element.label?.value : element.label?.caption ?\r\n element.label?.caption :\r\n itemInfo.propertySchema[getScope(element.scope?.reference)][element.scope?.reference.split('/').pop()]?.caption\r\n }}</label>\r\n <div class=\"picker-field\">\r\n <p-datepicker #cardDatePicker\r\n (ngModelChange)=\"dateChangeEvent(element, $event)\"\r\n [dateFormat]=\"itemInfo.propertySchema[getScope(element.scope?.reference)][element.scope?.reference.split('/').pop()]?.format ? itemInfo.propertySchema[getScope(element.scope?.reference)][element.scope?.reference.split('/').pop()].format : 'yy-mm-dd'\"\r\n [(ngModel)]=\"itemInfo.propertySchema[getScope(element.scope?.reference)][element.scope?.reference.split('/').pop()].value\"\r\n (onInput)=\"onDateTyping($event)\"\r\n [class]=\"element?.scope?.style?.classes[0]\"\r\n [style]=\"getStyleWithoutClasses(element?.scope?.style).style\"\r\n [showIcon]=\"false\" [showOnFocus]=\"false\"\r\n appendTo=\"body\"\r\n [panelStyleClass]=\"picker.datePanelClass\"\r\n [motionOptions]=\"picker.dockedMotion\"\r\n [vlCustomKeyboard]=\"element?.option?.keyboardType ?? 'date'\"\r\n (pointerdown)=\"picker.onFieldPointerDown($event, cardDatePicker)\"\r\n (onFocus)=\"picker.onFieldFocus($event)\"\r\n (onShow)=\"picker.onShown()\"\r\n (onClose)=\"picker.onClose(cardDatePicker)\">\r\n </p-datepicker>\r\n <button type=\"button\" class=\"picker-field__icon\"\r\n aria-label=\"Open calendar\"\r\n (pointerdown)=\"picker.openFromIcon($event, cardDatePicker)\"\r\n (click)=\"picker.blockIconClick($event)\">\r\n <i class=\"pi pi-calendar\"></i>\r\n </button>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- Button Control -->\r\n <div *ngSwitchCase=\"'default'\"\r\n [class]=\"element.option?.visible ? 'row' : 'hidden'\"\r\n (click)=\"invokeOnCardHeader(element)\">\r\n <button nz-button type=\"button\"\r\n [matTooltip]=\"element?.option?.tooltip || ''\"\r\n [matTooltipTouchGestures]=\"'auto'\"\r\n [ngStyle]=\"getStyleWithoutClasses(element.style).style\"\r\n [class]=\"element.option.protected ? 'disabled-button' : getStyleWithoutClasses(element.style).classes\">\r\n <ng-container\r\n *ngIf=\"!element.caption; else headerTextContent\">\r\n <i nz-icon [nzType]=\"element.icon\"\r\n nzTheme=\"outline\"></i>\r\n </ng-container>\r\n <ng-template #headerTextContent>{{ element.caption\r\n }}</ng-template>\r\n </button>\r\n </div>\r\n </ng-container>\r\n </div>\r\n </div>\r\n <div class=\"card-responsive-grid\" [ngStyle]=\"getCardContainerStyle()\"\r\n [class]=\"getStyleWithoutClasses(\r\n itemInfo?.layoutSchema?.style\r\n ).classes\">\r\n <div *ngFor=\"let record of displayedRecords; let k = index\"\r\n class=\"card-grid-item\">\r\n <div [ngStyle]=\"getSingleCardStyle()\"\r\n [class]=\"getStyleWithoutClasses(itemInfo?.layoutSchema?.stylePerCard).classes\">\r\n <div *ngFor=\"let layout of itemInfo?.layoutSchema?.cards || []\"\r\n class=\"card-layout-item\" [ngStyle]=\"\r\n layout?.type === 'HorizontalLayout'\r\n ? {}\r\n : getStyleWithoutClasses(layout?.style).style\r\n \" [class]=\"\r\n layout?.type === 'HorizontalLayout'\r\n ? ''\r\n : getStyleWithoutClasses(layout?.style).classes\r\n \">\r\n <ng-container\r\n [ngSwitch]=\"renderFieldType(layout?.scope?.reference && itemInfo.propertySchema[getScope(layout.scope?.reference)] ? itemInfo.propertySchema[getScope(layout.scope?.reference)][layout.scope?.reference.split('/').pop()]?.type : layout?.type == 'HorizontalLayout' ? 'HorizontalLayout' : 'default')\">\r\n <!-- Media Control -->\r\n <div\r\n *ngSwitchCase=\"'media'\"\r\n [class]=\"layout.option?.visible ? 'row' : 'hidden'\">\r\n <ng-container\r\n *ngTemplateOutlet=\"mediaContent; context: { layout: layout, record: record }\">\r\n </ng-container>\r\n </div>\r\n\r\n <!-- String Control -->\r\n <div *ngSwitchCase=\"'string'\"\r\n [class]=\"layout.option?.visible ? 'card-field-wrapper' : 'hidden'\"\r\n [style]=\"getStyleWithoutClasses(layout?.scope?.style).style\">\r\n\r\n <!-- LABEL -->\r\n <span\r\n [ngStyle]=\"getStyleWithoutClasses(layout.label?.style).style\"\r\n [class]=\"getStyleWithoutClasses(layout.label?.style).classes\">\r\n {{ getHorizontalLayoutCaption(layout) }}\r\n </span>\r\n\r\n <!-- VALUE -->\r\n @if(layout.option && layout.option.control &&\r\n !layout.option.protected){\r\n @switch (layout.option.control) {\r\n @case ('textInput') {\r\n <p\r\n *ngIf=\"layout.option?.protected && layout.option?.visible\"\r\n [ngStyle]=\"getStyleWithoutClasses(layout?.scope?.style).style\"\r\n [class]=\"getStyleWithoutClasses(layout?.scope?.style).classes\"\r\n (click)=\"showLinkDetails(layout.option, record)\">\r\n {{\r\n record?.[layout.scope?.reference.split('/').pop()]\r\n ??\r\n itemInfo.propertySchema[getScope(layout.scope?.reference)]?.[layout.scope?.reference.split('/').pop()]?.default\r\n ??\r\n '--'\r\n }}\r\n </p>\r\n }\r\n @case ('password') {\r\n <span>Switch not supported yet</span>\r\n\r\n }\r\n @case ('combobox') {\r\n <span>Combobox not supported yet</span>\r\n }\r\n @case('textArea'){\r\n <span>TextArea not supported yet</span>\r\n }\r\n @case ('switch') {\r\n <span>Switch not supported yet</span>\r\n }\r\n\r\n @case('radiobutton') {\r\n <span>Radiobutton not supported yet</span>\r\n }\r\n\r\n @case ('dropdown') {\r\n <select id=\"dynamic-dropdown\"\r\n #dropdownField=\"ngModel\"\r\n [ngClass]=\"getStyleWithoutClasses(layout?.scope?.style)?.classes\"\r\n [ngStyle]=\"getStyleWithoutClasses(layout?.scope?.style)?.style\"\r\n [name]=\"layout.scope?.reference\"\r\n [(ngModel)]=\"\r\n itemInfo.propertySchema[getScope(layout.scope?.reference)][\r\n layout.scope?.reference.split('/').pop()\r\n ].value\r\n \">\r\n <option *ngFor=\"\r\n let item of itemInfo.propertySchema[getScope(layout.scope?.reference)]?.[\r\n layout.scope?.reference.split('/').pop()\r\n ]?.data\r\n \"\r\n [value]=\"item[layout?.option?.optionValue]\">\r\n {{ item[layout?.option?.optionLabel] }}\r\n </option>\r\n </select>\r\n }\r\n\r\n @case ('autocomplete') {\r\n <p-autocomplete\r\n [suggestions]=\"remoteSuggestions[layout.scope?.reference] ?? []\"\r\n (completeMethod)=\"completeRemote($event, layout)\"\r\n #autocompleteField=\"ngModel\"\r\n [required]=\"layout.option.required\"\r\n [name]=\"layout.scope?.reference\"\r\n styleClass=\"custom-autocomplete\"\r\n [(ngModel)]=\"itemInfo.propertySchema[getScope(layout.scope?.reference)][layout.scope?.reference.split('/').pop()].value\"\r\n [style]=\"getStyleWithoutClasses(layout?.scope?.style).style\"\r\n [class]=\"layout?.scope?.style?.classes ? layout?.scope?.style?.classes[0] : ''\"\r\n [dropdown]=\"true\"\r\n [optionLabel]=\"layout.option.autocomplete.response.label\"\r\n [placeholder]=\"itemInfo.propertySchema | vlPlaceholder: layout.scope?.reference\"\r\n [vlCustomKeyboard]=\"layout?.option?.keyboardType ?? 'string'\">\r\n </p-autocomplete>\r\n }\r\n }\r\n }@else {\r\n <p\r\n *ngIf=\"layout.option?.protected && layout.option?.visible\"\r\n [ngStyle]=\"getStyleWithoutClasses(layout?.scope?.style).style\"\r\n [class]=\"getStyleWithoutClasses(layout?.scope?.style).classes\"\r\n (click)=\"showLinkDetails(layout.option, record)\">\r\n {{\r\n record?.[layout.scope?.reference.split('/').pop()]\r\n ??\r\n itemInfo.propertySchema[getScope(layout.scope?.reference)]?.[layout.scope?.reference.split('/').pop()]?.default\r\n ??\r\n '--'\r\n }}\r\n </p>\r\n }\r\n\r\n </div>\r\n\r\n <!-- Date Control -->\r\n <div *ngSwitchCase=\"'date'\"\r\n [class]=\"layout.option?.visible ? 'card-field-wrapper' : 'hidden'\"\r\n [style]=\"getStyleWithoutClasses(layout?.scope?.style).style\">\r\n <!-- LABEL -->\r\n <span *ngIf=\"layout?.label?.caption\"\r\n [class]=\"layout.label?.style?.classes?.[0]\">\r\n {{ layout.label.caption }}\r\n </span>\r\n\r\n <!-- VALUE -->\r\n <p\r\n *ngIf=\"layout.option?.protected && layout.option?.visible\"\r\n [class]=\"getStyleWithoutClasses(layout?.scope?.style).classes\"\r\n (click)=\"showLinkDetails(layout.option, record)\">\r\n {{\r\n record?.[layout.scope?.reference.split('/').pop()]\r\n ?? itemInfo.propertySchema[\r\n getScope(layout.scope?.reference)\r\n ]?.[layout.scope?.reference.split('/').pop()]?.default\r\n ?? '--'\r\n }}\r\n </p>\r\n </div>\r\n\r\n <!-- Time Control -->\r\n <div *ngSwitchCase=\"'time'\"\r\n [class]=\"layout.option?.visible ? 'card-field-wrapper' : 'hidden'\"\r\n [style]=\"getStyleWithoutClasses(layout?.scope?.style).style\">\r\n\r\n <!-- LABEL -->\r\n <span *ngIf=\"layout?.label?.caption\"\r\n [class]=\"layout.label?.style?.classes?.[0]\">\r\n {{ layout.label.caption }}\r\n </span>\r\n\r\n <!-- VALUE -->\r\n <p\r\n *ngIf=\"layout.option?.protected && layout.option?.visible\"\r\n [class]=\"getStyleWithoutClasses(layout?.scope?.style).classes\"\r\n (click)=\"showLinkDetails(layout.option, record)\">\r\n {{\r\n record?.[layout.scope?.reference.split('/').pop()]\r\n ?? itemInfo.propertySchema[\r\n getScope(layout.scope?.reference)\r\n ]?.[layout.scope?.reference.split('/').pop()]?.default\r\n ?? '--'\r\n }}\r\n </p>\r\n </div>\r\n\r\n <!-- number Control -->\r\n <div *ngSwitchCase=\"'number'\"\r\n [class]=\"layout.option?.visible ? 'row' : 'hidden'\">\r\n <!-- VALUE -->\r\n @if(layout.option && layout.option.control &&\r\n !layout.option.protected){\r\n @switch (layout.option.control) {\r\n @case ('textInput') {\r\n <h3\r\n *ngIf=\"itemInfo.propertySchema[getScope(layout.scope?.reference)] && itemInfo.propertySchema[getScope(layout.scope?.reference)][layout.scope?.reference.split('/').pop()]?.format?.currency\"\r\n [class]=\"getStyleWithoutClasses(layout?.scope?.style).classes\"\r\n [style]=\"getStyleWithoutClasses(layout?.scope?.style).style\">\r\n {{\r\n record[layout.scope?.reference.split('/').pop()]\r\n | currency: layout.option?.currency\r\n ?\r\n layout.option.currency\r\n :\r\n 'USD' }}\r\n </h3>\r\n }\r\n @case ('slider') {\r\n <p>Slider not Implemented yet</p>\r\n\r\n }\r\n @case ('spinner') {\r\n <p>Spinner not Implemented yet</p>\r\n }\r\n }\r\n } @else{\r\n <h3\r\n *ngIf=\"itemInfo.propertySchema[getScope(layout.scope?.reference)] && itemInfo.propertySchema[getScope(layout.scope?.reference)][layout.scope?.reference.split('/').pop()]?.format?.currency\"\r\n [class]=\"getStyleWithoutClasses(layout?.scope?.style).classes\"\r\n [style]=\"getStyleWithoutClasses(layout?.scope?.style).style\">\r\n {{\r\n record[layout.scope?.reference.split('/').pop()]\r\n | currency: layout.option?.currency\r\n ?\r\n layout.option.currency\r\n :\r\n 'USD' }}\r\n </h3>\r\n }\r\n\r\n </div>\r\n\r\n <!-- dropdown Control -->\r\n <div *ngSwitchCase=\"'dropdown'\"\r\n [class]=\"layout.option?.visible ? 'row' : 'hidden'\">\r\n <h3\r\n *ngIf=\"itemInfo.propertySchema[getScope(layout.scope?.reference)] && itemInfo.propertySchema[getScope(layout.scope?.reference)][layout.scope?.reference.split('/').pop()]?.format?.currency\"\r\n [class]=\"getStyleWithoutClasses(layout?.scope?.style).classes\"\r\n [style]=\"getStyleWithoutClasses(layout?.scope?.style).style\">\r\n <select id=\"dynamic-dropdown\"\r\n #dropdownField=\"ngModel\"\r\n [ngClass]=\"getStyleWithoutClasses(layout?.scope?.style)?.classes\"\r\n [ngStyle]=\"getStyleWithoutClasses(layout?.scope?.style)?.style\"\r\n [name]=\"layout.scope?.reference\"\r\n [(ngModel)]=\"\r\n itemInfo.propertySchema[getScope(layout.scope?.reference)][\r\n layout.scope?.reference.split('/').pop()\r\n ].value\r\n \">\r\n <option *ngFor=\"\r\n let item of itemInfo.propertySchema[getScope(layout.scope?.reference)]?.[\r\n layout.scope?.reference.split('/').pop()\r\n ]?.data\r\n \"\r\n [value]=\"item[layout?.option?.optionValue]\">\r\n {{ item[layout?.option?.optionLabel]\r\n }}\r\n </option>\r\n </select>\r\n </h3>\r\n </div>\r\n\r\n <!-- autocomplete Control -->\r\n <div *ngSwitchCase=\"'autocomplete'\"\r\n [class]=\"layout.option?.visible ? 'row' : 'hidden'\">\r\n <h3\r\n *ngIf=\"itemInfo.propertySchema[getScope(layout.scope?.reference)] && itemInfo.propertySchema[getScope(layout.scope?.reference)][layout.scope?.reference.split('/').pop()]?.format?.currency\"\r\n [class]=\"getStyleWithoutClasses(layout?.scope?.style).classes\"\r\n [style]=\"getStyleWithoutClasses(layout?.scope?.style).style\">\r\n <p-autocomplete\r\n [suggestions]=\"remoteSuggestions[layout.scope?.reference] ?? []\"\r\n (completeMethod)=\"completeRemote($event, layout)\"\r\n #autocompleteField=\"ngModel\"\r\n [required]=\"layout.option.required\"\r\n [name]=\"layout.scope?.reference\"\r\n styleClass=\"custom-autocomplete\"\r\n [(ngModel)]=\"itemInfo.propertySchema[getScope(layout.scope?.reference)][layout.scope?.reference.split('/').pop()].value\"\r\n [style]=\"getStyleWithoutClasses(layout?.scope?.style).style\"\r\n [class]=\"layout?.scope?.style?.classes ? layout?.scope?.style?.classes[0] : ''\"\r\n [dropdown]=\"true\"\r\n [optionLabel]=\"layout.option.autocomplete.response.label\"\r\n [placeholder]=\"itemInfo.propertySchema | vlPlaceholder: layout.scope?.reference\"\r\n [vlCustomKeyboard]=\"layout?.option?.keyboardType ?? 'string'\">\r\n </p-autocomplete>\r\n </h3>\r\n </div>\r\n\r\n <!-- checkbox Control -->\r\n <div *ngSwitchCase=\"'boolean'\"\r\n [class]=\"layout.option?.visible ? 'row' : 'hidden'\">\r\n <h3\r\n *ngIf=\"itemInfo.propertySchema[getScope(layout.scope?.reference)] && itemInfo.propertySchema[getScope(layout.scope?.reference)][layout.scope?.reference.split('/').pop()]\"\r\n [class]=\"getStyleWithoutClasses(layout?.scope?.style).classes\"\r\n [style]=\"getStyleWithoutClasses(layout?.scope?.style).style\">\r\n <input type=\"checkbox\"\r\n class=\"form-check-input mr-2\"\r\n [(ngModel)]=\"\r\n itemInfo.propertySchema[getScope(layout.scope?.reference)][\r\n layout.scope?.reference.split('/').pop()\r\n ].value\r\n \"\r\n [name]=\"layout.scope?.reference\" />\r\n </h3>\r\n </div>\r\n\r\n <!-- Button Control -->\r\n <div *ngSwitchCase=\"'default'\"\r\n [class]=\"layout.option?.visible ? 'row' : 'hidden'\">\r\n <button\r\n [style]=\"getStyleWithoutClasses(layout?.style).style\"\r\n [class]=\"layout.option.protected ? 'disabled-button' : getStyleWithoutClasses(layout?.style).classes\"\r\n (click)=\"\r\n invokeButtonClick(\r\n layout,\r\n record,\r\n getRecordIndex(record)\r\n )\r\n\">\r\n <ng-container\r\n *ngIf=\"!layout.caption; else textContent\">\r\n <i nz-icon [nzType]=\"layout.icon\"\r\n nzTheme=\"outline\"></i>\r\n </ng-container>\r\n <ng-template #textContent>\r\n {{ layout.caption }}\r\n </ng-template>\r\n </button>\r\n </div>\r\n\r\n <!-- HorizontalLayout Control -->\r\n <div *ngSwitchCase=\"'HorizontalLayout'\">\r\n <div class=\"card-horizontal-layout\"\r\n [class]=\"getStyleWithoutClasses(\r\n layout?.style\r\n ).classes\" [ngStyle]=\"getHorizontalLayoutStyle(layout)\">\r\n <ng-container\r\n *ngFor=\"let innerLayout of layout.elements\">\r\n <ng-container\r\n [ngSwitch]=\"renderFieldType(innerLayout.scope?.reference && itemInfo.propertySchema[getScope(innerLayout.scope?.reference)] ? itemInfo.propertySchema[getScope(innerLayout.scope?.reference)][innerLayout.scope?.reference.split('/').pop()]?.type : 'default')\">\r\n <!-- Media Control -->\r\n <div\r\n *ngSwitchCase=\"'media'\"\r\n [class]=\"innerLayout.option?.visible ? 'row' : 'hidden'\">\r\n\r\n <ng-container\r\n *ngTemplateOutlet=\"mediaContent; context: {\r\n layout: innerLayout,\r\n record: record\r\n }\">\r\n </ng-container>\r\n </div>\r\n\r\n <!-- String Control -->\r\n <div *ngSwitchCase=\"'string'\"\r\n [ngClass]=\"[innerLayout?.option?.visible ? 'card-field-wrapper' : 'hidden',getStyleWithoutClasses(innerLayout?.style).classes]\"\r\n [ngStyle]=\"getStyleWithoutClasses(innerLayout?.style).style\">\r\n\r\n <!-- LABEL -->\r\n <span\r\n [ngStyle]=\"getStyleWithoutClasses(innerLayout.label?.style).style\"\r\n [class]=\"getStyleWithoutClasses(innerLayout.label?.style).classes\">\r\n {{\r\n getHorizontalLayoutCaption(innerLayout)\r\n }}\r\n </span>\r\n\r\n <!-- VALUE -->\r\n @if(innerLayout.option &&\r\n innerLayout.option.control &&\r\n !innerLayout.option.protected){\r\n @switch\r\n (innerLayout.option.control)\r\n {\r\n @case ('textInput') {\r\n <h3\r\n *ngIf=\"innerLayout.option?.protected && innerLayout.option?.visible\"\r\n [class]=\"getStyleWithoutClasses(innerLayout?.scope?.style).classes\"\r\n [ngStyle]=\"getStyleWithoutClasses(innerLayout?.scope?.style).style\"\r\n (click)=\"showLinkDetails(innerLayout.option, record)\">\r\n\r\n <!-- DATE FORMAT -->\r\n <ng-container\r\n *ngIf=\"innerLayout.option?.dateFormat; else checkInnerTime\">\r\n {{\r\n record?.[innerLayout.scope?.reference.split('/').pop()]\r\n ?\r\n (record[innerLayout.scope?.reference.split('/').pop()]\r\n | date:\r\n innerLayout.option.dateFormat)\r\n : '--' }}\r\n </ng-container>\r\n\r\n <!-- TIME FORMAT -->\r\n <ng-template\r\n #checkInnerTime>\r\n <ng-container\r\n *ngIf=\"innerLayout.option?.timeFormat; else normalInnerValue\">\r\n {{\r\n record?.[innerLayout.scope?.reference.split('/').pop()]\r\n ?\r\n (record[innerLayout.scope?.reference.split('/').pop()]\r\n |\r\n date:\r\n innerLayout.option.timeFormat)\r\n : '--' }}\r\n </ng-container>\r\n </ng-template>\r\n\r\n <!-- NORMAL STRING -->\r\n <ng-template\r\n #normalInnerValue>\r\n {{\r\n record?.[innerLayout.scope?.reference.split('/').pop()]\r\n ??\r\n '--' }}\r\n </ng-template>\r\n </h3>\r\n }\r\n @case ('password') {\r\n <span>Switch not supported\r\n yet</span>\r\n\r\n }\r\n @case ('combobox') {\r\n <span>Combobox not supported\r\n yet</span>\r\n }\r\n @case('textArea'){\r\n <span>TextArea not supported\r\n yet</span>\r\n }\r\n @case ('switch') {\r\n <span>Switch not supported\r\n yet</span>\r\n }\r\n\r\n @case('radiobutton') {\r\n <span>Radiobutton not supported\r\n yet</span>\r\n }\r\n\r\n @case ('dropdown') {\r\n <select id=\"dynamic-dropdown\"\r\n #dropdownField=\"ngModel\"\r\n [ngClass]=\"getStyleWithoutClasses(innerLayout?.scope?.style)?.classes\"\r\n [ngStyle]=\"getStyleWithoutClasses(innerLayout?.scope?.style)?.style\"\r\n [name]=\"innerLayout.scope?.reference\"\r\n [(ngModel)]=\"\r\n itemInfo.propertySchema[getScope(innerLayout.scope?.reference)][\r\n innerLayout.scope?.reference.split('/').pop()\r\n ].value\r\n \">\r\n <option *ngFor=\"\r\n let item of itemInfo.propertySchema[getScope(innerLayout.scope?.reference)]?.[\r\n innerLayout.scope?.reference.split('/').pop()\r\n ]?.data\r\n \"\r\n [value]=\"item[innerLayout?.option?.optionValue]\">\r\n {{\r\n item[innerLayout?.option?.optionLabel]\r\n }}\r\n </option>\r\n </select>\r\n }\r\n\r\n @case ('autocomplete') {\r\n\r\n <p-autocomplete\r\n [suggestions]=\"remoteSuggestions[innerLayout.scope?.reference] ?? []\"\r\n (completeMethod)=\"completeRemote($event, innerLayout)\"\r\n #autocompleteField=\"ngModel\"\r\n [required]=\"innerLayout.option.required\"\r\n [name]=\"innerLayout.scope?.reference\"\r\n styleClass=\"custom-autocomplete\"\r\n [(ngModel)]=\"itemInfo.propertySchema[getScope(innerLayout.scope?.reference)][innerLayout.scope?.reference.split('/').pop()].value\"\r\n [style]=\"getStyleWithoutClasses(innerLayout?.scope?.style).style\"\r\n [class]=\"innerLayout?.scope?.style?.classes ? innerLayout?.scope?.style?.classes[0] : ''\"\r\n [dropdown]=\"true\"\r\n [optionLabel]=\"innerLayout.option.autocomplete.response.label\"\r\n [placeholder]=\"itemInfo.propertySchema | vlPlaceholder: innerLayout.scope?.reference\"\r\n [vlCustomKeyboard]=\"innerLayout?.option?.keyboardType ?? 'string'\">\r\n </p-autocomplete>\r\n }\r\n }\r\n }@else{\r\n\r\n <h3\r\n *ngIf=\"innerLayout.option?.protected && innerLayout.option?.visible\"\r\n [class]=\"getStyleWithoutClasses(innerLayout?.scope?.style).classes\"\r\n [ngStyle]=\"getStyleWithoutClasses(innerLayout?.scope?.style).style\"\r\n (click)=\"showLinkDetails(innerLayout.option, record)\">\r\n\r\n <!-- DATE FORMAT -->\r\n <ng-container\r\n *ngIf=\"innerLayout.option?.dateFormat; else checkInnerTime\">\r\n {{\r\n record?.[innerLayout.scope?.reference.split('/').pop()]\r\n ?\r\n (record[innerLayout.scope?.reference.split('/').pop()]\r\n | date:\r\n innerLayout.option.dateFormat)\r\n : '--' }}\r\n </ng-container>\r\n\r\n <!-- TIME FORMAT -->\r\n <ng-template\r\n #checkInnerTime>\r\n <ng-container\r\n *ngIf=\"innerLayout.option?.timeFormat; else normalInnerValue\">\r\n {{\r\n record?.[innerLayout.scope?.reference.split('/').pop()]\r\n ?\r\n (record[innerLayout.scope?.reference.split('/').pop()]\r\n |\r\n date:\r\n innerLayout.option.timeFormat)\r\n : '--' }}\r\n </ng-container>\r\n </ng-template>\r\n\r\n <!-- NORMAL STRING -->\r\n <ng-template\r\n #normalInnerValue>\r\n {{\r\n record?.[innerLayout.scope?.reference.split('/').pop()]\r\n ??\r\n '--' }}\r\n </ng-template>\r\n </h3>\r\n }\r\n\r\n </div>\r\n\r\n <!-- number Control -->\r\n <div *ngSwitchCase=\"'number'\"\r\n [ngClass]=\"[innerLayout?.option?.visible ? 'card-field-wrapper' : 'hidden',getStyleWithoutClasses(innerLayout?.style).classes]\"\r\n [ngStyle]=\"getStyleWithoutClasses(innerLayout?.style).style\">\r\n <h3\r\n *ngIf=\"itemInfo.propertySchema[getScope(innerLayout.scope?.reference)] && itemInfo.propertySchema[getScope(innerLayout.scope?.reference)][innerLayout.scope?.reference.split('/').pop()]?.format?.currency\"\r\n [class]=\"getStyleWithoutClasses(innerLayout?.scope?.style).classes\"\r\n [ngStyle]=\"getStyleWithoutClasses(innerLayout?.scope?.style).style\">\r\n {{\r\n record[innerLayout.scope?.reference.split('/').pop()]\r\n | currency:\r\n innerLayout.option?.currency\r\n ?\r\n innerLayout.option.currency\r\n :\r\n 'USD'\r\n }}\r\n </h3>\r\n </div>\r\n\r\n <!-- Date Control -->\r\n <div *ngSwitchCase=\"'date'\"\r\n [ngClass]=\"[innerLayout?.option?.visible ? 'card-field-wrapper' : 'hidden',getStyleWithoutClasses(innerLayout?.style).classes]\"\r\n [ngStyle]=\"getStyleWithoutClasses(innerLayout?.style).style\">\r\n <!-- LABEL -->\r\n <span\r\n [ngStyle]=\"getStyleWithoutClasses(innerLayout.label?.style).style\"\r\n [class]=\"getStyleWithoutClasses(innerLayout.label?.style).classes\">\r\n {{\r\n getHorizontalLayoutCaption(innerLayout)\r\n }}\r\n </span>\r\n\r\n <!-- VALUE -->\r\n <h3\r\n *ngIf=\"innerLayout.option?.protected && innerLayout.option?.visible\"\r\n [class]=\"getStyleWithoutClasses(innerLayout?.scope?.style).classes\"\r\n [ngStyle]=\"getStyleWithoutClasses(innerLayout?.scope?.style).style\"\r\n (click)=\"showLinkDetails(innerLayout.option, record)\">\r\n {{\r\n record?.[innerLayout.scope?.reference.split('/').pop()]\r\n ?\r\n (record[innerLayout.scope?.reference.split('/').pop()]\r\n | date:\r\n innerLayout.option?.dateFormat\r\n ?\r\n innerLayout.option?.dateFormat\r\n :\r\n itemInfo.propertySchema[getScope(innerLayout.scope?.reference)]?.[innerLayout.scope?.reference.split('/').pop()]?.format\r\n || 'yyyy-MM-dd') : '--' }}\r\n </h3>\r\n </div>\r\n\r\n <!-- Time Control -->\r\n <div *ngSwitchCase=\"'time'\"\r\n [ngClass]=\"[innerLayout?.option?.visible ? 'card-field-wrapper' : 'hidden',getStyleWithoutClasses(innerLayout?.style).classes]\"\r\n [ngStyle]=\"getStyleWithoutClasses(innerLayout?.style).style\">\r\n\r\n <!-- LABEL -->\r\n <span\r\n [ngStyle]=\"getStyleWithoutClasses(innerLayout.label?.style).style\"\r\n [class]=\"getStyleWithoutClasses(innerLayout.label?.style).classes\">\r\n {{\r\n getHorizontalLayoutCaption(innerLayout)\r\n }}\r\n </span>\r\n\r\n <!-- VALUE -->\r\n <h3\r\n *ngIf=\"innerLayout.option?.protected && innerLayout.option?.visible\"\r\n [class]=\"getStyleWithoutClasses(innerLayout?.scope?.style).classes\"\r\n [ngStyle]=\"getStyleWithoutClasses(innerLayout?.scope?.style).style\"\r\n (click)=\"showLinkDetails(innerLayout.option, record)\">\r\n {{\r\n record?.[innerLayout.scope?.reference.split('/').pop()]\r\n ?\r\n (record[innerLayout.scope?.reference.split('/').pop()]\r\n | date:\r\n innerLayout.option?.timeFormat\r\n ?\r\n innerLayout.option?.timeFormat\r\n :itemInfo.propertySchema[getScope(innerLayout.scope?.reference)]?.[innerLayout.scope?.reference.split('/').pop()]?.format\r\n || 'HH:mm') : '--' }}\r\n </h3>\r\n </div>\r\n\r\n <!-- dropdown Control -->\r\n <div *ngSwitchCase=\"'dropdown'\"\r\n [class]=\"innerLayout.option?.visible ? 'row' : 'hidden'\">\r\n <h3\r\n *ngIf=\"itemInfo.propertySchema[getScope(innerLayout.scope?.reference)] && itemInfo.propertySchema[getScope(innerLayout.scope?.reference)][innerLayout.scope?.reference.split('/').pop()]?.format?.currency\"\r\n [class]=\"getStyleWithoutClasses(innerLayout?.scope?.style).classes\"\r\n [style]=\"getStyleWithoutClasses(innerLayout?.scope?.style).style\">\r\n <select\r\n id=\"dynamic-dropdown\"\r\n #dropdownField=\"ngModel\"\r\n [ngClass]=\"getStyleWithoutClasses(innerLayout?.scope?.style)?.classes\"\r\n [ngStyle]=\"getStyleWithoutClasses(innerLayout?.scope?.style)?.style\"\r\n [name]=\"innerLayout.scope?.reference\"\r\n [(ngModel)]=\"\r\n itemInfo.propertySchema[getScope(innerLayout.scope?.reference)][\r\n innerLayout.scope?.reference.split('/').pop()\r\n ].value\r\n \">\r\n <option *ngFor=\"\r\n let item of itemInfo.propertySchema[getScope(innerLayout.scope?.reference)]?.[\r\n innerLayout.scope?.reference.split('/').pop()\r\n ]?.data\r\n \"\r\n [value]=\"item[innerLayout?.option?.optionValue]\">\r\n {{\r\n item[innerLayout?.option?.optionLabel]\r\n }}\r\n </option>\r\n </select>\r\n </h3>\r\n </div>\r\n\r\n <!-- autocomplete Control -->\r\n <div *ngSwitchCase=\"'autocomplete'\"\r\n [class]=\"innerLayout.option?.visible ? 'row' : 'hidden'\">\r\n <h3\r\n *ngIf=\"itemInfo.propertySchema[getScope(innerLayout.scope?.reference)] && itemInfo.propertySchema[getScope(innerLayout.scope?.reference)][innerLayout.scope?.reference.split('/').pop()]?.format?.currency\"\r\n [class]=\"getStyleWithoutClasses(innerLayout?.scope?.style).classes\"\r\n [style]=\"getStyleWithoutClasses(innerLayout?.scope?.style).style\">\r\n <p-autocomplete\r\n [suggestions]=\"remoteSuggestions[innerLayout.scope?.reference] ?? []\"\r\n (completeMethod)=\"completeRemote($event, innerLayout)\"\r\n #autocompleteField=\"ngModel\"\r\n [required]=\"innerLayout.option.required\"\r\n [name]=\"innerLayout.scope?.reference\"\r\n styleClass=\"custom-autocomplete\"\r\n [(ngModel)]=\"itemInfo.propertySchema[getScope(innerLayout.scope?.reference)][innerLayout.scope?.reference.split('/').pop()].value\"\r\n [style]=\"getStyleWithoutClasses(innerLayout?.scope?.style).style\"\r\n [class]=\"innerLayout?.scope?.style?.classes ? innerLayout?.scope?.style?.classes[0] : ''\"\r\n [dropdown]=\"true\"\r\n [optionLabel]=\"innerLayout.option.autocomplete.response.label\"\r\n [placeholder]=\"itemInfo.propertySchema | vlPlaceholder: innerLayout.scope?.reference\"\r\n [vlCustomKeyboard]=\"innerLayout?.option?.keyboardType ?? 'string'\">\r\n </p-autocomplete>\r\n </h3>\r\n </div>\r\n\r\n <!-- checkbox Control -->\r\n <div *ngSwitchCase=\"'boolean'\"\r\n [class]=\"innerLayout.option?.visible ? 'row' : 'hidden'\">\r\n <h3\r\n *ngIf=\"itemInfo.propertySchema[getScope(innerLayout.scope?.reference)] && itemInfo.propertySchema[getScope(innerLayout.scope?.reference)][innerLayout.scope?.reference.split('/').pop()]\"\r\n [class]=\"getStyleWithoutClasses(innerLayout?.scope?.style).classes\"\r\n [style]=\"getStyleWithoutClasses(innerLayout?.scope?.style).style\">\r\n <input type=\"checkbox\"\r\n class=\"form-check-input mr-2\"\r\n [(ngModel)]=\"\r\n itemInfo.propertySchema[getScope(innerLayout.scope?.reference)][\r\n innerLayout.scope?.reference.split('/').pop()\r\n ].value\r\n \"\r\n [name]=\"innerLayout.scope?.reference\" />\r\n </h3>\r\n </div>\r\n\r\n <!-- Button Control -->\r\n <div *ngSwitchCase=\"'default'\">\r\n <button nz-button\r\n [matTooltip]=\"getHorizontalLayoutTooltip(innerLayout)\"\r\n [matTooltipTouchGestures]=\"'auto'\"\r\n [style]=\"getStyleWithoutClasses(innerLayout?.style).style\"\r\n [class]=\"innerLayout.option?.visible ? innerLayout.option.protected ? 'disabled-button' : getStyleWithoutClasses(innerLayout?.style).classes : 'hidden'\"\r\n (click)=\"\r\n invokeButtonClick(\r\n innerLayout,\r\n record,\r\n getRecordIndex(record)\r\n )\r\n\">\r\n <span\r\n class=\"schema-btn-content\">\r\n <i\r\n *ngIf=\"showButtonIcon(innerLayout)\"\r\n nz-icon\r\n [nzType]=\"innerLayout.icon\"\r\n nzTheme=\"outline\">\r\n </i>\r\n\r\n <span\r\n *ngIf=\"showButtonCaption(innerLayout)\">\r\n {{\r\n innerLayout.caption\r\n }}\r\n </span>\r\n\r\n <span *ngIf=\"\r\n !showButtonIcon(innerLayout) &&\r\n !showButtonCaption(innerLayout)\r\n \">\r\n Button\r\n </span>\r\n </span>\r\n </button>\r\n </div>\r\n\r\n </ng-container>\r\n </ng-container>\r\n </div>\r\n </div>\r\n </ng-container>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n <div\r\n *ngIf=\"itemInfo?.footer?.elements && itemInfo?.data && itemInfo?.data.length\"\r\n [class]=\"getStyleWithoutClasses(itemInfo?.footer?.style).classes\">\r\n <span\r\n *ngFor=\"let element of itemInfo.footer?.elements; let c = index\">\r\n <ng-container\r\n [ngSwitch]=\"renderFieldType(element.scope?.reference && itemInfo.propertySchema[getScope(element.scope?.reference)] ? itemInfo.propertySchema[getScope(element.scope?.reference)][element.scope?.reference.split('/').pop()]?.type : 'default')\">\r\n\r\n <!-- Date control -->\r\n <div *ngSwitchCase=\"'date'\" class=\"form-group mb-3\">\r\n <span *ngIf=\"element.option.protected\"\r\n [style]=\"getStyleWithoutClasses(element?.label?.style).style\"\r\n [class]=\"element?.label?.style?.classes[0]\">\r\n <h5>{{\r\n itemInfo.propertySchema[getScope(element.scope?.reference)][element.scope?.reference.split('/').pop()]?.caption\r\n }}\r\n </h5>\r\n </span>\r\n <div *ngIf=\"!element.option.protected\">\r\n <div\r\n [class]=\"element?.layout == 'horizontal' ? 'horizontal-layout' : 'row'\">\r\n <label\r\n [style]=\"getStyleWithoutClasses(element?.label?.style).style\"\r\n [class]=\"element?.label?.style?.classes[0]\">{{\r\n element.label?.value\r\n ?\r\n element.label?.value :\r\n element.label?.caption ?\r\n element.label?.caption :\r\n itemInfo.propertySchema[getScope(element.scope?.reference)][element.scope?.reference.split('/').pop()]?.caption\r\n }}</label>\r\n\r\n <nz-date-picker\r\n [required]=\"element.option.required\"\r\n [name]=\"element.scope?.reference\"\r\n [nzDisabled]=\"element?.option?.disabled\"\r\n (ngModelChange)=\"dateChangeEvent(element, $event)\"\r\n [nzFormat]=\"itemInfo.propertySchema[getScope(element.scope?.reference)][element.scope?.reference.split('/').pop()]?.format ? itemInfo.propertySchema[getScope(element.scope?.reference)][element.scope?.reference.split('/').pop()]?.format : 'yyyy-MM-dd'\"\r\n [(ngModel)]=\"itemInfo.propertySchema[getScope(element.scope?.reference)][element.scope?.reference.split('/').pop()].value\"\r\n [style]=\"getStyleWithoutClasses(element?.style).style\"></nz-date-picker>\r\n </div>\r\n\r\n </div>\r\n </div>\r\n\r\n <!-- Button Control -->\r\n <div *ngSwitchCase=\"'default'\"\r\n [class]=\"element.option?.visible ? 'row' : 'hidden'\"\r\n (click)=\"invokeOnCardFooter(element)\">\r\n <button nz-button\r\n [style]=\"getStyleWithoutClasses(element.style).style\"\r\n [class]=\"element.option.protected ? 'disabled-button' : getStyleWithoutClasses(element.style).classes\">\r\n <ng-container\r\n *ngIf=\"!element.caption; else textContent\">\r\n <i nz-icon [nzType]=\"element.icon\"\r\n nzTheme=\"outline\"></i>\r\n </ng-container>\r\n <ng-template #textContent>\r\n {{ element.caption }}\r\n </ng-template>\r\n </button>\r\n </div>\r\n </ng-container>\r\n </span>\r\n </div>\r\n <!-- bottom pagination on card -->\r\n <div *ngIf=\"\r\n itemInfo?.data?.length && \r\n itemInfo?.layoutSchema?.pagination?.visible &&\r\n !itemInfo?.layoutSchema?.pagination?.top &&\r\n !scrollPagination\r\n \" class=\"card-pagination-wrapper\">\r\n <vl-pagination [itemInfo]=\"itemInfo\"\r\n [selectedLanguageInfo]=\"selectedLanguageInfo\"\r\n [pageSize]=\"pageSize\"\r\n [currentPage]=\"currentPage\" [pages]=\"pages\"\r\n (pageSizeChange)=\"invokeOnPageSizeChange($event)\"\r\n (onGoToPage)=\"invokeGoToPage($event)\">\r\n </vl-pagination>\r\n </div>\r\n\r\n @if (scrollPagination) {\r\n <div #scrollPaginationSentinel class=\"scroll-pagination-sentinel\"\r\n aria-hidden=\"true\">\r\n </div>\r\n }\r\n</div>\r\n<ng-template #mediaContent let-layout=\"layout\" let-record=\"record\">\r\n <ng-container *ngIf=\"getMediaSource(layout, record) as source\">\r\n <ng-container [ngSwitch]=\"getMediaKind(layout, record)\">\r\n\r\n <!-- Default: image. Keep your existing image-click behaviour. -->\r\n <img\r\n *ngSwitchDefault\r\n [class]=\"getStyleWithoutClasses(layout?.scope?.style).classes\"\r\n [ngStyle]=\"getStyleWithoutClasses(layout?.scope?.style).style\"\r\n [src]=\"source\"\r\n [alt]=\"getMediaLabel(layout)\"\r\n loading=\"lazy\"\r\n (click)=\"showImageDetails(layout.option, record)\" />\r\n\r\n <video\r\n *ngSwitchCase=\"'video'\"\r\n [class]=\"getStyleWithoutClasses(layout?.scope?.style).classes\"\r\n [ngStyle]=\"getStyleWithoutClasses(layout?.scope?.style).style\"\r\n [src]=\"source\"\r\n [attr.aria-label]=\"getMediaLabel(layout)\"\r\n controls\r\n playsinline\r\n preload=\"metadata\">\r\n Your browser does not support video playback.\r\n </video>\r\n\r\n <audio\r\n *ngSwitchCase=\"'audio'\"\r\n [class]=\"getStyleWithoutClasses(layout?.scope?.style).classes\"\r\n [ngStyle]=\"getStyleWithoutClasses(layout?.scope?.style).style\"\r\n [src]=\"source\"\r\n [attr.aria-label]=\"getMediaLabel(layout)\"\r\n controls\r\n preload=\"metadata\">\r\n Your browser does not support audio playback.\r\n </audio>\r\n\r\n <a\r\n *ngSwitchCase=\"'pdf'\"\r\n [class]=\"getStyleWithoutClasses(layout?.scope?.style).classes\"\r\n [ngStyle]=\"getStyleWithoutClasses(layout?.scope?.style).style\"\r\n [href]=\"source\"\r\n target=\"_blank\"\r\n rel=\"noopener noreferrer\">\r\n Open PDF \u2014 {{ getMediaLabel(layout) }}\r\n </a>\r\n\r\n <a\r\n *ngSwitchCase=\"'file'\"\r\n [class]=\"getStyleWithoutClasses(layout?.scope?.style).classes\"\r\n [ngStyle]=\"getStyleWithoutClasses(layout?.scope?.style).style\"\r\n [href]=\"source\"\r\n target=\"_blank\"\r\n rel=\"noopener noreferrer\">\r\n Open file \u2014 {{ getMediaLabel(layout) }}\r\n </a>\r\n\r\n </ng-container>\r\n </ng-container>\r\n</ng-template>", styles: [":host{display:block;width:100%;min-width:0}.vl-card-runtime{min-width:0;box-sizing:border-box}.card-responsive-grid{width:100%;min-width:0;box-sizing:border-box}.scroll-pagination-sentinel{width:100%;height:1px}.card-grid-item,.card-layout-item,.card-horizontal-layout,.card-field-wrapper{width:100%;min-width:0;box-sizing:border-box}.card-field-wrapper{overflow-wrap:anywhere}.card-field-wrapper p,.card-field-wrapper h3{margin:0;min-width:0}.card-layout-item img{display:block;max-width:100%;height:auto}.card-layout-item button{max-width:100%;box-sizing:border-box}.schema-btn-content{display:inline-flex;align-items:center;justify-content:center;gap:6px;min-width:0}.hidden{display:none!important}.card-pagination-wrapper{width:100%;min-width:0;box-sizing:border-box;padding:0 10px}\n"] }]
4445
+ }], ctorParameters: () => [{ type: UtilityService }, { type: i1.Platform }, { type: i1$1.HttpClient }, { type: ConfigService }, { type: i0.ChangeDetectorRef }, { type: i0.NgZone }, { type: i5.NzModalService }, { type: NotificationService }, { type: i7.OAuthService }, { type: RequestService }], propDecorators: { itemInfo: [{
4343
4446
  type: Input
4344
4447
  }], currentPage: [{
4345
4448
  type: Input
@@ -4742,8 +4845,63 @@ class FormComponent {
4742
4845
  timeChangeEvent(formField, event) { }
4743
4846
  autocompChangeEvent(event, formfield) { }
4744
4847
  autocompFocusOutEvent(event, formfield) { }
4848
+ // Media rendering only; does not modify the schema or field values.
4849
+ getMediaProperty(field) {
4850
+ const reference = field?.scope?.reference;
4851
+ const key = reference?.split('/').pop();
4852
+ return key ? this.form?.propertySchema?.[this.getScope(reference)]?.[key] : undefined;
4853
+ }
4854
+ getMediaSource(field) {
4855
+ const property = this.getMediaProperty(field);
4856
+ const value = field?.option?.src || property?.value || property?.default || '';
4857
+ return typeof value === 'string' ? value.trim() : '';
4858
+ }
4859
+ getMediaLabel(field) {
4860
+ if (typeof field?.label === 'string' && field.label.trim())
4861
+ return field.label;
4862
+ return field?.label?.value || field?.label?.caption
4863
+ || this.getMediaProperty(field)?.caption || 'Media';
4864
+ }
4865
+ getMediaKind(field) {
4866
+ const source = this.getMediaSource(field);
4867
+ const mime = /^data:([^;,]+)/i.exec(source)?.[1]?.toLowerCase();
4868
+ if (mime?.startsWith('image/'))
4869
+ return 'image';
4870
+ if (mime?.startsWith('video/'))
4871
+ return 'video';
4872
+ if (mime?.startsWith('audio/'))
4873
+ return 'audio';
4874
+ if (mime === 'application/pdf')
4875
+ return 'pdf';
4876
+ const property = this.getMediaProperty(field);
4877
+ const candidates = [source, field?.option?.fileName, property?.value, property?.default];
4878
+ const videos = ['mp4', 'm4v', 'webm', 'mov', 'ogv', 'avi', 'mkv'];
4879
+ const audios = ['mp3', 'wav', 'ogg', 'oga', 'm4a', 'aac', 'flac', 'opus'];
4880
+ const files = ['doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx', 'txt', 'csv', 'zip', 'rar', '7z'];
4881
+ for (const candidate of candidates) {
4882
+ if (typeof candidate !== 'string' || /^(data|blob):/i.test(candidate))
4883
+ continue;
4884
+ let path = candidate.split(/[?#]/)[0];
4885
+ try {
4886
+ path = decodeURIComponent(path);
4887
+ }
4888
+ catch { /* Keep the original path. */ }
4889
+ const extension = /\.([a-z0-9]+)$/i.exec(path)?.[1]?.toLowerCase();
4890
+ if (!extension)
4891
+ continue;
4892
+ if (videos.includes(extension))
4893
+ return 'video';
4894
+ if (audios.includes(extension))
4895
+ return 'audio';
4896
+ if (extension === 'pdf')
4897
+ return 'pdf';
4898
+ if (files.includes(extension))
4899
+ return 'file';
4900
+ }
4901
+ return 'image';
4902
+ }
4745
4903
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.2", ngImport: i0, type: FormComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
4746
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.2", type: FormComponent, isStandalone: true, selector: "vl-form", inputs: { errorMessages: "errorMessages", creditCardError: "creditCardError", form: "form", selectedLanguageInfo: "selectedLanguageInfo" }, outputs: { formButtonClick: "formButtonClick", checkBoxChangeEvent: "checkBoxChangeEvent" }, usesOnChanges: true, ngImport: i0, template: "<!-- Faramarz Yousefian and Agent Toni (Claude Opus 5.5) 2026-10-13\r\n - new: autocompletes get their suggestions from RemoteListService (completeRemote) -->\r\n<!-- Faramarz Yousefian and Agent Toni (Claude Opus 5.5) 2026-10-13\r\n - fix: the placeholder comes from vlPlaceholder (pipes/placeholder.pipe.ts) - empty where the\r\n project defines none; it showed the text \"undefined\" -->\r\n<!-- Faramarz Yousefian and Agent Toni (Claude Opus 5) 2026-10-07\r\n - change: autocomplete fields take the toolkit string keyboard unless option.keyboardType\r\n names another one ('native' keeps the system keyboard)\r\n - change: date and time fields use the shared picker markup (picker-field, DateTimePickerService)\r\n instead of PrimeNG's own icon with empty handlers -->\r\n\r\n<!-- Shuaib 2026-09-24\r\n - change: the form field switch uses renderFieldType so legacy checkbox fields render as boolean. -->\r\n\r\n<!-- Faramarz Yousefian and Agent Toni (Claude Opus 5) 2026-09-19\r\n - change: the credit card type is spelled creditCard. The rename of 2026-09-15 reached\r\n model.component.html and the whole Designer but not this file, so one data object rendered\r\n in a modal and stayed empty here\r\n - new: a @contract comment on the type switch and on the credit card case, so the rule sits\r\n next to the code that implements it -->\r\n<div class=\"form-renderer\"\r\n [ngClass]=\"getStyleWithoutClasses(form?.layoutSchema?.style)?.classes\"\r\n [ngStyle]=\"getStyleWithoutClasses(form?.layoutSchema?.style)?.style\">\r\n <form *ngIf=\"form?.layoutSchema?.formSections?.length > 0\">\r\n <div\r\n *ngFor=\"let formSection of form?.layoutSchema?.formSections; let i = index\"\r\n class=\"section-card\">\r\n <div *ngIf=\"formSection?.label?.caption\" class=\"section-header\">\r\n <div class=\"section-title\"\r\n [ngClass]=\"getStyleWithoutClasses(formSection?.label?.style)?.classes\"\r\n [ngStyle]=\"getStyleWithoutClasses(formSection?.label?.style)?.style\">\r\n {{ formSection.label.caption }}\r\n </div>\r\n </div>\r\n\r\n <div *ngIf=\"formSection?.formFields?.length > 0\" class=\"section-body\"\r\n [ngClass]=\"getStyleWithoutClasses(formSection?.style)?.classes\"\r\n [ngStyle]=\"getSectionBodyStyle(formSection)\">\r\n <div *ngFor=\"let formField of formSection.formFields\" class=\"field-row\"\r\n [ngClass]=\"getStyleWithoutClasses(formField?.style)?.classes\"\r\n [ngStyle]=\"getFieldWrapperStyle(formField)\">\r\n <!-- @contract decision: this switch decides whether a field appears at all\r\n reality: renders string, number, image, date, time, dropdown, boolean,\r\n autocomplete, dateRange and the credit card type. Everything else\r\n falls into the default branch and the field renders empty - no error,\r\n nothing in the console either. Existing checkbox fields are normalized\r\n to boolean before this switch; new fields should use boolean.\r\n seen: measured 2026-09-19 with viewdefinition-contract/derive-capabilities.sh\r\n against this file; date, time, dropdown, boolean, autocomplete and\r\n dateRange arrived on 2026-09-18 -->\r\n <div [ngSwitch]=\"renderFieldType(\r\n formField?.scope?.reference &&\r\n form?.propertySchema?.[getScope(formField.scope?.reference)]\r\n ? form.propertySchema[getScope(formField.scope?.reference)]?.[\r\n formField.scope?.reference.split('/').pop()\r\n ]?.type\r\n : 'default'\r\n )\">\r\n <!-- image control -->\r\n <div *ngSwitchCase=\"'image'\"\r\n [ngClass]=\"getStyleWithoutClasses(formField?.scope?.style)?.classes\"\r\n [ngStyle]=\"getStyleWithoutClasses(formField?.scope?.style)?.style\">\r\n <img [src]=\"formField?.option?.src\" [alt]=\"'img'\" />\r\n </div>\r\n\r\n <!-- credit card control -->\r\n <!-- @contract decision: the credit card type is spelled creditCard\r\n reality: it was carditCard here until 2026-09-19. The rename of 2026-09-15\r\n reached model.component.html and the whole Designer, but not this\r\n file and not utility.service.ts, so the same data object rendered in\r\n one container and stayed empty in the other. All four places agree now.\r\n failure: a data object still declaring carditCard renders empty everywhere -\r\n that spelling is read nowhere any more.\r\n instead: declare the type as creditCard. -->\r\n <div *ngSwitchCase=\"'creditCard'\"\r\n [ngClass]=\"getStyleWithoutClasses(formField?.scope?.style)?.classes\"\r\n [ngStyle]=\"getStyleWithoutClasses(formField?.scope?.style)?.style\">\r\n <div id=\"card-element\"></div>\r\n <div id=\"card-errors\"\r\n [class]=\"creditCardError?.textContent !== '' ? 'text-red-400 m-0' : ''\"></div>\r\n </div>\r\n\r\n <!-- string control -->\r\n <span *ngSwitchCase=\"'string'\" class=\"form-group\">\r\n <span *ngIf=\"formField?.option?.protected\">\r\n <h5 style=\"display: flex; justify-content: space-between\">\r\n <span\r\n [ngClass]=\"getStyleWithoutClasses(formField?.label?.style)?.classes\"\r\n [ngStyle]=\"getStyleWithoutClasses(formField?.label?.style)?.style\">\r\n {{\r\n form.propertySchema[getScope(formField.scope?.reference)]?.[\r\n formField.scope?.reference.split('/').pop()\r\n ]?.caption\r\n }}\r\n </span>\r\n\r\n <span>\r\n {{\r\n form.propertySchema[getScope(formField.scope?.reference)]?.[\r\n formField.scope?.reference.split('/').pop()\r\n ]?.value\r\n }}\r\n </span>\r\n </h5>\r\n </span>\r\n\r\n <span *ngIf=\"!formField?.option?.protected\">\r\n <div [ngStyle]=\"getFieldInnerLayoutStyle(formField)\">\r\n <label\r\n [ngClass]=\"getStyleWithoutClasses(formField?.label?.style)?.classes\"\r\n [ngStyle]=\"getStyleWithoutClasses(formField?.label?.style)?.style\">\r\n {{\r\n formField?.label?.value\r\n ? formField.label.value\r\n : formField?.label?.caption\r\n ? formField.label.caption\r\n :\r\n form.propertySchema[getScope(formField.scope?.reference)]?.[\r\n formField.scope?.reference.split('/').pop()\r\n ]?.caption\r\n }}\r\n </label>\r\n\r\n <div [ngStyle]=\"\r\n formField?.option?.password\r\n ? {\r\n position: 'relative',\r\n display: 'flex',\r\n alignItems: 'center'\r\n }\r\n : {}\r\n \">\r\n <input [type]=\"\r\n formField?.option?.password\r\n ? !showPassword\r\n ? 'password'\r\n : 'text'\r\n : 'text'\r\n \" #inputField=\"ngModel\" [required]=\"formField?.required\"\r\n [attr.inputmode]=\"\r\n formField?.option?.email\r\n ? 'email'\r\n : formField?.option?.password\r\n ? 'numeric'\r\n : 'text'\r\n \" [pattern]=\"formField?.email ? customEmailPattern : ''\"\r\n [email]=\"formField?.email\"\r\n [minlength]=\"formField?.minlength\"\r\n [maxlength]=\"formField?.maxlength\"\r\n [ngClass]=\"getStyleWithoutClasses(formField?.scope?.style)?.classes\"\r\n [ngStyle]=\"getStyleWithoutClasses(formField?.scope?.style)?.style\"\r\n [(ngModel)]=\"\r\n form.propertySchema[getScope(formField.scope?.reference)][\r\n formField.scope?.reference.split('/').pop()\r\n ].value\r\n \" [name]=\"formField.scope?.reference\" [placeholder]=\"form.propertySchema | vlPlaceholder: formField.scope?.reference\" />\r\n\r\n <i *ngIf=\"formField?.option?.password\" class=\"fa\"\r\n [ngClass]=\"showPassword ? 'fa-eye' : 'fa-eye-slash'\"\r\n (click)=\"togglePasswordVisibility()\"\r\n style=\"position: absolute; right: 10px; cursor: pointer\"></i>\r\n </div>\r\n </div>\r\n\r\n <div *ngIf=\"inputField?.touched && inputField?.invalid\"\r\n [ngClass]=\"getStyleWithoutClasses(formField?.validation?.style)?.classes\"\r\n [ngStyle]=\"getStyleWithoutClasses(formField?.validation?.style)?.style\">\r\n <p [class]=\"\r\n formField?.layout === 'horizontal'\r\n ? 'text-red-400 m-0 horizontal-error'\r\n : 'text-red-400 m-0'\r\n \" *ngIf=\"inputField?.errors\">\r\n {{ setErroMessage(formField, errorMessages, inputField) }}\r\n </p>\r\n </div>\r\n </span>\r\n </span>\r\n\r\n <!-- number control -->\r\n <div *ngSwitchCase=\"'number'\" class=\"form-group\">\r\n <span *ngIf=\"formField?.option?.protected\"\r\n [ngClass]=\"getStyleWithoutClasses(formField?.label?.style)?.classes\"\r\n [ngStyle]=\"getStyleWithoutClasses(formField?.label?.style)?.style\">\r\n <h5>\r\n {{\r\n form.propertySchema[getScope(formField.scope?.reference)]?.[\r\n formField.scope?.reference.split('/').pop()\r\n ]?.caption\r\n }}\r\n\r\n {{\r\n form.propertySchema[getScope(formField.scope?.reference)]?.[\r\n formField.scope?.reference.split('/').pop()\r\n ]?.value\r\n | currency\r\n : formField?.option?.currency\r\n : true\r\n : formField?.option?.decimalPoint\r\n }}\r\n </h5>\r\n </span>\r\n\r\n <span *ngIf=\"!formField?.option?.protected\">\r\n <div [ngStyle]=\"getFieldInnerLayoutStyle(formField)\">\r\n <label\r\n [ngClass]=\"getStyleWithoutClasses(formField?.label?.style)?.classes\"\r\n [ngStyle]=\"getStyleWithoutClasses(formField?.label?.style)?.style\">\r\n {{\r\n formField?.label?.value\r\n ? formField.label.value\r\n :\r\n form.propertySchema[getScope(formField.scope?.reference)]?.[\r\n formField.scope?.reference.split('/').pop()\r\n ]?.caption\r\n }}\r\n </label>\r\n\r\n <input type=\"number\"\r\n [ngClass]=\"getStyleWithoutClasses(formField?.scope?.style)?.classes\"\r\n [ngStyle]=\"getStyleWithoutClasses(formField?.scope?.style)?.style\"\r\n [(ngModel)]=\"\r\n form.propertySchema[getScope(formField.scope?.reference)][\r\n formField.scope?.reference.split('/').pop()\r\n ].value\r\n \" [name]=\"formField.scope?.reference\" [placeholder]=\"form.propertySchema | vlPlaceholder: formField.scope?.reference\" />\r\n </div>\r\n </span>\r\n </div>\r\n\r\n <!-- checkbox control -->\r\n <div *ngSwitchCase=\"'boolean'\" class=\"form-group\"\r\n [ngClass]=\"getStyleWithoutClasses(formField?.scope?.style)?.classes\"\r\n [ngStyle]=\"getStyleWithoutClasses(formField?.scope?.style)?.style\">\r\n <span *ngIf=\"formField?.option?.postfixCaption\">\r\n <label class=\"form-check-label\">\r\n <input type=\"checkbox\" class=\"form-check-input mr-2\"\r\n [(ngModel)]=\"\r\n form.propertySchema[getScope(formField.scope?.reference)][\r\n formField.scope?.reference.split('/').pop()\r\n ].value\r\n \" [name]=\"formField.scope?.reference\"\r\n (ngModelChange)=\"setformData()\" />\r\n\r\n {{\r\n form.propertySchema[getScope(formField.scope?.reference)]?.[\r\n formField.scope?.reference.split('/').pop()\r\n ]?.caption\r\n }}\r\n </label>\r\n </span>\r\n\r\n <div *ngIf=\"!formField?.option?.postfixCaption\"\r\n [ngStyle]=\"getFieldInnerLayoutStyle(formField)\">\r\n <label class=\"form-check-label\">\r\n {{\r\n form.propertySchema[getScope(formField.scope?.reference)]?.[\r\n formField.scope?.reference.split('/').pop()\r\n ]?.caption\r\n }}\r\n\r\n <input type=\"checkbox\" class=\"form-check-input\" [(ngModel)]=\"\r\n form.propertySchema[getScope(formField.scope?.reference)][\r\n formField.scope?.reference.split('/').pop()\r\n ].value\r\n \" [name]=\"formField.scope?.reference\"\r\n (ngModelChange)=\"setformData()\" />\r\n </label>\r\n </div>\r\n </div>\r\n\r\n <!-- DateRange control -->\r\n <div *ngSwitchCase=\"'dateRange'\" class=\"form-group mb-3\">\r\n <span *ngIf=\"formField.option.protected\"\r\n [style]=\"getStyleWithoutClasses(formField?.label?.style).style\"\r\n [class]=\"formField?.label?.style.classes ? formField?.label?.style?.classes[0] : ''\">\r\n <vl-string [formField]=\"formField\" [modalItemInfo]=\"form\">\r\n </vl-string>\r\n </span>\r\n <div *ngIf=\"!formField.option.protected\">\r\n <div [ngStyle]=\"getFieldInnerLayoutStyle(formField)\">\r\n <label\r\n [style]=\"getStyleWithoutClasses(formField?.label?.style).style\"\r\n [class]=\"formField?.label?.style.classes ? formField?.label?.style?.classes[0] : ''\">{{\r\n formField.label?.value\r\n ?\r\n formField.label?.value :\r\n form.propertySchema[getScope(formField.scope?.reference)][formField.scope?.reference.split('/').pop()]?.caption\r\n }}</label>\r\n <nz-range-picker #dateRangeField=\"ngModel\"\r\n [required]=\"formField.option.required\"\r\n [name]=\"formField.scope?.reference\"\r\n [style]=\"getStyleWithoutClasses(formField?.style).style\"\r\n [(ngModel)]=\"form.propertySchema[getScope(formField.scope?.reference)][formField.scope?.reference.split('/').pop()].value\"></nz-range-picker>\r\n </div>\r\n <!-- Error Message -->\r\n <div *ngIf=\"dateRangeField?.touched && dateRangeField?.invalid\"\r\n [style]=\"getStyleWithoutClasses(formField?.validation?.style).style\">\r\n <p class=\"text-danger\"\r\n *ngIf=\"dateRangeField?.errors?.['required']\">\r\n {{formField.label?.value ?\r\n formField.label?.value :\r\n form.propertySchema[getScope(formField.scope?.reference)][formField.scope?.reference.split('/').pop()]?.caption\r\n +\r\n ' ' + errorMessages.required}}</p>\r\n <p class=\"text-danger\"\r\n *ngIf=\"dateRangeField?.errors?.['email']\">\r\n {{(formField.label?.value ?\r\n formField.label?.value :\r\n form.propertySchema[getScope(formField.scope?.reference)][formField.scope?.reference.split('/').pop()]?.caption)\r\n +\r\n ' ' + errorMessages.pattern}}</p>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- Date control -->\r\n <div *ngSwitchCase=\"'date'\" class=\"form-group mb-3\">\r\n <span *ngIf=\"formField.option.protected\"\r\n [style]=\"getStyleWithoutClasses(formField?.label?.style).style\"\r\n [class]=\"formField?.label?.style.classes ? formField?.label?.style?.classes[0] : ''\">\r\n <vl-string [formField]=\"formField\" [modalItemInfo]=\"form\">\r\n </vl-string>\r\n </span>\r\n <div *ngIf=\"!formField.option.protected\">\r\n <div [ngStyle]=\"getFieldInnerLayoutStyle(formField)\">\r\n <label\r\n [style]=\"getStyleWithoutClasses(formField?.label?.style).style\"\r\n [class]=\"formField?.label?.style.classes ? formField?.label?.style?.classes[0] : ''\">{{getLabel(formField)}}</label>\r\n\r\n <span>\r\n <div class=\"picker-field\">\r\n <p-datepicker #datePicker #dateField=\"ngModel\"\r\n styleClass=\"custom-datepicker\"\r\n [required]=\"formField.option.required\"\r\n [name]=\"formField.scope?.reference\"\r\n [disabled]=\"formField?.option?.disabled\"\r\n [autoZIndex]=\"true\" [baseZIndex]=\"10000\"\r\n (ngModelChange)=\"dateChangeEvent(formField, $event)\"\r\n (onInput)=\"onDateTyping($event)\" [dateFormat]=\"\r\n form.propertySchema[\r\n getScope(formField.scope?.reference)\r\n ][\r\n formField.scope?.reference.split('/').pop()\r\n ]?.format || 'yy-mm-dd'\r\n \" [(ngModel)]=\"\r\n form.propertySchema[\r\n getScope(formField.scope?.reference)\r\n ][\r\n formField.scope?.reference.split('/').pop()\r\n ].value\r\n \" [class]=\"formField?.scope?.style?.classes?.[0] || ''\"\r\n [style]=\"getStyleWithoutClasses(formField?.scope?.style).style\"\r\n [showIcon]=\"false\" [showOnFocus]=\"false\" appendTo=\"body\"\r\n [panelStyleClass]=\"picker.datePanelClass\" [motionOptions]=\"picker.dockedMotion\"\r\n [vlCustomKeyboard]=\"formField?.option?.keyboardType ?? 'date'\"\r\n (pointerdown)=\"picker.onFieldPointerDown($event, datePicker)\"\r\n (onFocus)=\"picker.onFieldFocus($event)\"\r\n (onShow)=\"picker.onShown()\"\r\n (onClose)=\"picker.onClose(datePicker)\">\r\n </p-datepicker>\r\n <button type=\"button\" class=\"picker-field__icon\" aria-label=\"Open calendar\"\r\n (pointerdown)=\"picker.openFromIcon($event, datePicker)\"\r\n (click)=\"picker.blockIconClick($event)\">\r\n <i class=\"pi pi-calendar\"></i>\r\n </button>\r\n </div>\r\n <!-- Error Message -->\r\n <div *ngIf=\"dateField?.touched && dateField?.invalid\"\r\n [style]=\"getStyleWithoutClasses(formField?.validation?.style).style\">\r\n <p class=\"text-danger\"\r\n *ngIf=\"dateField?.errors?.['required']\">\r\n {{setErroMessage(formField, errorMessages,\r\n \"required\")}}</p>\r\n <p class=\"text-danger\"\r\n *ngIf=\"dateField?.errors?.['email']\">\r\n {{(formField.label?.value ?\r\n formField.label?.value :\r\n form.propertySchema[getScope(formField.scope?.reference)][formField.scope?.reference.split('/').pop()]?.caption)\r\n +\r\n ' ' + errorMessages.pattern}}</p>\r\n </div>\r\n </span>\r\n\r\n </div>\r\n\r\n </div>\r\n </div>\r\n\r\n <!-- Time control -->\r\n <div *ngSwitchCase=\"'time'\" class=\"form-group mb-3\">\r\n <span *ngIf=\"formField.option.protected\"\r\n [style]=\"getStyleWithoutClasses(formField?.label?.style).style\"\r\n [class]=\"formField?.label?.style.classes ? formField?.label?.style?.classes[0] : ''\">\r\n <vl-string [formField]=\"formField\" [modalItemInfo]=\"form\">\r\n </vl-string>\r\n </span>\r\n <div *ngIf=\"!formField.option.protected\">\r\n <div [ngStyle]=\"getFieldInnerLayoutStyle(formField)\">\r\n <label\r\n [style]=\"getStyleWithoutClasses(formField?.label?.style).style\"\r\n [class]=\"formField?.label?.style.classes ? formField?.label?.style?.classes[0] : ''\">{{getLabel(formField)}}</label>\r\n <span>\r\n <div class=\"picker-field\">\r\n <p-datepicker #timePicker #timeField=\"ngModel\"\r\n styleClass=\"custom-datepicker\"\r\n [required]=\"formField.option.required\"\r\n [name]=\"formField.scope?.reference\" [timeOnly]=\"true\"\r\n hourFormat=\"24\" [disabled]=\"formField?.option?.disabled\" [autoZIndex]=\"true\" [baseZIndex]=\"10000\"\r\n (onInput)=\"onTimeTyping($event)\"\r\n (ngModelChange)=\"timeChangeEvent(formField, $event)\"\r\n [style]=\"getStyleWithoutClasses(formField?.scope?.style).style\"\r\n [(ngModel)]=\"\r\n form.propertySchema[\r\n getScope(formField.scope?.reference)\r\n ][\r\n formField.scope?.reference.split('/').pop()\r\n ].value\r\n \"\r\n [class]=\"formField?.scope?.style?.classes?.[0] || ''\"\r\n [showIcon]=\"false\" [showOnFocus]=\"false\" appendTo=\"body\"\r\n [panelStyleClass]=\"picker.timePanelClass\"\r\n [vlCustomKeyboard]=\"formField?.option?.keyboardType ?? 'time'\"\r\n (pointerdown)=\"picker.onFieldPointerDown($event, timePicker)\"\r\n (onFocus)=\"picker.onFieldFocus($event)\"\r\n (onShow)=\"picker.onShown()\"\r\n (onClose)=\"picker.onClose(timePicker)\">\r\n </p-datepicker>\r\n <button type=\"button\" class=\"picker-field__icon\" aria-label=\"Open time picker\"\r\n (pointerdown)=\"picker.openFromIcon($event, timePicker)\"\r\n (click)=\"picker.blockIconClick($event)\">\r\n <i class=\"pi pi-clock\"></i>\r\n </button>\r\n </div>\r\n\r\n <!-- Error Message -->\r\n <div *ngIf=\"timeField?.touched && timeField?.invalid\"\r\n [style]=\"getStyleWithoutClasses(formField?.validation?.style).style\">\r\n <p class=\"text-danger\"\r\n *ngIf=\"timeField?.errors?.['required']\">\r\n {{setErroMessage(formField, errorMessages,\r\n \"required\")}}</p>\r\n <p class=\"text-danger\"\r\n *ngIf=\"timeField?.errors?.['email']\">\r\n {{(formField.label?.value ?\r\n formField.label?.value :\r\n form.propertySchema[getScope(formField.scope?.reference)][formField.scope?.reference.split('/').pop()]?.caption)\r\n +\r\n ' ' + errorMessages.pattern}}</p>\r\n </div>\r\n </span>\r\n\r\n </div>\r\n\r\n </div>\r\n </div>\r\n\r\n <!-- Autocomplete control -->\r\n <div *ngSwitchCase=\"'autocomplete'\" class=\"form-group mb-3\">\r\n <span *ngIf=\"formField.option.protected\"\r\n [style]=\"getStyleWithoutClasses(formField?.label?.style).style\"\r\n [class]=\"formField?.label?.style.classes ? formField?.label?.style?.classes[0] : ''\">\r\n <vl-string [formField]=\"formField\" [modalItemInfo]=\"form\">\r\n </vl-string>\r\n </span>\r\n <div *ngIf=\"!formField.option.protected\">\r\n <div [ngStyle]=\"getFieldInnerLayoutStyle(formField)\">\r\n <vl-label [formField]=\"formField\" [modalItemInfo]=\"form\">\r\n </vl-label>\r\n\r\n <span>\r\n <p-autocomplete [suggestions]=\"remoteSuggestions[formField.scope?.reference] ?? []\" (completeMethod)=\"completeRemote($event, formField)\" #autocompleteField=\"ngModel\"\r\n [required]=\"formField.option.required\"\r\n [name]=\"formField.scope?.reference\"\r\n styleClass=\"custom-autocomplete\"\r\n [(ngModel)]=\"form.propertySchema[getScope(formField.scope?.reference)][formField.scope?.reference.split('/').pop()].value\"\r\n [style]=\"getStyleWithoutClasses(formField?.scope?.style).style\"\r\n [class]=\"formField?.scope?.style?.classes ? formField?.scope?.style?.classes[0] : ''\" [dropdown]=\"true\"\r\n [optionLabel]=\"formField.option.autocomplete.response.label\"\r\n [placeholder]=\"form.propertySchema | vlPlaceholder: formField.scope?.reference\"\r\n (ngModelChange)=\"autocompFocusOutEvent($event, formField)\"\r\n [vlCustomKeyboard]=\"formField?.option?.keyboardType ?? 'string'\">\r\n </p-autocomplete>\r\n <!-- Error Message -->\r\n <div\r\n *ngIf=\"autocompleteField?.touched && autocompleteField?.invalid\"\r\n [style]=\"getStyleWithoutClasses(formField?.validation?.style).style\">\r\n <p class=\"text-danger\"\r\n *ngIf=\"autocompleteField?.errors?.['required']\">\r\n {{setErroMessage(formField, errorMessages,\r\n \"required\")}}</p>\r\n <p class=\"text-danger\"\r\n *ngIf=\"autocompleteField?.errors?.['email']\">\r\n {{(formField.label?.value ?\r\n formField.label?.value :\r\n form.propertySchema[getScope(formField.scope?.reference)][formField.scope?.reference.split('/').pop()]?.caption)\r\n +\r\n ' ' + errorMessages.pattern}}</p>\r\n </div>\r\n </span>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- dropdown control -->\r\n <div *ngSwitchCase=\"'dropdown'\" class=\"form-group\"\r\n [ngClass]=\"getStyleWithoutClasses(formField?.scope?.style)?.classes\"\r\n [ngStyle]=\"getStyleWithoutClasses(formField?.scope?.style)?.style\">\r\n <span *ngIf=\"formField?.option?.postfixCaption\">\r\n <select id=\"dynamic-dropdown\" #dropdownField=\"ngModel\"\r\n [ngClass]=\"getStyleWithoutClasses(formField?.scope?.style)?.classes\"\r\n [ngStyle]=\"getStyleWithoutClasses(formField?.scope?.style)?.style\"\r\n [name]=\"formField.scope?.reference\"\r\n [(ngModel)]=\"\r\n form.propertySchema[getScope(formField.scope?.reference)][\r\n formField.scope?.reference.split('/').pop()\r\n ].value\r\n \">\r\n <option *ngFor=\"\r\n let item of form.propertySchema[getScope(formField.scope?.reference)]?.[\r\n formField.scope?.reference.split('/').pop()\r\n ]?.data\r\n \" [value]=\"item[formField?.option?.optionValue]\">\r\n {{ item[formField?.option?.optionLabel] }}\r\n </option>\r\n </select>\r\n\r\n <label\r\n [ngClass]=\"getStyleWithoutClasses(formField?.label?.style)?.classes\"\r\n [ngStyle]=\"getStyleWithoutClasses(formField?.label?.style)?.style\">\r\n {{\r\n form.propertySchema[getScope(formField.scope?.reference)]?.[\r\n formField.scope?.reference.split('/').pop()\r\n ]?.caption\r\n }}\r\n </label>\r\n </span>\r\n\r\n <div *ngIf=\"!formField?.option?.postfixCaption\">\r\n <div [ngStyle]=\"getFieldInnerLayoutStyle(formField)\">\r\n <label\r\n [ngClass]=\"getStyleWithoutClasses(formField?.label?.style)?.classes\"\r\n [ngStyle]=\"getStyleWithoutClasses(formField?.label?.style)?.style\">\r\n {{\r\n form.propertySchema[getScope(formField.scope?.reference)]?.[\r\n formField.scope?.reference.split('/').pop()\r\n ]?.caption\r\n }}\r\n </label>\r\n\r\n <nz-select nzShowSearch nzAllowClear nzPlaceHolder=\"Select\"\r\n #dropdownField=\"ngModel\"\r\n [required]=\"formField?.required\"\r\n [ngClass]=\"getStyleWithoutClasses(formField?.scope?.style)?.classes\"\r\n [ngStyle]=\"getStyleWithoutClasses(formField?.scope?.style)?.style\"\r\n [name]=\"formField.scope?.reference\" [(ngModel)]=\"\r\n form.propertySchema[getScope(formField.scope?.reference)][\r\n formField.scope?.reference.split('/').pop()\r\n ].value\r\n \">\r\n <nz-option *ngFor=\"\r\n let item of form.propertySchema[getScope(formField.scope?.reference)]?.[\r\n formField.scope?.reference.split('/').pop()\r\n ]?.data\r\n \" [nzLabel]=\"item[formField?.option?.optionLabel]\"\r\n [nzValue]=\"item[formField?.option?.optionValue]\"></nz-option>\r\n </nz-select>\r\n </div>\r\n\r\n <div *ngIf=\"dropdownField?.touched && dropdownField?.invalid\"\r\n [ngClass]=\"getStyleWithoutClasses(formField?.validation?.style)?.classes\"\r\n [ngStyle]=\"getStyleWithoutClasses(formField?.validation?.style)?.style\">\r\n <p [class]=\"\r\n formField?.layout === 'horizontal'\r\n ? 'text-red-400 m-0 horizontal-error'\r\n : 'text-red-400 m-0'\r\n \" *ngIf=\"dropdownField?.errors\">\r\n {{ setErroMessage(formField, errorMessages, dropdownField)\r\n }}\r\n </p>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- button/default control -->\r\n <div *ngSwitchCase=\"'default'\">\r\n <button type=\"submit\"\r\n [ngClass]=\"getStyleWithoutClasses(formField?.style)?.classes\"\r\n [ngStyle]=\"getStyleWithoutClasses(formField?.style)?.style\"\r\n (click)=\"invokeFormBtnClick(formField?.option, form.propertySchema)\">\r\n {{ formField?.label?.caption }}\r\n </button>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n </form>\r\n</div>\r\n", styles: [":host{display:block;width:100%;height:100%;min-height:0}.form-renderer{width:100%;height:100%;min-height:0;overflow-y:auto;overflow-x:hidden;box-sizing:border-box;padding:12px}.section-card{border:1px solid #e5e7eb;border-radius:var(--radius-sm, 8px);padding:12px;margin-bottom:12px;background:#fff;box-sizing:border-box}.section-header{display:flex;align-items:center;justify-content:space-between;margin-bottom:10px;font-weight:600}.section-title{font-size:14px;color:#0f172a}.section-body{position:relative;width:100%;min-height:78px;box-sizing:border-box}.field-row{position:relative;min-width:0;width:100%;box-sizing:border-box}.field-row input,.field-row select,.field-row nz-select,.field-row textarea,.field-row button{max-width:100%;box-sizing:border-box}@media(max-width:768px){.section-body{grid-template-columns:repeat(1,minmax(0,1fr))!important}.field-row{grid-column:span 1!important}}@media(min-width:769px)and (max-width:1024px){.section-body{grid-template-columns:repeat(6,minmax(0,1fr))!important}.field-row{grid-column:span 6!important}}:host-context(.mobile-frame) .section-body,:host-context(.device-mobile) .section-body{grid-template-columns:repeat(1,minmax(0,1fr))!important}:host-context(.mobile-frame) .field-row,:host-context(.device-mobile) .field-row{grid-column:span 1!important}:host-context(.tablet-frame) .section-body,:host-context(.device-tablet) .section-body{grid-template-columns:repeat(6,minmax(0,1fr))!important}:host-context(.tablet-frame) .field-row,:host-context(.device-tablet) .field-row{grid-column:span 6!important}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i5.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i5.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i5.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i5.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "directive", type: i5.NgSwitch, selector: "[ngSwitch]", inputs: ["ngSwitch"] }, { kind: "directive", type: i5.NgSwitchCase, selector: "[ngSwitchCase]", inputs: ["ngSwitchCase"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i2.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i2.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { kind: "directive", type: i2.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { kind: "directive", type: i2.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i2.MinLengthValidator, selector: "[minlength][formControlName],[minlength][formControl],[minlength][ngModel]", inputs: ["minlength"] }, { kind: "directive", type: i2.MaxLengthValidator, selector: "[maxlength][formControlName],[maxlength][formControl],[maxlength][ngModel]", inputs: ["maxlength"] }, { kind: "directive", type: i2.PatternValidator, selector: "[pattern][formControlName],[pattern][formControl],[pattern][ngModel]", inputs: ["pattern"] }, { kind: "directive", type: i2.EmailValidator, selector: "[email][formControlName],[email][formControl],[email][ngModel]", inputs: ["email"] }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: i2.NgForm, selector: "form:not([ngNoForm]):not([formGroup]):not([formArray]),ng-form,[ngForm]", inputs: ["ngFormOptions"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "ngmodule", type: NzSelectModule }, { kind: "component", type: i3.NzOptionComponent, selector: "nz-option", inputs: ["nzTitle", "nzLabel", "nzValue", "nzKey", "nzDisabled", "nzHide", "nzCustomContent"], exportAs: ["nzOption"] }, { kind: "component", type: i3.NzSelectComponent, selector: "nz-select", inputs: ["nzId", "nzSize", "nzStatus", "nzVariant", "nzOptionHeightPx", "nzOptionOverflowSize", "nzDropdownClassName", "nzDropdownMatchSelectWidth", "nzDropdownStyle", "nzNotFoundContent", "nzPlaceHolder", "nzPlacement", "nzMaxTagCount", "nzDropdownRender", "nzCustomTemplate", "nzPrefix", "nzSuffixIcon", "nzClearIcon", "nzRemoveIcon", "nzMenuItemSelectedIcon", "nzTokenSeparators", "nzMaxTagPlaceholder", "nzMaxMultipleCount", "nzMode", "nzFilterOption", "compareWith", "nzAllowClear", "nzShowSearch", "nzLoading", "nzAutoFocus", "nzAutoClearSearchValue", "nzServerSearch", "nzDisabled", "nzOpen", "nzSelectOnTab", "nzBackdrop", "nzOptions", "nzShowArrow"], outputs: ["nzOnSearch", "nzScrollToBottom", "nzOpenChange", "nzBlur", "nzFocus", "nzOnClear"], exportAs: ["nzSelect"] }, { kind: "component", type: String$1, selector: "vl-string", inputs: ["formField", "modalItemInfo"] }, { kind: "component", type: Label, selector: "vl-label", inputs: ["formField", "modalItemInfo"] }, { kind: "ngmodule", type: NzDatePickerModule }, { kind: "component", type: i4.NzDatePickerComponent, selector: "nz-date-picker,nz-week-picker,nz-month-picker,nz-quarter-picker,nz-year-picker,nz-range-picker", inputs: ["nzInline", "nzAllowClear", "nzAutoFocus", "nzDisabled", "nzInputReadOnly", "nzOpen", "nzDisabledDate", "nzLocale", "nzPlaceHolder", "nzPopupStyle", "nzDropdownClassName", "nzSize", "nzStatus", "nzFormat", "nzVariant", "nzDateRender", "nzDisabledTime", "nzRenderExtraFooter", "nzShowToday", "nzMode", "nzShowNow", "nzRanges", "nzDefaultPickerValue", "nzSeparator", "nzSuffixIcon", "nzBackdrop", "nzId", "nzPlacement", "nzShowWeekNumber", "nzShowTime"], outputs: ["nzOnPanelChange", "nzOnCalendarChange", "nzOnOk", "nzOnOpenChange"], exportAs: ["nzDatePicker"] }, { kind: "directive", type: i4.NzRangePickerComponent, selector: "nz-range-picker", exportAs: ["nzRangePicker"] }, { kind: "ngmodule", type: DatePickerModule }, { kind: "component", type: i12.DatePicker, selector: "p-datePicker, p-datepicker, p-date-picker", inputs: ["iconDisplay", "styleClass", "inputStyle", "inputId", "inputStyleClass", "placeholder", "ariaLabelledBy", "ariaLabel", "iconAriaLabel", "dateFormat", "multipleSeparator", "rangeSeparator", "inline", "showOtherMonths", "selectOtherMonths", "showIcon", "icon", "readonlyInput", "shortYearCutoff", "hourFormat", "timeOnly", "stepHour", "stepMinute", "stepSecond", "showSeconds", "showOnFocus", "showWeek", "startWeekFromFirstDayOfYear", "showClear", "dataType", "selectionMode", "maxDateCount", "showButtonBar", "todayButtonStyleClass", "clearButtonStyleClass", "autofocus", "autoZIndex", "baseZIndex", "panelStyleClass", "panelStyle", "keepInvalid", "hideOnDateTimeSelect", "touchUI", "timeSeparator", "focusTrap", "showTransitionOptions", "hideTransitionOptions", "tabindex", "minDate", "maxDate", "disabledDates", "disabledDays", "showTime", "responsiveOptions", "numberOfMonths", "firstDayOfWeek", "view", "defaultDate", "appendTo", "motionOptions"], outputs: ["onFocus", "onBlur", "onClose", "onSelect", "onClear", "onInput", "onTodayClick", "onClearClick", "onMonthChange", "onYearChange", "onClickOutside", "onShow"] }, { kind: "ngmodule", type: AutoCompleteModule }, { kind: "component", type: i18.AutoComplete, selector: "p-autoComplete, p-autocomplete, p-auto-complete", inputs: ["minLength", "minQueryLength", "delay", "panelStyle", "styleClass", "panelStyleClass", "inputStyle", "inputId", "inputStyleClass", "placeholder", "readonly", "scrollHeight", "lazy", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "autoHighlight", "forceSelection", "type", "autoZIndex", "baseZIndex", "ariaLabel", "dropdownAriaLabel", "ariaLabelledBy", "dropdownIcon", "unique", "group", "completeOnFocus", "showClear", "dropdown", "showEmptyMessage", "dropdownMode", "multiple", "addOnTab", "tabindex", "dataKey", "emptyMessage", "showTransitionOptions", "hideTransitionOptions", "autofocus", "autocomplete", "optionGroupChildren", "optionGroupLabel", "overlayOptions", "suggestions", "optionLabel", "optionValue", "id", "searchMessage", "emptySelectionMessage", "selectionMessage", "autoOptionFocus", "selectOnFocus", "searchLocale", "optionDisabled", "focusOnHover", "typeahead", "addOnBlur", "separator", "appendTo", "motionOptions"], outputs: ["completeMethod", "onSelect", "onUnselect", "onAdd", "onFocus", "onBlur", "onDropdownClick", "onClear", "onInputKeydown", "onKeyUp", "onShow", "onHide", "onLazyLoad"] }, { kind: "ngmodule", type: InputTextModule }, { kind: "directive", type: CustomKeyboardDirective, selector: "[vlCustomKeyboard]", inputs: ["vlCustomKeyboard"] }, { kind: "pipe", type: PlaceholderPipe, name: "vlPlaceholder" }, { kind: "pipe", type: i5.CurrencyPipe, name: "currency" }] });
4904
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.2", type: FormComponent, isStandalone: true, selector: "vl-form", inputs: { errorMessages: "errorMessages", creditCardError: "creditCardError", form: "form", selectedLanguageInfo: "selectedLanguageInfo" }, outputs: { formButtonClick: "formButtonClick", checkBoxChangeEvent: "checkBoxChangeEvent" }, usesOnChanges: true, ngImport: i0, template: "<!-- Faramarz Yousefian and Agent Toni (Claude Opus 5.5) 2026-10-13\r\n - new: autocompletes get their suggestions from RemoteListService (completeRemote) -->\r\n<!-- Faramarz Yousefian and Agent Toni (Claude Opus 5.5) 2026-10-13\r\n - fix: the placeholder comes from vlPlaceholder (pipes/placeholder.pipe.ts) - empty where the\r\n project defines none; it showed the text \"undefined\" -->\r\n<!-- Faramarz Yousefian and Agent Toni (Claude Opus 5) 2026-10-07\r\n - change: autocomplete fields take the toolkit string keyboard unless option.keyboardType\r\n names another one ('native' keeps the system keyboard)\r\n - change: date and time fields use the shared picker markup (picker-field, DateTimePickerService)\r\n instead of PrimeNG's own icon with empty handlers -->\r\n\r\n<!-- Shuaib 2026-09-24\r\n - change: the form field switch uses renderFieldType so legacy checkbox fields render as boolean. -->\r\n\r\n<!-- Faramarz Yousefian and Agent Toni (Claude Opus 5) 2026-09-19\r\n - change: the credit card type is spelled creditCard. The rename of 2026-09-15 reached\r\n model.component.html and the whole Designer but not this file, so one data object rendered\r\n in a modal and stayed empty here\r\n - new: a @contract comment on the type switch and on the credit card case, so the rule sits\r\n next to the code that implements it -->\r\n<div class=\"form-renderer\"\r\n [ngClass]=\"getStyleWithoutClasses(form?.layoutSchema?.style)?.classes\"\r\n [ngStyle]=\"getStyleWithoutClasses(form?.layoutSchema?.style)?.style\">\r\n <form *ngIf=\"form?.layoutSchema?.formSections?.length > 0\">\r\n <div\r\n *ngFor=\"let formSection of form?.layoutSchema?.formSections; let i = index\"\r\n class=\"section-card\">\r\n <div *ngIf=\"formSection?.label?.caption\" class=\"section-header\">\r\n <div class=\"section-title\"\r\n [ngClass]=\"getStyleWithoutClasses(formSection?.label?.style)?.classes\"\r\n [ngStyle]=\"getStyleWithoutClasses(formSection?.label?.style)?.style\">\r\n {{ formSection.label.caption }}\r\n </div>\r\n </div>\r\n\r\n <div *ngIf=\"formSection?.formFields?.length > 0\" class=\"section-body\"\r\n [ngClass]=\"getStyleWithoutClasses(formSection?.style)?.classes\"\r\n [ngStyle]=\"getSectionBodyStyle(formSection)\">\r\n <div *ngFor=\"let formField of formSection.formFields\" class=\"field-row\"\r\n [ngClass]=\"getStyleWithoutClasses(formField?.style)?.classes\"\r\n [ngStyle]=\"getFieldWrapperStyle(formField)\">\r\n <!-- @contract decision: this switch decides whether a field appears at all\r\n reality: renders string, number, image, date, time, dropdown, boolean,\r\n autocomplete, dateRange and the credit card type. Everything else\r\n falls into the default branch and the field renders empty - no error,\r\n nothing in the console either. Existing checkbox fields are normalized\r\n to boolean before this switch; new fields should use boolean.\r\n seen: measured 2026-09-19 with viewdefinition-contract/derive-capabilities.sh\r\n against this file; date, time, dropdown, boolean, autocomplete and\r\n dateRange arrived on 2026-09-18 -->\r\n <div [ngSwitch]=\"renderFieldType(\r\n formField?.scope?.reference &&\r\n form?.propertySchema?.[getScope(formField.scope?.reference)]\r\n ? form.propertySchema[getScope(formField.scope?.reference)]?.[\r\n formField.scope?.reference.split('/').pop()\r\n ]?.type\r\n : 'default'\r\n )\">\r\n <!-- Media control -->\r\n\r\n <div *ngSwitchCase=\"'media'\"\r\n [ngClass]=\"getStyleWithoutClasses(formField?.scope?.style)?.classes\"\r\n [ngStyle]=\"getStyleWithoutClasses(formField?.scope?.style)?.style\">\r\n <ng-container *ngTemplateOutlet=\"formMediaContent; context: { field: formField }\"></ng-container>\r\n </div>\r\n\r\n\r\n <!-- credit card control -->\r\n <!-- @contract decision: the credit card type is spelled creditCard\r\n reality: it was carditCard here until 2026-09-19. The rename of 2026-09-15\r\n reached model.component.html and the whole Designer, but not this\r\n file and not utility.service.ts, so the same data object rendered in\r\n one container and stayed empty in the other. All four places agree now.\r\n failure: a data object still declaring carditCard renders empty everywhere -\r\n that spelling is read nowhere any more.\r\n instead: declare the type as creditCard. -->\r\n <div *ngSwitchCase=\"'creditCard'\"\r\n [ngClass]=\"getStyleWithoutClasses(formField?.scope?.style)?.classes\"\r\n [ngStyle]=\"getStyleWithoutClasses(formField?.scope?.style)?.style\">\r\n <div id=\"card-element\"></div>\r\n <div id=\"card-errors\"\r\n [class]=\"creditCardError?.textContent !== '' ? 'text-red-400 m-0' : ''\"></div>\r\n </div>\r\n\r\n <!-- string control -->\r\n <span *ngSwitchCase=\"'string'\" class=\"form-group\">\r\n <span *ngIf=\"formField?.option?.protected\">\r\n <h5 style=\"display: flex; justify-content: space-between\">\r\n <span\r\n [ngClass]=\"getStyleWithoutClasses(formField?.label?.style)?.classes\"\r\n [ngStyle]=\"getStyleWithoutClasses(formField?.label?.style)?.style\">\r\n {{\r\n form.propertySchema[getScope(formField.scope?.reference)]?.[\r\n formField.scope?.reference.split('/').pop()\r\n ]?.caption\r\n }}\r\n </span>\r\n\r\n <span>\r\n {{\r\n form.propertySchema[getScope(formField.scope?.reference)]?.[\r\n formField.scope?.reference.split('/').pop()\r\n ]?.value\r\n }}\r\n </span>\r\n </h5>\r\n </span>\r\n\r\n <span *ngIf=\"!formField?.option?.protected\">\r\n <div [ngStyle]=\"getFieldInnerLayoutStyle(formField)\">\r\n <label\r\n [ngClass]=\"getStyleWithoutClasses(formField?.label?.style)?.classes\"\r\n [ngStyle]=\"getStyleWithoutClasses(formField?.label?.style)?.style\">\r\n {{\r\n formField?.label?.value\r\n ? formField.label.value\r\n : formField?.label?.caption\r\n ? formField.label.caption\r\n :\r\n form.propertySchema[getScope(formField.scope?.reference)]?.[\r\n formField.scope?.reference.split('/').pop()\r\n ]?.caption\r\n }}\r\n </label>\r\n\r\n <div [ngStyle]=\"\r\n formField?.option?.password\r\n ? {\r\n position: 'relative',\r\n display: 'flex',\r\n alignItems: 'center'\r\n }\r\n : {}\r\n \">\r\n <input [type]=\"\r\n formField?.option?.password\r\n ? !showPassword\r\n ? 'password'\r\n : 'text'\r\n : 'text'\r\n \" #inputField=\"ngModel\" [required]=\"formField?.required\"\r\n [attr.inputmode]=\"\r\n formField?.option?.email\r\n ? 'email'\r\n : formField?.option?.password\r\n ? 'numeric'\r\n : 'text'\r\n \" [pattern]=\"formField?.email ? customEmailPattern : ''\"\r\n [email]=\"formField?.email\"\r\n [minlength]=\"formField?.minlength\"\r\n [maxlength]=\"formField?.maxlength\"\r\n [ngClass]=\"getStyleWithoutClasses(formField?.scope?.style)?.classes\"\r\n [ngStyle]=\"getStyleWithoutClasses(formField?.scope?.style)?.style\"\r\n [(ngModel)]=\"\r\n form.propertySchema[getScope(formField.scope?.reference)][\r\n formField.scope?.reference.split('/').pop()\r\n ].value\r\n \" [name]=\"formField.scope?.reference\" [placeholder]=\"form.propertySchema | vlPlaceholder: formField.scope?.reference\" />\r\n\r\n <i *ngIf=\"formField?.option?.password\" class=\"fa\"\r\n [ngClass]=\"showPassword ? 'fa-eye' : 'fa-eye-slash'\"\r\n (click)=\"togglePasswordVisibility()\"\r\n style=\"position: absolute; right: 10px; cursor: pointer\"></i>\r\n </div>\r\n </div>\r\n\r\n <div *ngIf=\"inputField?.touched && inputField?.invalid\"\r\n [ngClass]=\"getStyleWithoutClasses(formField?.validation?.style)?.classes\"\r\n [ngStyle]=\"getStyleWithoutClasses(formField?.validation?.style)?.style\">\r\n <p [class]=\"\r\n formField?.layout === 'horizontal'\r\n ? 'text-red-400 m-0 horizontal-error'\r\n : 'text-red-400 m-0'\r\n \" *ngIf=\"inputField?.errors\">\r\n {{ setErroMessage(formField, errorMessages, inputField) }}\r\n </p>\r\n </div>\r\n </span>\r\n </span>\r\n\r\n <!-- number control -->\r\n <div *ngSwitchCase=\"'number'\" class=\"form-group\">\r\n <span *ngIf=\"formField?.option?.protected\"\r\n [ngClass]=\"getStyleWithoutClasses(formField?.label?.style)?.classes\"\r\n [ngStyle]=\"getStyleWithoutClasses(formField?.label?.style)?.style\">\r\n <h5>\r\n {{\r\n form.propertySchema[getScope(formField.scope?.reference)]?.[\r\n formField.scope?.reference.split('/').pop()\r\n ]?.caption\r\n }}\r\n\r\n {{\r\n form.propertySchema[getScope(formField.scope?.reference)]?.[\r\n formField.scope?.reference.split('/').pop()\r\n ]?.value\r\n | currency\r\n : formField?.option?.currency\r\n : true\r\n : formField?.option?.decimalPoint\r\n }}\r\n </h5>\r\n </span>\r\n\r\n <span *ngIf=\"!formField?.option?.protected\">\r\n <div [ngStyle]=\"getFieldInnerLayoutStyle(formField)\">\r\n <label\r\n [ngClass]=\"getStyleWithoutClasses(formField?.label?.style)?.classes\"\r\n [ngStyle]=\"getStyleWithoutClasses(formField?.label?.style)?.style\">\r\n {{\r\n formField?.label?.value\r\n ? formField.label.value\r\n :\r\n form.propertySchema[getScope(formField.scope?.reference)]?.[\r\n formField.scope?.reference.split('/').pop()\r\n ]?.caption\r\n }}\r\n </label>\r\n\r\n <input type=\"number\"\r\n [ngClass]=\"getStyleWithoutClasses(formField?.scope?.style)?.classes\"\r\n [ngStyle]=\"getStyleWithoutClasses(formField?.scope?.style)?.style\"\r\n [(ngModel)]=\"\r\n form.propertySchema[getScope(formField.scope?.reference)][\r\n formField.scope?.reference.split('/').pop()\r\n ].value\r\n \" [name]=\"formField.scope?.reference\" [placeholder]=\"form.propertySchema | vlPlaceholder: formField.scope?.reference\" />\r\n </div>\r\n </span>\r\n </div>\r\n\r\n <!-- checkbox control -->\r\n <div *ngSwitchCase=\"'boolean'\" class=\"form-group\"\r\n [ngClass]=\"getStyleWithoutClasses(formField?.scope?.style)?.classes\"\r\n [ngStyle]=\"getStyleWithoutClasses(formField?.scope?.style)?.style\">\r\n <span *ngIf=\"formField?.option?.postfixCaption\">\r\n <label class=\"form-check-label\">\r\n <input type=\"checkbox\" class=\"form-check-input mr-2\"\r\n [(ngModel)]=\"\r\n form.propertySchema[getScope(formField.scope?.reference)][\r\n formField.scope?.reference.split('/').pop()\r\n ].value\r\n \" [name]=\"formField.scope?.reference\"\r\n (ngModelChange)=\"setformData()\" />\r\n\r\n {{\r\n form.propertySchema[getScope(formField.scope?.reference)]?.[\r\n formField.scope?.reference.split('/').pop()\r\n ]?.caption\r\n }}\r\n </label>\r\n </span>\r\n\r\n <div *ngIf=\"!formField?.option?.postfixCaption\"\r\n [ngStyle]=\"getFieldInnerLayoutStyle(formField)\">\r\n <label class=\"form-check-label\">\r\n {{\r\n form.propertySchema[getScope(formField.scope?.reference)]?.[\r\n formField.scope?.reference.split('/').pop()\r\n ]?.caption\r\n }}\r\n\r\n <input type=\"checkbox\" class=\"form-check-input\" [(ngModel)]=\"\r\n form.propertySchema[getScope(formField.scope?.reference)][\r\n formField.scope?.reference.split('/').pop()\r\n ].value\r\n \" [name]=\"formField.scope?.reference\"\r\n (ngModelChange)=\"setformData()\" />\r\n </label>\r\n </div>\r\n </div>\r\n\r\n <!-- DateRange control -->\r\n <div *ngSwitchCase=\"'dateRange'\" class=\"form-group mb-3\">\r\n <span *ngIf=\"formField.option.protected\"\r\n [style]=\"getStyleWithoutClasses(formField?.label?.style).style\"\r\n [class]=\"formField?.label?.style.classes ? formField?.label?.style?.classes[0] : ''\">\r\n <vl-string [formField]=\"formField\" [modalItemInfo]=\"form\">\r\n </vl-string>\r\n </span>\r\n <div *ngIf=\"!formField.option.protected\">\r\n <div [ngStyle]=\"getFieldInnerLayoutStyle(formField)\">\r\n <label\r\n [style]=\"getStyleWithoutClasses(formField?.label?.style).style\"\r\n [class]=\"formField?.label?.style.classes ? formField?.label?.style?.classes[0] : ''\">{{\r\n formField.label?.value\r\n ?\r\n formField.label?.value :\r\n form.propertySchema[getScope(formField.scope?.reference)][formField.scope?.reference.split('/').pop()]?.caption\r\n }}</label>\r\n <nz-range-picker #dateRangeField=\"ngModel\"\r\n [required]=\"formField.option.required\"\r\n [name]=\"formField.scope?.reference\"\r\n [style]=\"getStyleWithoutClasses(formField?.style).style\"\r\n [(ngModel)]=\"form.propertySchema[getScope(formField.scope?.reference)][formField.scope?.reference.split('/').pop()].value\"></nz-range-picker>\r\n </div>\r\n <!-- Error Message -->\r\n <div *ngIf=\"dateRangeField?.touched && dateRangeField?.invalid\"\r\n [style]=\"getStyleWithoutClasses(formField?.validation?.style).style\">\r\n <p class=\"text-danger\"\r\n *ngIf=\"dateRangeField?.errors?.['required']\">\r\n {{formField.label?.value ?\r\n formField.label?.value :\r\n form.propertySchema[getScope(formField.scope?.reference)][formField.scope?.reference.split('/').pop()]?.caption\r\n +\r\n ' ' + errorMessages.required}}</p>\r\n <p class=\"text-danger\"\r\n *ngIf=\"dateRangeField?.errors?.['email']\">\r\n {{(formField.label?.value ?\r\n formField.label?.value :\r\n form.propertySchema[getScope(formField.scope?.reference)][formField.scope?.reference.split('/').pop()]?.caption)\r\n +\r\n ' ' + errorMessages.pattern}}</p>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- Date control -->\r\n <div *ngSwitchCase=\"'date'\" class=\"form-group mb-3\">\r\n <span *ngIf=\"formField.option.protected\"\r\n [style]=\"getStyleWithoutClasses(formField?.label?.style).style\"\r\n [class]=\"formField?.label?.style.classes ? formField?.label?.style?.classes[0] : ''\">\r\n <vl-string [formField]=\"formField\" [modalItemInfo]=\"form\">\r\n </vl-string>\r\n </span>\r\n <div *ngIf=\"!formField.option.protected\">\r\n <div [ngStyle]=\"getFieldInnerLayoutStyle(formField)\">\r\n <label\r\n [style]=\"getStyleWithoutClasses(formField?.label?.style).style\"\r\n [class]=\"formField?.label?.style.classes ? formField?.label?.style?.classes[0] : ''\">{{getLabel(formField)}}</label>\r\n\r\n <span>\r\n <div class=\"picker-field\">\r\n <p-datepicker #datePicker #dateField=\"ngModel\"\r\n styleClass=\"custom-datepicker\"\r\n [required]=\"formField.option.required\"\r\n [name]=\"formField.scope?.reference\"\r\n [disabled]=\"formField?.option?.disabled\"\r\n [autoZIndex]=\"true\" [baseZIndex]=\"10000\"\r\n (ngModelChange)=\"dateChangeEvent(formField, $event)\"\r\n (onInput)=\"onDateTyping($event)\" [dateFormat]=\"\r\n form.propertySchema[\r\n getScope(formField.scope?.reference)\r\n ][\r\n formField.scope?.reference.split('/').pop()\r\n ]?.format || 'yy-mm-dd'\r\n \" [(ngModel)]=\"\r\n form.propertySchema[\r\n getScope(formField.scope?.reference)\r\n ][\r\n formField.scope?.reference.split('/').pop()\r\n ].value\r\n \" [class]=\"formField?.scope?.style?.classes?.[0] || ''\"\r\n [style]=\"getStyleWithoutClasses(formField?.scope?.style).style\"\r\n [showIcon]=\"false\" [showOnFocus]=\"false\" appendTo=\"body\"\r\n [panelStyleClass]=\"picker.datePanelClass\" [motionOptions]=\"picker.dockedMotion\"\r\n [vlCustomKeyboard]=\"formField?.option?.keyboardType ?? 'date'\"\r\n (pointerdown)=\"picker.onFieldPointerDown($event, datePicker)\"\r\n (onFocus)=\"picker.onFieldFocus($event)\"\r\n (onShow)=\"picker.onShown()\"\r\n (onClose)=\"picker.onClose(datePicker)\">\r\n </p-datepicker>\r\n <button type=\"button\" class=\"picker-field__icon\" aria-label=\"Open calendar\"\r\n (pointerdown)=\"picker.openFromIcon($event, datePicker)\"\r\n (click)=\"picker.blockIconClick($event)\">\r\n <i class=\"pi pi-calendar\"></i>\r\n </button>\r\n </div>\r\n <!-- Error Message -->\r\n <div *ngIf=\"dateField?.touched && dateField?.invalid\"\r\n [style]=\"getStyleWithoutClasses(formField?.validation?.style).style\">\r\n <p class=\"text-danger\"\r\n *ngIf=\"dateField?.errors?.['required']\">\r\n {{setErroMessage(formField, errorMessages,\r\n \"required\")}}</p>\r\n <p class=\"text-danger\"\r\n *ngIf=\"dateField?.errors?.['email']\">\r\n {{(formField.label?.value ?\r\n formField.label?.value :\r\n form.propertySchema[getScope(formField.scope?.reference)][formField.scope?.reference.split('/').pop()]?.caption)\r\n +\r\n ' ' + errorMessages.pattern}}</p>\r\n </div>\r\n </span>\r\n\r\n </div>\r\n\r\n </div>\r\n </div>\r\n\r\n <!-- Time control -->\r\n <div *ngSwitchCase=\"'time'\" class=\"form-group mb-3\">\r\n <span *ngIf=\"formField.option.protected\"\r\n [style]=\"getStyleWithoutClasses(formField?.label?.style).style\"\r\n [class]=\"formField?.label?.style.classes ? formField?.label?.style?.classes[0] : ''\">\r\n <vl-string [formField]=\"formField\" [modalItemInfo]=\"form\">\r\n </vl-string>\r\n </span>\r\n <div *ngIf=\"!formField.option.protected\">\r\n <div [ngStyle]=\"getFieldInnerLayoutStyle(formField)\">\r\n <label\r\n [style]=\"getStyleWithoutClasses(formField?.label?.style).style\"\r\n [class]=\"formField?.label?.style.classes ? formField?.label?.style?.classes[0] : ''\">{{getLabel(formField)}}</label>\r\n <span>\r\n <div class=\"picker-field\">\r\n <p-datepicker #timePicker #timeField=\"ngModel\"\r\n styleClass=\"custom-datepicker\"\r\n [required]=\"formField.option.required\"\r\n [name]=\"formField.scope?.reference\" [timeOnly]=\"true\"\r\n hourFormat=\"24\" [disabled]=\"formField?.option?.disabled\" [autoZIndex]=\"true\" [baseZIndex]=\"10000\"\r\n (onInput)=\"onTimeTyping($event)\"\r\n (ngModelChange)=\"timeChangeEvent(formField, $event)\"\r\n [style]=\"getStyleWithoutClasses(formField?.scope?.style).style\"\r\n [(ngModel)]=\"\r\n form.propertySchema[\r\n getScope(formField.scope?.reference)\r\n ][\r\n formField.scope?.reference.split('/').pop()\r\n ].value\r\n \"\r\n [class]=\"formField?.scope?.style?.classes?.[0] || ''\"\r\n [showIcon]=\"false\" [showOnFocus]=\"false\" appendTo=\"body\"\r\n [panelStyleClass]=\"picker.timePanelClass\"\r\n [vlCustomKeyboard]=\"formField?.option?.keyboardType ?? 'time'\"\r\n (pointerdown)=\"picker.onFieldPointerDown($event, timePicker)\"\r\n (onFocus)=\"picker.onFieldFocus($event)\"\r\n (onShow)=\"picker.onShown()\"\r\n (onClose)=\"picker.onClose(timePicker)\">\r\n </p-datepicker>\r\n <button type=\"button\" class=\"picker-field__icon\" aria-label=\"Open time picker\"\r\n (pointerdown)=\"picker.openFromIcon($event, timePicker)\"\r\n (click)=\"picker.blockIconClick($event)\">\r\n <i class=\"pi pi-clock\"></i>\r\n </button>\r\n </div>\r\n\r\n <!-- Error Message -->\r\n <div *ngIf=\"timeField?.touched && timeField?.invalid\"\r\n [style]=\"getStyleWithoutClasses(formField?.validation?.style).style\">\r\n <p class=\"text-danger\"\r\n *ngIf=\"timeField?.errors?.['required']\">\r\n {{setErroMessage(formField, errorMessages,\r\n \"required\")}}</p>\r\n <p class=\"text-danger\"\r\n *ngIf=\"timeField?.errors?.['email']\">\r\n {{(formField.label?.value ?\r\n formField.label?.value :\r\n form.propertySchema[getScope(formField.scope?.reference)][formField.scope?.reference.split('/').pop()]?.caption)\r\n +\r\n ' ' + errorMessages.pattern}}</p>\r\n </div>\r\n </span>\r\n\r\n </div>\r\n\r\n </div>\r\n </div>\r\n\r\n <!-- Autocomplete control -->\r\n <div *ngSwitchCase=\"'autocomplete'\" class=\"form-group mb-3\">\r\n <span *ngIf=\"formField.option.protected\"\r\n [style]=\"getStyleWithoutClasses(formField?.label?.style).style\"\r\n [class]=\"formField?.label?.style.classes ? formField?.label?.style?.classes[0] : ''\">\r\n <vl-string [formField]=\"formField\" [modalItemInfo]=\"form\">\r\n </vl-string>\r\n </span>\r\n <div *ngIf=\"!formField.option.protected\">\r\n <div [ngStyle]=\"getFieldInnerLayoutStyle(formField)\">\r\n <vl-label [formField]=\"formField\" [modalItemInfo]=\"form\">\r\n </vl-label>\r\n\r\n <span>\r\n <p-autocomplete [suggestions]=\"remoteSuggestions[formField.scope?.reference] ?? []\" (completeMethod)=\"completeRemote($event, formField)\" #autocompleteField=\"ngModel\"\r\n [required]=\"formField.option.required\"\r\n [name]=\"formField.scope?.reference\"\r\n styleClass=\"custom-autocomplete\"\r\n [(ngModel)]=\"form.propertySchema[getScope(formField.scope?.reference)][formField.scope?.reference.split('/').pop()].value\"\r\n [style]=\"getStyleWithoutClasses(formField?.scope?.style).style\"\r\n [class]=\"formField?.scope?.style?.classes ? formField?.scope?.style?.classes[0] : ''\" [dropdown]=\"true\"\r\n [optionLabel]=\"formField.option.autocomplete.response.label\"\r\n [placeholder]=\"form.propertySchema | vlPlaceholder: formField.scope?.reference\"\r\n (ngModelChange)=\"autocompFocusOutEvent($event, formField)\"\r\n [vlCustomKeyboard]=\"formField?.option?.keyboardType ?? 'string'\">\r\n </p-autocomplete>\r\n <!-- Error Message -->\r\n <div\r\n *ngIf=\"autocompleteField?.touched && autocompleteField?.invalid\"\r\n [style]=\"getStyleWithoutClasses(formField?.validation?.style).style\">\r\n <p class=\"text-danger\"\r\n *ngIf=\"autocompleteField?.errors?.['required']\">\r\n {{setErroMessage(formField, errorMessages,\r\n \"required\")}}</p>\r\n <p class=\"text-danger\"\r\n *ngIf=\"autocompleteField?.errors?.['email']\">\r\n {{(formField.label?.value ?\r\n formField.label?.value :\r\n form.propertySchema[getScope(formField.scope?.reference)][formField.scope?.reference.split('/').pop()]?.caption)\r\n +\r\n ' ' + errorMessages.pattern}}</p>\r\n </div>\r\n </span>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- dropdown control -->\r\n <div *ngSwitchCase=\"'dropdown'\" class=\"form-group\"\r\n [ngClass]=\"getStyleWithoutClasses(formField?.scope?.style)?.classes\"\r\n [ngStyle]=\"getStyleWithoutClasses(formField?.scope?.style)?.style\">\r\n <span *ngIf=\"formField?.option?.postfixCaption\">\r\n <select id=\"dynamic-dropdown\" #dropdownField=\"ngModel\"\r\n [ngClass]=\"getStyleWithoutClasses(formField?.scope?.style)?.classes\"\r\n [ngStyle]=\"getStyleWithoutClasses(formField?.scope?.style)?.style\"\r\n [name]=\"formField.scope?.reference\"\r\n [(ngModel)]=\"\r\n form.propertySchema[getScope(formField.scope?.reference)][\r\n formField.scope?.reference.split('/').pop()\r\n ].value\r\n \">\r\n <option *ngFor=\"\r\n let item of form.propertySchema[getScope(formField.scope?.reference)]?.[\r\n formField.scope?.reference.split('/').pop()\r\n ]?.data\r\n \" [value]=\"item[formField?.option?.optionValue]\">\r\n {{ item[formField?.option?.optionLabel] }}\r\n </option>\r\n </select>\r\n\r\n <label\r\n [ngClass]=\"getStyleWithoutClasses(formField?.label?.style)?.classes\"\r\n [ngStyle]=\"getStyleWithoutClasses(formField?.label?.style)?.style\">\r\n {{\r\n form.propertySchema[getScope(formField.scope?.reference)]?.[\r\n formField.scope?.reference.split('/').pop()\r\n ]?.caption\r\n }}\r\n </label>\r\n </span>\r\n\r\n <div *ngIf=\"!formField?.option?.postfixCaption\">\r\n <div [ngStyle]=\"getFieldInnerLayoutStyle(formField)\">\r\n <label\r\n [ngClass]=\"getStyleWithoutClasses(formField?.label?.style)?.classes\"\r\n [ngStyle]=\"getStyleWithoutClasses(formField?.label?.style)?.style\">\r\n {{\r\n form.propertySchema[getScope(formField.scope?.reference)]?.[\r\n formField.scope?.reference.split('/').pop()\r\n ]?.caption\r\n }}\r\n </label>\r\n\r\n <nz-select nzShowSearch nzAllowClear nzPlaceHolder=\"Select\"\r\n #dropdownField=\"ngModel\"\r\n [required]=\"formField?.required\"\r\n [ngClass]=\"getStyleWithoutClasses(formField?.scope?.style)?.classes\"\r\n [ngStyle]=\"getStyleWithoutClasses(formField?.scope?.style)?.style\"\r\n [name]=\"formField.scope?.reference\" [(ngModel)]=\"\r\n form.propertySchema[getScope(formField.scope?.reference)][\r\n formField.scope?.reference.split('/').pop()\r\n ].value\r\n \">\r\n <nz-option *ngFor=\"\r\n let item of form.propertySchema[getScope(formField.scope?.reference)]?.[\r\n formField.scope?.reference.split('/').pop()\r\n ]?.data\r\n \" [nzLabel]=\"item[formField?.option?.optionLabel]\"\r\n [nzValue]=\"item[formField?.option?.optionValue]\"></nz-option>\r\n </nz-select>\r\n </div>\r\n\r\n <div *ngIf=\"dropdownField?.touched && dropdownField?.invalid\"\r\n [ngClass]=\"getStyleWithoutClasses(formField?.validation?.style)?.classes\"\r\n [ngStyle]=\"getStyleWithoutClasses(formField?.validation?.style)?.style\">\r\n <p [class]=\"\r\n formField?.layout === 'horizontal'\r\n ? 'text-red-400 m-0 horizontal-error'\r\n : 'text-red-400 m-0'\r\n \" *ngIf=\"dropdownField?.errors\">\r\n {{ setErroMessage(formField, errorMessages, dropdownField)\r\n }}\r\n </p>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- button/default control -->\r\n <div *ngSwitchCase=\"'default'\">\r\n <button type=\"submit\"\r\n [ngClass]=\"getStyleWithoutClasses(formField?.style)?.classes\"\r\n [ngStyle]=\"getStyleWithoutClasses(formField?.style)?.style\"\r\n (click)=\"invokeFormBtnClick(formField?.option, form.propertySchema)\">\r\n {{ formField?.label?.caption }}\r\n </button>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n </form>\r\n</div>\r\n\r\n<ng-template #formMediaContent let-field=\"field\">\r\n <ng-container *ngIf=\"getMediaSource(field) as source\">\r\n <ng-container [ngSwitch]=\"getMediaKind(field)\">\r\n <img *ngSwitchDefault [src]=\"source\" [alt]=\"getMediaLabel(field)\" loading=\"lazy\" />\r\n <video *ngSwitchCase=\"'video'\" [src]=\"source\"\r\n [attr.aria-label]=\"getMediaLabel(field)\" controls playsinline preload=\"metadata\">\r\n Your browser does not support video playback.\r\n </video>\r\n <audio *ngSwitchCase=\"'audio'\" [src]=\"source\"\r\n [attr.aria-label]=\"getMediaLabel(field)\" controls preload=\"metadata\">\r\n Your browser does not support audio playback.\r\n </audio>\r\n <a *ngSwitchCase=\"'pdf'\" [href]=\"source\" target=\"_blank\" rel=\"noopener noreferrer\">\r\n Open PDF \u2014 {{ getMediaLabel(field) }}\r\n </a>\r\n <a *ngSwitchCase=\"'file'\" [href]=\"source\" target=\"_blank\" rel=\"noopener noreferrer\">\r\n Open file \u2014 {{ getMediaLabel(field) }}\r\n </a>\r\n </ng-container>\r\n </ng-container>\r\n</ng-template>\r\n\r\n", styles: [":host{display:block;width:100%;height:100%;min-height:0}.form-renderer{width:100%;height:100%;min-height:0;overflow-y:auto;overflow-x:hidden;box-sizing:border-box;padding:12px}.section-card{border:1px solid #e5e7eb;border-radius:var(--radius-sm, 8px);padding:12px;margin-bottom:12px;background:#fff;box-sizing:border-box}.section-header{display:flex;align-items:center;justify-content:space-between;margin-bottom:10px;font-weight:600}.section-title{font-size:14px;color:#0f172a}.section-body{position:relative;width:100%;min-height:78px;box-sizing:border-box}.field-row{position:relative;min-width:0;width:100%;box-sizing:border-box}.field-row input,.field-row select,.field-row nz-select,.field-row textarea,.field-row button{max-width:100%;box-sizing:border-box}@media(max-width:768px){.section-body{grid-template-columns:repeat(1,minmax(0,1fr))!important}.field-row{grid-column:span 1!important}}@media(min-width:769px)and (max-width:1024px){.section-body{grid-template-columns:repeat(6,minmax(0,1fr))!important}.field-row{grid-column:span 6!important}}:host-context(.mobile-frame) .section-body,:host-context(.device-mobile) .section-body{grid-template-columns:repeat(1,minmax(0,1fr))!important}:host-context(.mobile-frame) .field-row,:host-context(.device-mobile) .field-row{grid-column:span 1!important}:host-context(.tablet-frame) .section-body,:host-context(.device-tablet) .section-body{grid-template-columns:repeat(6,minmax(0,1fr))!important}:host-context(.tablet-frame) .field-row,:host-context(.device-tablet) .field-row{grid-column:span 6!important}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i9.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i9.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i9.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i9.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: i9.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "directive", type: i9.NgSwitch, selector: "[ngSwitch]", inputs: ["ngSwitch"] }, { kind: "directive", type: i9.NgSwitchCase, selector: "[ngSwitchCase]", inputs: ["ngSwitchCase"] }, { kind: "directive", type: i9.NgSwitchDefault, selector: "[ngSwitchDefault]" }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i2.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i2.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { kind: "directive", type: i2.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { kind: "directive", type: i2.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i2.MinLengthValidator, selector: "[minlength][formControlName],[minlength][formControl],[minlength][ngModel]", inputs: ["minlength"] }, { kind: "directive", type: i2.MaxLengthValidator, selector: "[maxlength][formControlName],[maxlength][formControl],[maxlength][ngModel]", inputs: ["maxlength"] }, { kind: "directive", type: i2.PatternValidator, selector: "[pattern][formControlName],[pattern][formControl],[pattern][ngModel]", inputs: ["pattern"] }, { kind: "directive", type: i2.EmailValidator, selector: "[email][formControlName],[email][formControl],[email][ngModel]", inputs: ["email"] }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: i2.NgForm, selector: "form:not([ngNoForm]):not([formGroup]):not([formArray]),ng-form,[ngForm]", inputs: ["ngFormOptions"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "ngmodule", type: NzSelectModule }, { kind: "component", type: i3.NzOptionComponent, selector: "nz-option", inputs: ["nzTitle", "nzLabel", "nzValue", "nzKey", "nzDisabled", "nzHide", "nzCustomContent"], exportAs: ["nzOption"] }, { kind: "component", type: i3.NzSelectComponent, selector: "nz-select", inputs: ["nzId", "nzSize", "nzStatus", "nzVariant", "nzOptionHeightPx", "nzOptionOverflowSize", "nzDropdownClassName", "nzDropdownMatchSelectWidth", "nzDropdownStyle", "nzNotFoundContent", "nzPlaceHolder", "nzPlacement", "nzMaxTagCount", "nzDropdownRender", "nzCustomTemplate", "nzPrefix", "nzSuffixIcon", "nzClearIcon", "nzRemoveIcon", "nzMenuItemSelectedIcon", "nzTokenSeparators", "nzMaxTagPlaceholder", "nzMaxMultipleCount", "nzMode", "nzFilterOption", "compareWith", "nzAllowClear", "nzShowSearch", "nzLoading", "nzAutoFocus", "nzAutoClearSearchValue", "nzServerSearch", "nzDisabled", "nzOpen", "nzSelectOnTab", "nzBackdrop", "nzOptions", "nzShowArrow"], outputs: ["nzOnSearch", "nzScrollToBottom", "nzOpenChange", "nzBlur", "nzFocus", "nzOnClear"], exportAs: ["nzSelect"] }, { kind: "component", type: String$1, selector: "vl-string", inputs: ["formField", "modalItemInfo"] }, { kind: "component", type: Label, selector: "vl-label", inputs: ["formField", "modalItemInfo"] }, { kind: "ngmodule", type: NzDatePickerModule }, { kind: "component", type: i4.NzDatePickerComponent, selector: "nz-date-picker,nz-week-picker,nz-month-picker,nz-quarter-picker,nz-year-picker,nz-range-picker", inputs: ["nzInline", "nzAllowClear", "nzAutoFocus", "nzDisabled", "nzInputReadOnly", "nzOpen", "nzDisabledDate", "nzLocale", "nzPlaceHolder", "nzPopupStyle", "nzDropdownClassName", "nzSize", "nzStatus", "nzFormat", "nzVariant", "nzDateRender", "nzDisabledTime", "nzRenderExtraFooter", "nzShowToday", "nzMode", "nzShowNow", "nzRanges", "nzDefaultPickerValue", "nzSeparator", "nzSuffixIcon", "nzBackdrop", "nzId", "nzPlacement", "nzShowWeekNumber", "nzShowTime"], outputs: ["nzOnPanelChange", "nzOnCalendarChange", "nzOnOk", "nzOnOpenChange"], exportAs: ["nzDatePicker"] }, { kind: "directive", type: i4.NzRangePickerComponent, selector: "nz-range-picker", exportAs: ["nzRangePicker"] }, { kind: "ngmodule", type: DatePickerModule }, { kind: "component", type: i12.DatePicker, selector: "p-datePicker, p-datepicker, p-date-picker", inputs: ["iconDisplay", "styleClass", "inputStyle", "inputId", "inputStyleClass", "placeholder", "ariaLabelledBy", "ariaLabel", "iconAriaLabel", "dateFormat", "multipleSeparator", "rangeSeparator", "inline", "showOtherMonths", "selectOtherMonths", "showIcon", "icon", "readonlyInput", "shortYearCutoff", "hourFormat", "timeOnly", "stepHour", "stepMinute", "stepSecond", "showSeconds", "showOnFocus", "showWeek", "startWeekFromFirstDayOfYear", "showClear", "dataType", "selectionMode", "maxDateCount", "showButtonBar", "todayButtonStyleClass", "clearButtonStyleClass", "autofocus", "autoZIndex", "baseZIndex", "panelStyleClass", "panelStyle", "keepInvalid", "hideOnDateTimeSelect", "touchUI", "timeSeparator", "focusTrap", "showTransitionOptions", "hideTransitionOptions", "tabindex", "minDate", "maxDate", "disabledDates", "disabledDays", "showTime", "responsiveOptions", "numberOfMonths", "firstDayOfWeek", "view", "defaultDate", "appendTo", "motionOptions"], outputs: ["onFocus", "onBlur", "onClose", "onSelect", "onClear", "onInput", "onTodayClick", "onClearClick", "onMonthChange", "onYearChange", "onClickOutside", "onShow"] }, { kind: "ngmodule", type: AutoCompleteModule }, { kind: "component", type: i18.AutoComplete, selector: "p-autoComplete, p-autocomplete, p-auto-complete", inputs: ["minLength", "minQueryLength", "delay", "panelStyle", "styleClass", "panelStyleClass", "inputStyle", "inputId", "inputStyleClass", "placeholder", "readonly", "scrollHeight", "lazy", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "autoHighlight", "forceSelection", "type", "autoZIndex", "baseZIndex", "ariaLabel", "dropdownAriaLabel", "ariaLabelledBy", "dropdownIcon", "unique", "group", "completeOnFocus", "showClear", "dropdown", "showEmptyMessage", "dropdownMode", "multiple", "addOnTab", "tabindex", "dataKey", "emptyMessage", "showTransitionOptions", "hideTransitionOptions", "autofocus", "autocomplete", "optionGroupChildren", "optionGroupLabel", "overlayOptions", "suggestions", "optionLabel", "optionValue", "id", "searchMessage", "emptySelectionMessage", "selectionMessage", "autoOptionFocus", "selectOnFocus", "searchLocale", "optionDisabled", "focusOnHover", "typeahead", "addOnBlur", "separator", "appendTo", "motionOptions"], outputs: ["completeMethod", "onSelect", "onUnselect", "onAdd", "onFocus", "onBlur", "onDropdownClick", "onClear", "onInputKeydown", "onKeyUp", "onShow", "onHide", "onLazyLoad"] }, { kind: "ngmodule", type: InputTextModule }, { kind: "directive", type: CustomKeyboardDirective, selector: "[vlCustomKeyboard]", inputs: ["vlCustomKeyboard"] }, { kind: "pipe", type: PlaceholderPipe, name: "vlPlaceholder" }, { kind: "pipe", type: i9.CurrencyPipe, name: "currency" }] });
4747
4905
  }
4748
4906
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.2", ngImport: i0, type: FormComponent, decorators: [{
4749
4907
  type: Component,
@@ -4753,7 +4911,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.2", ngImpor
4753
4911
  AutoCompleteModule,
4754
4912
  InputTextModule,
4755
4913
  CustomKeyboardDirective,
4756
- ], selector: 'vl-form', template: "<!-- Faramarz Yousefian and Agent Toni (Claude Opus 5.5) 2026-10-13\r\n - new: autocompletes get their suggestions from RemoteListService (completeRemote) -->\r\n<!-- Faramarz Yousefian and Agent Toni (Claude Opus 5.5) 2026-10-13\r\n - fix: the placeholder comes from vlPlaceholder (pipes/placeholder.pipe.ts) - empty where the\r\n project defines none; it showed the text \"undefined\" -->\r\n<!-- Faramarz Yousefian and Agent Toni (Claude Opus 5) 2026-10-07\r\n - change: autocomplete fields take the toolkit string keyboard unless option.keyboardType\r\n names another one ('native' keeps the system keyboard)\r\n - change: date and time fields use the shared picker markup (picker-field, DateTimePickerService)\r\n instead of PrimeNG's own icon with empty handlers -->\r\n\r\n<!-- Shuaib 2026-09-24\r\n - change: the form field switch uses renderFieldType so legacy checkbox fields render as boolean. -->\r\n\r\n<!-- Faramarz Yousefian and Agent Toni (Claude Opus 5) 2026-09-19\r\n - change: the credit card type is spelled creditCard. The rename of 2026-09-15 reached\r\n model.component.html and the whole Designer but not this file, so one data object rendered\r\n in a modal and stayed empty here\r\n - new: a @contract comment on the type switch and on the credit card case, so the rule sits\r\n next to the code that implements it -->\r\n<div class=\"form-renderer\"\r\n [ngClass]=\"getStyleWithoutClasses(form?.layoutSchema?.style)?.classes\"\r\n [ngStyle]=\"getStyleWithoutClasses(form?.layoutSchema?.style)?.style\">\r\n <form *ngIf=\"form?.layoutSchema?.formSections?.length > 0\">\r\n <div\r\n *ngFor=\"let formSection of form?.layoutSchema?.formSections; let i = index\"\r\n class=\"section-card\">\r\n <div *ngIf=\"formSection?.label?.caption\" class=\"section-header\">\r\n <div class=\"section-title\"\r\n [ngClass]=\"getStyleWithoutClasses(formSection?.label?.style)?.classes\"\r\n [ngStyle]=\"getStyleWithoutClasses(formSection?.label?.style)?.style\">\r\n {{ formSection.label.caption }}\r\n </div>\r\n </div>\r\n\r\n <div *ngIf=\"formSection?.formFields?.length > 0\" class=\"section-body\"\r\n [ngClass]=\"getStyleWithoutClasses(formSection?.style)?.classes\"\r\n [ngStyle]=\"getSectionBodyStyle(formSection)\">\r\n <div *ngFor=\"let formField of formSection.formFields\" class=\"field-row\"\r\n [ngClass]=\"getStyleWithoutClasses(formField?.style)?.classes\"\r\n [ngStyle]=\"getFieldWrapperStyle(formField)\">\r\n <!-- @contract decision: this switch decides whether a field appears at all\r\n reality: renders string, number, image, date, time, dropdown, boolean,\r\n autocomplete, dateRange and the credit card type. Everything else\r\n falls into the default branch and the field renders empty - no error,\r\n nothing in the console either. Existing checkbox fields are normalized\r\n to boolean before this switch; new fields should use boolean.\r\n seen: measured 2026-09-19 with viewdefinition-contract/derive-capabilities.sh\r\n against this file; date, time, dropdown, boolean, autocomplete and\r\n dateRange arrived on 2026-09-18 -->\r\n <div [ngSwitch]=\"renderFieldType(\r\n formField?.scope?.reference &&\r\n form?.propertySchema?.[getScope(formField.scope?.reference)]\r\n ? form.propertySchema[getScope(formField.scope?.reference)]?.[\r\n formField.scope?.reference.split('/').pop()\r\n ]?.type\r\n : 'default'\r\n )\">\r\n <!-- image control -->\r\n <div *ngSwitchCase=\"'image'\"\r\n [ngClass]=\"getStyleWithoutClasses(formField?.scope?.style)?.classes\"\r\n [ngStyle]=\"getStyleWithoutClasses(formField?.scope?.style)?.style\">\r\n <img [src]=\"formField?.option?.src\" [alt]=\"'img'\" />\r\n </div>\r\n\r\n <!-- credit card control -->\r\n <!-- @contract decision: the credit card type is spelled creditCard\r\n reality: it was carditCard here until 2026-09-19. The rename of 2026-09-15\r\n reached model.component.html and the whole Designer, but not this\r\n file and not utility.service.ts, so the same data object rendered in\r\n one container and stayed empty in the other. All four places agree now.\r\n failure: a data object still declaring carditCard renders empty everywhere -\r\n that spelling is read nowhere any more.\r\n instead: declare the type as creditCard. -->\r\n <div *ngSwitchCase=\"'creditCard'\"\r\n [ngClass]=\"getStyleWithoutClasses(formField?.scope?.style)?.classes\"\r\n [ngStyle]=\"getStyleWithoutClasses(formField?.scope?.style)?.style\">\r\n <div id=\"card-element\"></div>\r\n <div id=\"card-errors\"\r\n [class]=\"creditCardError?.textContent !== '' ? 'text-red-400 m-0' : ''\"></div>\r\n </div>\r\n\r\n <!-- string control -->\r\n <span *ngSwitchCase=\"'string'\" class=\"form-group\">\r\n <span *ngIf=\"formField?.option?.protected\">\r\n <h5 style=\"display: flex; justify-content: space-between\">\r\n <span\r\n [ngClass]=\"getStyleWithoutClasses(formField?.label?.style)?.classes\"\r\n [ngStyle]=\"getStyleWithoutClasses(formField?.label?.style)?.style\">\r\n {{\r\n form.propertySchema[getScope(formField.scope?.reference)]?.[\r\n formField.scope?.reference.split('/').pop()\r\n ]?.caption\r\n }}\r\n </span>\r\n\r\n <span>\r\n {{\r\n form.propertySchema[getScope(formField.scope?.reference)]?.[\r\n formField.scope?.reference.split('/').pop()\r\n ]?.value\r\n }}\r\n </span>\r\n </h5>\r\n </span>\r\n\r\n <span *ngIf=\"!formField?.option?.protected\">\r\n <div [ngStyle]=\"getFieldInnerLayoutStyle(formField)\">\r\n <label\r\n [ngClass]=\"getStyleWithoutClasses(formField?.label?.style)?.classes\"\r\n [ngStyle]=\"getStyleWithoutClasses(formField?.label?.style)?.style\">\r\n {{\r\n formField?.label?.value\r\n ? formField.label.value\r\n : formField?.label?.caption\r\n ? formField.label.caption\r\n :\r\n form.propertySchema[getScope(formField.scope?.reference)]?.[\r\n formField.scope?.reference.split('/').pop()\r\n ]?.caption\r\n }}\r\n </label>\r\n\r\n <div [ngStyle]=\"\r\n formField?.option?.password\r\n ? {\r\n position: 'relative',\r\n display: 'flex',\r\n alignItems: 'center'\r\n }\r\n : {}\r\n \">\r\n <input [type]=\"\r\n formField?.option?.password\r\n ? !showPassword\r\n ? 'password'\r\n : 'text'\r\n : 'text'\r\n \" #inputField=\"ngModel\" [required]=\"formField?.required\"\r\n [attr.inputmode]=\"\r\n formField?.option?.email\r\n ? 'email'\r\n : formField?.option?.password\r\n ? 'numeric'\r\n : 'text'\r\n \" [pattern]=\"formField?.email ? customEmailPattern : ''\"\r\n [email]=\"formField?.email\"\r\n [minlength]=\"formField?.minlength\"\r\n [maxlength]=\"formField?.maxlength\"\r\n [ngClass]=\"getStyleWithoutClasses(formField?.scope?.style)?.classes\"\r\n [ngStyle]=\"getStyleWithoutClasses(formField?.scope?.style)?.style\"\r\n [(ngModel)]=\"\r\n form.propertySchema[getScope(formField.scope?.reference)][\r\n formField.scope?.reference.split('/').pop()\r\n ].value\r\n \" [name]=\"formField.scope?.reference\" [placeholder]=\"form.propertySchema | vlPlaceholder: formField.scope?.reference\" />\r\n\r\n <i *ngIf=\"formField?.option?.password\" class=\"fa\"\r\n [ngClass]=\"showPassword ? 'fa-eye' : 'fa-eye-slash'\"\r\n (click)=\"togglePasswordVisibility()\"\r\n style=\"position: absolute; right: 10px; cursor: pointer\"></i>\r\n </div>\r\n </div>\r\n\r\n <div *ngIf=\"inputField?.touched && inputField?.invalid\"\r\n [ngClass]=\"getStyleWithoutClasses(formField?.validation?.style)?.classes\"\r\n [ngStyle]=\"getStyleWithoutClasses(formField?.validation?.style)?.style\">\r\n <p [class]=\"\r\n formField?.layout === 'horizontal'\r\n ? 'text-red-400 m-0 horizontal-error'\r\n : 'text-red-400 m-0'\r\n \" *ngIf=\"inputField?.errors\">\r\n {{ setErroMessage(formField, errorMessages, inputField) }}\r\n </p>\r\n </div>\r\n </span>\r\n </span>\r\n\r\n <!-- number control -->\r\n <div *ngSwitchCase=\"'number'\" class=\"form-group\">\r\n <span *ngIf=\"formField?.option?.protected\"\r\n [ngClass]=\"getStyleWithoutClasses(formField?.label?.style)?.classes\"\r\n [ngStyle]=\"getStyleWithoutClasses(formField?.label?.style)?.style\">\r\n <h5>\r\n {{\r\n form.propertySchema[getScope(formField.scope?.reference)]?.[\r\n formField.scope?.reference.split('/').pop()\r\n ]?.caption\r\n }}\r\n\r\n {{\r\n form.propertySchema[getScope(formField.scope?.reference)]?.[\r\n formField.scope?.reference.split('/').pop()\r\n ]?.value\r\n | currency\r\n : formField?.option?.currency\r\n : true\r\n : formField?.option?.decimalPoint\r\n }}\r\n </h5>\r\n </span>\r\n\r\n <span *ngIf=\"!formField?.option?.protected\">\r\n <div [ngStyle]=\"getFieldInnerLayoutStyle(formField)\">\r\n <label\r\n [ngClass]=\"getStyleWithoutClasses(formField?.label?.style)?.classes\"\r\n [ngStyle]=\"getStyleWithoutClasses(formField?.label?.style)?.style\">\r\n {{\r\n formField?.label?.value\r\n ? formField.label.value\r\n :\r\n form.propertySchema[getScope(formField.scope?.reference)]?.[\r\n formField.scope?.reference.split('/').pop()\r\n ]?.caption\r\n }}\r\n </label>\r\n\r\n <input type=\"number\"\r\n [ngClass]=\"getStyleWithoutClasses(formField?.scope?.style)?.classes\"\r\n [ngStyle]=\"getStyleWithoutClasses(formField?.scope?.style)?.style\"\r\n [(ngModel)]=\"\r\n form.propertySchema[getScope(formField.scope?.reference)][\r\n formField.scope?.reference.split('/').pop()\r\n ].value\r\n \" [name]=\"formField.scope?.reference\" [placeholder]=\"form.propertySchema | vlPlaceholder: formField.scope?.reference\" />\r\n </div>\r\n </span>\r\n </div>\r\n\r\n <!-- checkbox control -->\r\n <div *ngSwitchCase=\"'boolean'\" class=\"form-group\"\r\n [ngClass]=\"getStyleWithoutClasses(formField?.scope?.style)?.classes\"\r\n [ngStyle]=\"getStyleWithoutClasses(formField?.scope?.style)?.style\">\r\n <span *ngIf=\"formField?.option?.postfixCaption\">\r\n <label class=\"form-check-label\">\r\n <input type=\"checkbox\" class=\"form-check-input mr-2\"\r\n [(ngModel)]=\"\r\n form.propertySchema[getScope(formField.scope?.reference)][\r\n formField.scope?.reference.split('/').pop()\r\n ].value\r\n \" [name]=\"formField.scope?.reference\"\r\n (ngModelChange)=\"setformData()\" />\r\n\r\n {{\r\n form.propertySchema[getScope(formField.scope?.reference)]?.[\r\n formField.scope?.reference.split('/').pop()\r\n ]?.caption\r\n }}\r\n </label>\r\n </span>\r\n\r\n <div *ngIf=\"!formField?.option?.postfixCaption\"\r\n [ngStyle]=\"getFieldInnerLayoutStyle(formField)\">\r\n <label class=\"form-check-label\">\r\n {{\r\n form.propertySchema[getScope(formField.scope?.reference)]?.[\r\n formField.scope?.reference.split('/').pop()\r\n ]?.caption\r\n }}\r\n\r\n <input type=\"checkbox\" class=\"form-check-input\" [(ngModel)]=\"\r\n form.propertySchema[getScope(formField.scope?.reference)][\r\n formField.scope?.reference.split('/').pop()\r\n ].value\r\n \" [name]=\"formField.scope?.reference\"\r\n (ngModelChange)=\"setformData()\" />\r\n </label>\r\n </div>\r\n </div>\r\n\r\n <!-- DateRange control -->\r\n <div *ngSwitchCase=\"'dateRange'\" class=\"form-group mb-3\">\r\n <span *ngIf=\"formField.option.protected\"\r\n [style]=\"getStyleWithoutClasses(formField?.label?.style).style\"\r\n [class]=\"formField?.label?.style.classes ? formField?.label?.style?.classes[0] : ''\">\r\n <vl-string [formField]=\"formField\" [modalItemInfo]=\"form\">\r\n </vl-string>\r\n </span>\r\n <div *ngIf=\"!formField.option.protected\">\r\n <div [ngStyle]=\"getFieldInnerLayoutStyle(formField)\">\r\n <label\r\n [style]=\"getStyleWithoutClasses(formField?.label?.style).style\"\r\n [class]=\"formField?.label?.style.classes ? formField?.label?.style?.classes[0] : ''\">{{\r\n formField.label?.value\r\n ?\r\n formField.label?.value :\r\n form.propertySchema[getScope(formField.scope?.reference)][formField.scope?.reference.split('/').pop()]?.caption\r\n }}</label>\r\n <nz-range-picker #dateRangeField=\"ngModel\"\r\n [required]=\"formField.option.required\"\r\n [name]=\"formField.scope?.reference\"\r\n [style]=\"getStyleWithoutClasses(formField?.style).style\"\r\n [(ngModel)]=\"form.propertySchema[getScope(formField.scope?.reference)][formField.scope?.reference.split('/').pop()].value\"></nz-range-picker>\r\n </div>\r\n <!-- Error Message -->\r\n <div *ngIf=\"dateRangeField?.touched && dateRangeField?.invalid\"\r\n [style]=\"getStyleWithoutClasses(formField?.validation?.style).style\">\r\n <p class=\"text-danger\"\r\n *ngIf=\"dateRangeField?.errors?.['required']\">\r\n {{formField.label?.value ?\r\n formField.label?.value :\r\n form.propertySchema[getScope(formField.scope?.reference)][formField.scope?.reference.split('/').pop()]?.caption\r\n +\r\n ' ' + errorMessages.required}}</p>\r\n <p class=\"text-danger\"\r\n *ngIf=\"dateRangeField?.errors?.['email']\">\r\n {{(formField.label?.value ?\r\n formField.label?.value :\r\n form.propertySchema[getScope(formField.scope?.reference)][formField.scope?.reference.split('/').pop()]?.caption)\r\n +\r\n ' ' + errorMessages.pattern}}</p>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- Date control -->\r\n <div *ngSwitchCase=\"'date'\" class=\"form-group mb-3\">\r\n <span *ngIf=\"formField.option.protected\"\r\n [style]=\"getStyleWithoutClasses(formField?.label?.style).style\"\r\n [class]=\"formField?.label?.style.classes ? formField?.label?.style?.classes[0] : ''\">\r\n <vl-string [formField]=\"formField\" [modalItemInfo]=\"form\">\r\n </vl-string>\r\n </span>\r\n <div *ngIf=\"!formField.option.protected\">\r\n <div [ngStyle]=\"getFieldInnerLayoutStyle(formField)\">\r\n <label\r\n [style]=\"getStyleWithoutClasses(formField?.label?.style).style\"\r\n [class]=\"formField?.label?.style.classes ? formField?.label?.style?.classes[0] : ''\">{{getLabel(formField)}}</label>\r\n\r\n <span>\r\n <div class=\"picker-field\">\r\n <p-datepicker #datePicker #dateField=\"ngModel\"\r\n styleClass=\"custom-datepicker\"\r\n [required]=\"formField.option.required\"\r\n [name]=\"formField.scope?.reference\"\r\n [disabled]=\"formField?.option?.disabled\"\r\n [autoZIndex]=\"true\" [baseZIndex]=\"10000\"\r\n (ngModelChange)=\"dateChangeEvent(formField, $event)\"\r\n (onInput)=\"onDateTyping($event)\" [dateFormat]=\"\r\n form.propertySchema[\r\n getScope(formField.scope?.reference)\r\n ][\r\n formField.scope?.reference.split('/').pop()\r\n ]?.format || 'yy-mm-dd'\r\n \" [(ngModel)]=\"\r\n form.propertySchema[\r\n getScope(formField.scope?.reference)\r\n ][\r\n formField.scope?.reference.split('/').pop()\r\n ].value\r\n \" [class]=\"formField?.scope?.style?.classes?.[0] || ''\"\r\n [style]=\"getStyleWithoutClasses(formField?.scope?.style).style\"\r\n [showIcon]=\"false\" [showOnFocus]=\"false\" appendTo=\"body\"\r\n [panelStyleClass]=\"picker.datePanelClass\" [motionOptions]=\"picker.dockedMotion\"\r\n [vlCustomKeyboard]=\"formField?.option?.keyboardType ?? 'date'\"\r\n (pointerdown)=\"picker.onFieldPointerDown($event, datePicker)\"\r\n (onFocus)=\"picker.onFieldFocus($event)\"\r\n (onShow)=\"picker.onShown()\"\r\n (onClose)=\"picker.onClose(datePicker)\">\r\n </p-datepicker>\r\n <button type=\"button\" class=\"picker-field__icon\" aria-label=\"Open calendar\"\r\n (pointerdown)=\"picker.openFromIcon($event, datePicker)\"\r\n (click)=\"picker.blockIconClick($event)\">\r\n <i class=\"pi pi-calendar\"></i>\r\n </button>\r\n </div>\r\n <!-- Error Message -->\r\n <div *ngIf=\"dateField?.touched && dateField?.invalid\"\r\n [style]=\"getStyleWithoutClasses(formField?.validation?.style).style\">\r\n <p class=\"text-danger\"\r\n *ngIf=\"dateField?.errors?.['required']\">\r\n {{setErroMessage(formField, errorMessages,\r\n \"required\")}}</p>\r\n <p class=\"text-danger\"\r\n *ngIf=\"dateField?.errors?.['email']\">\r\n {{(formField.label?.value ?\r\n formField.label?.value :\r\n form.propertySchema[getScope(formField.scope?.reference)][formField.scope?.reference.split('/').pop()]?.caption)\r\n +\r\n ' ' + errorMessages.pattern}}</p>\r\n </div>\r\n </span>\r\n\r\n </div>\r\n\r\n </div>\r\n </div>\r\n\r\n <!-- Time control -->\r\n <div *ngSwitchCase=\"'time'\" class=\"form-group mb-3\">\r\n <span *ngIf=\"formField.option.protected\"\r\n [style]=\"getStyleWithoutClasses(formField?.label?.style).style\"\r\n [class]=\"formField?.label?.style.classes ? formField?.label?.style?.classes[0] : ''\">\r\n <vl-string [formField]=\"formField\" [modalItemInfo]=\"form\">\r\n </vl-string>\r\n </span>\r\n <div *ngIf=\"!formField.option.protected\">\r\n <div [ngStyle]=\"getFieldInnerLayoutStyle(formField)\">\r\n <label\r\n [style]=\"getStyleWithoutClasses(formField?.label?.style).style\"\r\n [class]=\"formField?.label?.style.classes ? formField?.label?.style?.classes[0] : ''\">{{getLabel(formField)}}</label>\r\n <span>\r\n <div class=\"picker-field\">\r\n <p-datepicker #timePicker #timeField=\"ngModel\"\r\n styleClass=\"custom-datepicker\"\r\n [required]=\"formField.option.required\"\r\n [name]=\"formField.scope?.reference\" [timeOnly]=\"true\"\r\n hourFormat=\"24\" [disabled]=\"formField?.option?.disabled\" [autoZIndex]=\"true\" [baseZIndex]=\"10000\"\r\n (onInput)=\"onTimeTyping($event)\"\r\n (ngModelChange)=\"timeChangeEvent(formField, $event)\"\r\n [style]=\"getStyleWithoutClasses(formField?.scope?.style).style\"\r\n [(ngModel)]=\"\r\n form.propertySchema[\r\n getScope(formField.scope?.reference)\r\n ][\r\n formField.scope?.reference.split('/').pop()\r\n ].value\r\n \"\r\n [class]=\"formField?.scope?.style?.classes?.[0] || ''\"\r\n [showIcon]=\"false\" [showOnFocus]=\"false\" appendTo=\"body\"\r\n [panelStyleClass]=\"picker.timePanelClass\"\r\n [vlCustomKeyboard]=\"formField?.option?.keyboardType ?? 'time'\"\r\n (pointerdown)=\"picker.onFieldPointerDown($event, timePicker)\"\r\n (onFocus)=\"picker.onFieldFocus($event)\"\r\n (onShow)=\"picker.onShown()\"\r\n (onClose)=\"picker.onClose(timePicker)\">\r\n </p-datepicker>\r\n <button type=\"button\" class=\"picker-field__icon\" aria-label=\"Open time picker\"\r\n (pointerdown)=\"picker.openFromIcon($event, timePicker)\"\r\n (click)=\"picker.blockIconClick($event)\">\r\n <i class=\"pi pi-clock\"></i>\r\n </button>\r\n </div>\r\n\r\n <!-- Error Message -->\r\n <div *ngIf=\"timeField?.touched && timeField?.invalid\"\r\n [style]=\"getStyleWithoutClasses(formField?.validation?.style).style\">\r\n <p class=\"text-danger\"\r\n *ngIf=\"timeField?.errors?.['required']\">\r\n {{setErroMessage(formField, errorMessages,\r\n \"required\")}}</p>\r\n <p class=\"text-danger\"\r\n *ngIf=\"timeField?.errors?.['email']\">\r\n {{(formField.label?.value ?\r\n formField.label?.value :\r\n form.propertySchema[getScope(formField.scope?.reference)][formField.scope?.reference.split('/').pop()]?.caption)\r\n +\r\n ' ' + errorMessages.pattern}}</p>\r\n </div>\r\n </span>\r\n\r\n </div>\r\n\r\n </div>\r\n </div>\r\n\r\n <!-- Autocomplete control -->\r\n <div *ngSwitchCase=\"'autocomplete'\" class=\"form-group mb-3\">\r\n <span *ngIf=\"formField.option.protected\"\r\n [style]=\"getStyleWithoutClasses(formField?.label?.style).style\"\r\n [class]=\"formField?.label?.style.classes ? formField?.label?.style?.classes[0] : ''\">\r\n <vl-string [formField]=\"formField\" [modalItemInfo]=\"form\">\r\n </vl-string>\r\n </span>\r\n <div *ngIf=\"!formField.option.protected\">\r\n <div [ngStyle]=\"getFieldInnerLayoutStyle(formField)\">\r\n <vl-label [formField]=\"formField\" [modalItemInfo]=\"form\">\r\n </vl-label>\r\n\r\n <span>\r\n <p-autocomplete [suggestions]=\"remoteSuggestions[formField.scope?.reference] ?? []\" (completeMethod)=\"completeRemote($event, formField)\" #autocompleteField=\"ngModel\"\r\n [required]=\"formField.option.required\"\r\n [name]=\"formField.scope?.reference\"\r\n styleClass=\"custom-autocomplete\"\r\n [(ngModel)]=\"form.propertySchema[getScope(formField.scope?.reference)][formField.scope?.reference.split('/').pop()].value\"\r\n [style]=\"getStyleWithoutClasses(formField?.scope?.style).style\"\r\n [class]=\"formField?.scope?.style?.classes ? formField?.scope?.style?.classes[0] : ''\" [dropdown]=\"true\"\r\n [optionLabel]=\"formField.option.autocomplete.response.label\"\r\n [placeholder]=\"form.propertySchema | vlPlaceholder: formField.scope?.reference\"\r\n (ngModelChange)=\"autocompFocusOutEvent($event, formField)\"\r\n [vlCustomKeyboard]=\"formField?.option?.keyboardType ?? 'string'\">\r\n </p-autocomplete>\r\n <!-- Error Message -->\r\n <div\r\n *ngIf=\"autocompleteField?.touched && autocompleteField?.invalid\"\r\n [style]=\"getStyleWithoutClasses(formField?.validation?.style).style\">\r\n <p class=\"text-danger\"\r\n *ngIf=\"autocompleteField?.errors?.['required']\">\r\n {{setErroMessage(formField, errorMessages,\r\n \"required\")}}</p>\r\n <p class=\"text-danger\"\r\n *ngIf=\"autocompleteField?.errors?.['email']\">\r\n {{(formField.label?.value ?\r\n formField.label?.value :\r\n form.propertySchema[getScope(formField.scope?.reference)][formField.scope?.reference.split('/').pop()]?.caption)\r\n +\r\n ' ' + errorMessages.pattern}}</p>\r\n </div>\r\n </span>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- dropdown control -->\r\n <div *ngSwitchCase=\"'dropdown'\" class=\"form-group\"\r\n [ngClass]=\"getStyleWithoutClasses(formField?.scope?.style)?.classes\"\r\n [ngStyle]=\"getStyleWithoutClasses(formField?.scope?.style)?.style\">\r\n <span *ngIf=\"formField?.option?.postfixCaption\">\r\n <select id=\"dynamic-dropdown\" #dropdownField=\"ngModel\"\r\n [ngClass]=\"getStyleWithoutClasses(formField?.scope?.style)?.classes\"\r\n [ngStyle]=\"getStyleWithoutClasses(formField?.scope?.style)?.style\"\r\n [name]=\"formField.scope?.reference\"\r\n [(ngModel)]=\"\r\n form.propertySchema[getScope(formField.scope?.reference)][\r\n formField.scope?.reference.split('/').pop()\r\n ].value\r\n \">\r\n <option *ngFor=\"\r\n let item of form.propertySchema[getScope(formField.scope?.reference)]?.[\r\n formField.scope?.reference.split('/').pop()\r\n ]?.data\r\n \" [value]=\"item[formField?.option?.optionValue]\">\r\n {{ item[formField?.option?.optionLabel] }}\r\n </option>\r\n </select>\r\n\r\n <label\r\n [ngClass]=\"getStyleWithoutClasses(formField?.label?.style)?.classes\"\r\n [ngStyle]=\"getStyleWithoutClasses(formField?.label?.style)?.style\">\r\n {{\r\n form.propertySchema[getScope(formField.scope?.reference)]?.[\r\n formField.scope?.reference.split('/').pop()\r\n ]?.caption\r\n }}\r\n </label>\r\n </span>\r\n\r\n <div *ngIf=\"!formField?.option?.postfixCaption\">\r\n <div [ngStyle]=\"getFieldInnerLayoutStyle(formField)\">\r\n <label\r\n [ngClass]=\"getStyleWithoutClasses(formField?.label?.style)?.classes\"\r\n [ngStyle]=\"getStyleWithoutClasses(formField?.label?.style)?.style\">\r\n {{\r\n form.propertySchema[getScope(formField.scope?.reference)]?.[\r\n formField.scope?.reference.split('/').pop()\r\n ]?.caption\r\n }}\r\n </label>\r\n\r\n <nz-select nzShowSearch nzAllowClear nzPlaceHolder=\"Select\"\r\n #dropdownField=\"ngModel\"\r\n [required]=\"formField?.required\"\r\n [ngClass]=\"getStyleWithoutClasses(formField?.scope?.style)?.classes\"\r\n [ngStyle]=\"getStyleWithoutClasses(formField?.scope?.style)?.style\"\r\n [name]=\"formField.scope?.reference\" [(ngModel)]=\"\r\n form.propertySchema[getScope(formField.scope?.reference)][\r\n formField.scope?.reference.split('/').pop()\r\n ].value\r\n \">\r\n <nz-option *ngFor=\"\r\n let item of form.propertySchema[getScope(formField.scope?.reference)]?.[\r\n formField.scope?.reference.split('/').pop()\r\n ]?.data\r\n \" [nzLabel]=\"item[formField?.option?.optionLabel]\"\r\n [nzValue]=\"item[formField?.option?.optionValue]\"></nz-option>\r\n </nz-select>\r\n </div>\r\n\r\n <div *ngIf=\"dropdownField?.touched && dropdownField?.invalid\"\r\n [ngClass]=\"getStyleWithoutClasses(formField?.validation?.style)?.classes\"\r\n [ngStyle]=\"getStyleWithoutClasses(formField?.validation?.style)?.style\">\r\n <p [class]=\"\r\n formField?.layout === 'horizontal'\r\n ? 'text-red-400 m-0 horizontal-error'\r\n : 'text-red-400 m-0'\r\n \" *ngIf=\"dropdownField?.errors\">\r\n {{ setErroMessage(formField, errorMessages, dropdownField)\r\n }}\r\n </p>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- button/default control -->\r\n <div *ngSwitchCase=\"'default'\">\r\n <button type=\"submit\"\r\n [ngClass]=\"getStyleWithoutClasses(formField?.style)?.classes\"\r\n [ngStyle]=\"getStyleWithoutClasses(formField?.style)?.style\"\r\n (click)=\"invokeFormBtnClick(formField?.option, form.propertySchema)\">\r\n {{ formField?.label?.caption }}\r\n </button>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n </form>\r\n</div>\r\n", styles: [":host{display:block;width:100%;height:100%;min-height:0}.form-renderer{width:100%;height:100%;min-height:0;overflow-y:auto;overflow-x:hidden;box-sizing:border-box;padding:12px}.section-card{border:1px solid #e5e7eb;border-radius:var(--radius-sm, 8px);padding:12px;margin-bottom:12px;background:#fff;box-sizing:border-box}.section-header{display:flex;align-items:center;justify-content:space-between;margin-bottom:10px;font-weight:600}.section-title{font-size:14px;color:#0f172a}.section-body{position:relative;width:100%;min-height:78px;box-sizing:border-box}.field-row{position:relative;min-width:0;width:100%;box-sizing:border-box}.field-row input,.field-row select,.field-row nz-select,.field-row textarea,.field-row button{max-width:100%;box-sizing:border-box}@media(max-width:768px){.section-body{grid-template-columns:repeat(1,minmax(0,1fr))!important}.field-row{grid-column:span 1!important}}@media(min-width:769px)and (max-width:1024px){.section-body{grid-template-columns:repeat(6,minmax(0,1fr))!important}.field-row{grid-column:span 6!important}}:host-context(.mobile-frame) .section-body,:host-context(.device-mobile) .section-body{grid-template-columns:repeat(1,minmax(0,1fr))!important}:host-context(.mobile-frame) .field-row,:host-context(.device-mobile) .field-row{grid-column:span 1!important}:host-context(.tablet-frame) .section-body,:host-context(.device-tablet) .section-body{grid-template-columns:repeat(6,minmax(0,1fr))!important}:host-context(.tablet-frame) .field-row,:host-context(.device-tablet) .field-row{grid-column:span 6!important}\n"] }]
4914
+ ], selector: 'vl-form', template: "<!-- Faramarz Yousefian and Agent Toni (Claude Opus 5.5) 2026-10-13\r\n - new: autocompletes get their suggestions from RemoteListService (completeRemote) -->\r\n<!-- Faramarz Yousefian and Agent Toni (Claude Opus 5.5) 2026-10-13\r\n - fix: the placeholder comes from vlPlaceholder (pipes/placeholder.pipe.ts) - empty where the\r\n project defines none; it showed the text \"undefined\" -->\r\n<!-- Faramarz Yousefian and Agent Toni (Claude Opus 5) 2026-10-07\r\n - change: autocomplete fields take the toolkit string keyboard unless option.keyboardType\r\n names another one ('native' keeps the system keyboard)\r\n - change: date and time fields use the shared picker markup (picker-field, DateTimePickerService)\r\n instead of PrimeNG's own icon with empty handlers -->\r\n\r\n<!-- Shuaib 2026-09-24\r\n - change: the form field switch uses renderFieldType so legacy checkbox fields render as boolean. -->\r\n\r\n<!-- Faramarz Yousefian and Agent Toni (Claude Opus 5) 2026-09-19\r\n - change: the credit card type is spelled creditCard. The rename of 2026-09-15 reached\r\n model.component.html and the whole Designer but not this file, so one data object rendered\r\n in a modal and stayed empty here\r\n - new: a @contract comment on the type switch and on the credit card case, so the rule sits\r\n next to the code that implements it -->\r\n<div class=\"form-renderer\"\r\n [ngClass]=\"getStyleWithoutClasses(form?.layoutSchema?.style)?.classes\"\r\n [ngStyle]=\"getStyleWithoutClasses(form?.layoutSchema?.style)?.style\">\r\n <form *ngIf=\"form?.layoutSchema?.formSections?.length > 0\">\r\n <div\r\n *ngFor=\"let formSection of form?.layoutSchema?.formSections; let i = index\"\r\n class=\"section-card\">\r\n <div *ngIf=\"formSection?.label?.caption\" class=\"section-header\">\r\n <div class=\"section-title\"\r\n [ngClass]=\"getStyleWithoutClasses(formSection?.label?.style)?.classes\"\r\n [ngStyle]=\"getStyleWithoutClasses(formSection?.label?.style)?.style\">\r\n {{ formSection.label.caption }}\r\n </div>\r\n </div>\r\n\r\n <div *ngIf=\"formSection?.formFields?.length > 0\" class=\"section-body\"\r\n [ngClass]=\"getStyleWithoutClasses(formSection?.style)?.classes\"\r\n [ngStyle]=\"getSectionBodyStyle(formSection)\">\r\n <div *ngFor=\"let formField of formSection.formFields\" class=\"field-row\"\r\n [ngClass]=\"getStyleWithoutClasses(formField?.style)?.classes\"\r\n [ngStyle]=\"getFieldWrapperStyle(formField)\">\r\n <!-- @contract decision: this switch decides whether a field appears at all\r\n reality: renders string, number, image, date, time, dropdown, boolean,\r\n autocomplete, dateRange and the credit card type. Everything else\r\n falls into the default branch and the field renders empty - no error,\r\n nothing in the console either. Existing checkbox fields are normalized\r\n to boolean before this switch; new fields should use boolean.\r\n seen: measured 2026-09-19 with viewdefinition-contract/derive-capabilities.sh\r\n against this file; date, time, dropdown, boolean, autocomplete and\r\n dateRange arrived on 2026-09-18 -->\r\n <div [ngSwitch]=\"renderFieldType(\r\n formField?.scope?.reference &&\r\n form?.propertySchema?.[getScope(formField.scope?.reference)]\r\n ? form.propertySchema[getScope(formField.scope?.reference)]?.[\r\n formField.scope?.reference.split('/').pop()\r\n ]?.type\r\n : 'default'\r\n )\">\r\n <!-- Media control -->\r\n\r\n <div *ngSwitchCase=\"'media'\"\r\n [ngClass]=\"getStyleWithoutClasses(formField?.scope?.style)?.classes\"\r\n [ngStyle]=\"getStyleWithoutClasses(formField?.scope?.style)?.style\">\r\n <ng-container *ngTemplateOutlet=\"formMediaContent; context: { field: formField }\"></ng-container>\r\n </div>\r\n\r\n\r\n <!-- credit card control -->\r\n <!-- @contract decision: the credit card type is spelled creditCard\r\n reality: it was carditCard here until 2026-09-19. The rename of 2026-09-15\r\n reached model.component.html and the whole Designer, but not this\r\n file and not utility.service.ts, so the same data object rendered in\r\n one container and stayed empty in the other. All four places agree now.\r\n failure: a data object still declaring carditCard renders empty everywhere -\r\n that spelling is read nowhere any more.\r\n instead: declare the type as creditCard. -->\r\n <div *ngSwitchCase=\"'creditCard'\"\r\n [ngClass]=\"getStyleWithoutClasses(formField?.scope?.style)?.classes\"\r\n [ngStyle]=\"getStyleWithoutClasses(formField?.scope?.style)?.style\">\r\n <div id=\"card-element\"></div>\r\n <div id=\"card-errors\"\r\n [class]=\"creditCardError?.textContent !== '' ? 'text-red-400 m-0' : ''\"></div>\r\n </div>\r\n\r\n <!-- string control -->\r\n <span *ngSwitchCase=\"'string'\" class=\"form-group\">\r\n <span *ngIf=\"formField?.option?.protected\">\r\n <h5 style=\"display: flex; justify-content: space-between\">\r\n <span\r\n [ngClass]=\"getStyleWithoutClasses(formField?.label?.style)?.classes\"\r\n [ngStyle]=\"getStyleWithoutClasses(formField?.label?.style)?.style\">\r\n {{\r\n form.propertySchema[getScope(formField.scope?.reference)]?.[\r\n formField.scope?.reference.split('/').pop()\r\n ]?.caption\r\n }}\r\n </span>\r\n\r\n <span>\r\n {{\r\n form.propertySchema[getScope(formField.scope?.reference)]?.[\r\n formField.scope?.reference.split('/').pop()\r\n ]?.value\r\n }}\r\n </span>\r\n </h5>\r\n </span>\r\n\r\n <span *ngIf=\"!formField?.option?.protected\">\r\n <div [ngStyle]=\"getFieldInnerLayoutStyle(formField)\">\r\n <label\r\n [ngClass]=\"getStyleWithoutClasses(formField?.label?.style)?.classes\"\r\n [ngStyle]=\"getStyleWithoutClasses(formField?.label?.style)?.style\">\r\n {{\r\n formField?.label?.value\r\n ? formField.label.value\r\n : formField?.label?.caption\r\n ? formField.label.caption\r\n :\r\n form.propertySchema[getScope(formField.scope?.reference)]?.[\r\n formField.scope?.reference.split('/').pop()\r\n ]?.caption\r\n }}\r\n </label>\r\n\r\n <div [ngStyle]=\"\r\n formField?.option?.password\r\n ? {\r\n position: 'relative',\r\n display: 'flex',\r\n alignItems: 'center'\r\n }\r\n : {}\r\n \">\r\n <input [type]=\"\r\n formField?.option?.password\r\n ? !showPassword\r\n ? 'password'\r\n : 'text'\r\n : 'text'\r\n \" #inputField=\"ngModel\" [required]=\"formField?.required\"\r\n [attr.inputmode]=\"\r\n formField?.option?.email\r\n ? 'email'\r\n : formField?.option?.password\r\n ? 'numeric'\r\n : 'text'\r\n \" [pattern]=\"formField?.email ? customEmailPattern : ''\"\r\n [email]=\"formField?.email\"\r\n [minlength]=\"formField?.minlength\"\r\n [maxlength]=\"formField?.maxlength\"\r\n [ngClass]=\"getStyleWithoutClasses(formField?.scope?.style)?.classes\"\r\n [ngStyle]=\"getStyleWithoutClasses(formField?.scope?.style)?.style\"\r\n [(ngModel)]=\"\r\n form.propertySchema[getScope(formField.scope?.reference)][\r\n formField.scope?.reference.split('/').pop()\r\n ].value\r\n \" [name]=\"formField.scope?.reference\" [placeholder]=\"form.propertySchema | vlPlaceholder: formField.scope?.reference\" />\r\n\r\n <i *ngIf=\"formField?.option?.password\" class=\"fa\"\r\n [ngClass]=\"showPassword ? 'fa-eye' : 'fa-eye-slash'\"\r\n (click)=\"togglePasswordVisibility()\"\r\n style=\"position: absolute; right: 10px; cursor: pointer\"></i>\r\n </div>\r\n </div>\r\n\r\n <div *ngIf=\"inputField?.touched && inputField?.invalid\"\r\n [ngClass]=\"getStyleWithoutClasses(formField?.validation?.style)?.classes\"\r\n [ngStyle]=\"getStyleWithoutClasses(formField?.validation?.style)?.style\">\r\n <p [class]=\"\r\n formField?.layout === 'horizontal'\r\n ? 'text-red-400 m-0 horizontal-error'\r\n : 'text-red-400 m-0'\r\n \" *ngIf=\"inputField?.errors\">\r\n {{ setErroMessage(formField, errorMessages, inputField) }}\r\n </p>\r\n </div>\r\n </span>\r\n </span>\r\n\r\n <!-- number control -->\r\n <div *ngSwitchCase=\"'number'\" class=\"form-group\">\r\n <span *ngIf=\"formField?.option?.protected\"\r\n [ngClass]=\"getStyleWithoutClasses(formField?.label?.style)?.classes\"\r\n [ngStyle]=\"getStyleWithoutClasses(formField?.label?.style)?.style\">\r\n <h5>\r\n {{\r\n form.propertySchema[getScope(formField.scope?.reference)]?.[\r\n formField.scope?.reference.split('/').pop()\r\n ]?.caption\r\n }}\r\n\r\n {{\r\n form.propertySchema[getScope(formField.scope?.reference)]?.[\r\n formField.scope?.reference.split('/').pop()\r\n ]?.value\r\n | currency\r\n : formField?.option?.currency\r\n : true\r\n : formField?.option?.decimalPoint\r\n }}\r\n </h5>\r\n </span>\r\n\r\n <span *ngIf=\"!formField?.option?.protected\">\r\n <div [ngStyle]=\"getFieldInnerLayoutStyle(formField)\">\r\n <label\r\n [ngClass]=\"getStyleWithoutClasses(formField?.label?.style)?.classes\"\r\n [ngStyle]=\"getStyleWithoutClasses(formField?.label?.style)?.style\">\r\n {{\r\n formField?.label?.value\r\n ? formField.label.value\r\n :\r\n form.propertySchema[getScope(formField.scope?.reference)]?.[\r\n formField.scope?.reference.split('/').pop()\r\n ]?.caption\r\n }}\r\n </label>\r\n\r\n <input type=\"number\"\r\n [ngClass]=\"getStyleWithoutClasses(formField?.scope?.style)?.classes\"\r\n [ngStyle]=\"getStyleWithoutClasses(formField?.scope?.style)?.style\"\r\n [(ngModel)]=\"\r\n form.propertySchema[getScope(formField.scope?.reference)][\r\n formField.scope?.reference.split('/').pop()\r\n ].value\r\n \" [name]=\"formField.scope?.reference\" [placeholder]=\"form.propertySchema | vlPlaceholder: formField.scope?.reference\" />\r\n </div>\r\n </span>\r\n </div>\r\n\r\n <!-- checkbox control -->\r\n <div *ngSwitchCase=\"'boolean'\" class=\"form-group\"\r\n [ngClass]=\"getStyleWithoutClasses(formField?.scope?.style)?.classes\"\r\n [ngStyle]=\"getStyleWithoutClasses(formField?.scope?.style)?.style\">\r\n <span *ngIf=\"formField?.option?.postfixCaption\">\r\n <label class=\"form-check-label\">\r\n <input type=\"checkbox\" class=\"form-check-input mr-2\"\r\n [(ngModel)]=\"\r\n form.propertySchema[getScope(formField.scope?.reference)][\r\n formField.scope?.reference.split('/').pop()\r\n ].value\r\n \" [name]=\"formField.scope?.reference\"\r\n (ngModelChange)=\"setformData()\" />\r\n\r\n {{\r\n form.propertySchema[getScope(formField.scope?.reference)]?.[\r\n formField.scope?.reference.split('/').pop()\r\n ]?.caption\r\n }}\r\n </label>\r\n </span>\r\n\r\n <div *ngIf=\"!formField?.option?.postfixCaption\"\r\n [ngStyle]=\"getFieldInnerLayoutStyle(formField)\">\r\n <label class=\"form-check-label\">\r\n {{\r\n form.propertySchema[getScope(formField.scope?.reference)]?.[\r\n formField.scope?.reference.split('/').pop()\r\n ]?.caption\r\n }}\r\n\r\n <input type=\"checkbox\" class=\"form-check-input\" [(ngModel)]=\"\r\n form.propertySchema[getScope(formField.scope?.reference)][\r\n formField.scope?.reference.split('/').pop()\r\n ].value\r\n \" [name]=\"formField.scope?.reference\"\r\n (ngModelChange)=\"setformData()\" />\r\n </label>\r\n </div>\r\n </div>\r\n\r\n <!-- DateRange control -->\r\n <div *ngSwitchCase=\"'dateRange'\" class=\"form-group mb-3\">\r\n <span *ngIf=\"formField.option.protected\"\r\n [style]=\"getStyleWithoutClasses(formField?.label?.style).style\"\r\n [class]=\"formField?.label?.style.classes ? formField?.label?.style?.classes[0] : ''\">\r\n <vl-string [formField]=\"formField\" [modalItemInfo]=\"form\">\r\n </vl-string>\r\n </span>\r\n <div *ngIf=\"!formField.option.protected\">\r\n <div [ngStyle]=\"getFieldInnerLayoutStyle(formField)\">\r\n <label\r\n [style]=\"getStyleWithoutClasses(formField?.label?.style).style\"\r\n [class]=\"formField?.label?.style.classes ? formField?.label?.style?.classes[0] : ''\">{{\r\n formField.label?.value\r\n ?\r\n formField.label?.value :\r\n form.propertySchema[getScope(formField.scope?.reference)][formField.scope?.reference.split('/').pop()]?.caption\r\n }}</label>\r\n <nz-range-picker #dateRangeField=\"ngModel\"\r\n [required]=\"formField.option.required\"\r\n [name]=\"formField.scope?.reference\"\r\n [style]=\"getStyleWithoutClasses(formField?.style).style\"\r\n [(ngModel)]=\"form.propertySchema[getScope(formField.scope?.reference)][formField.scope?.reference.split('/').pop()].value\"></nz-range-picker>\r\n </div>\r\n <!-- Error Message -->\r\n <div *ngIf=\"dateRangeField?.touched && dateRangeField?.invalid\"\r\n [style]=\"getStyleWithoutClasses(formField?.validation?.style).style\">\r\n <p class=\"text-danger\"\r\n *ngIf=\"dateRangeField?.errors?.['required']\">\r\n {{formField.label?.value ?\r\n formField.label?.value :\r\n form.propertySchema[getScope(formField.scope?.reference)][formField.scope?.reference.split('/').pop()]?.caption\r\n +\r\n ' ' + errorMessages.required}}</p>\r\n <p class=\"text-danger\"\r\n *ngIf=\"dateRangeField?.errors?.['email']\">\r\n {{(formField.label?.value ?\r\n formField.label?.value :\r\n form.propertySchema[getScope(formField.scope?.reference)][formField.scope?.reference.split('/').pop()]?.caption)\r\n +\r\n ' ' + errorMessages.pattern}}</p>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- Date control -->\r\n <div *ngSwitchCase=\"'date'\" class=\"form-group mb-3\">\r\n <span *ngIf=\"formField.option.protected\"\r\n [style]=\"getStyleWithoutClasses(formField?.label?.style).style\"\r\n [class]=\"formField?.label?.style.classes ? formField?.label?.style?.classes[0] : ''\">\r\n <vl-string [formField]=\"formField\" [modalItemInfo]=\"form\">\r\n </vl-string>\r\n </span>\r\n <div *ngIf=\"!formField.option.protected\">\r\n <div [ngStyle]=\"getFieldInnerLayoutStyle(formField)\">\r\n <label\r\n [style]=\"getStyleWithoutClasses(formField?.label?.style).style\"\r\n [class]=\"formField?.label?.style.classes ? formField?.label?.style?.classes[0] : ''\">{{getLabel(formField)}}</label>\r\n\r\n <span>\r\n <div class=\"picker-field\">\r\n <p-datepicker #datePicker #dateField=\"ngModel\"\r\n styleClass=\"custom-datepicker\"\r\n [required]=\"formField.option.required\"\r\n [name]=\"formField.scope?.reference\"\r\n [disabled]=\"formField?.option?.disabled\"\r\n [autoZIndex]=\"true\" [baseZIndex]=\"10000\"\r\n (ngModelChange)=\"dateChangeEvent(formField, $event)\"\r\n (onInput)=\"onDateTyping($event)\" [dateFormat]=\"\r\n form.propertySchema[\r\n getScope(formField.scope?.reference)\r\n ][\r\n formField.scope?.reference.split('/').pop()\r\n ]?.format || 'yy-mm-dd'\r\n \" [(ngModel)]=\"\r\n form.propertySchema[\r\n getScope(formField.scope?.reference)\r\n ][\r\n formField.scope?.reference.split('/').pop()\r\n ].value\r\n \" [class]=\"formField?.scope?.style?.classes?.[0] || ''\"\r\n [style]=\"getStyleWithoutClasses(formField?.scope?.style).style\"\r\n [showIcon]=\"false\" [showOnFocus]=\"false\" appendTo=\"body\"\r\n [panelStyleClass]=\"picker.datePanelClass\" [motionOptions]=\"picker.dockedMotion\"\r\n [vlCustomKeyboard]=\"formField?.option?.keyboardType ?? 'date'\"\r\n (pointerdown)=\"picker.onFieldPointerDown($event, datePicker)\"\r\n (onFocus)=\"picker.onFieldFocus($event)\"\r\n (onShow)=\"picker.onShown()\"\r\n (onClose)=\"picker.onClose(datePicker)\">\r\n </p-datepicker>\r\n <button type=\"button\" class=\"picker-field__icon\" aria-label=\"Open calendar\"\r\n (pointerdown)=\"picker.openFromIcon($event, datePicker)\"\r\n (click)=\"picker.blockIconClick($event)\">\r\n <i class=\"pi pi-calendar\"></i>\r\n </button>\r\n </div>\r\n <!-- Error Message -->\r\n <div *ngIf=\"dateField?.touched && dateField?.invalid\"\r\n [style]=\"getStyleWithoutClasses(formField?.validation?.style).style\">\r\n <p class=\"text-danger\"\r\n *ngIf=\"dateField?.errors?.['required']\">\r\n {{setErroMessage(formField, errorMessages,\r\n \"required\")}}</p>\r\n <p class=\"text-danger\"\r\n *ngIf=\"dateField?.errors?.['email']\">\r\n {{(formField.label?.value ?\r\n formField.label?.value :\r\n form.propertySchema[getScope(formField.scope?.reference)][formField.scope?.reference.split('/').pop()]?.caption)\r\n +\r\n ' ' + errorMessages.pattern}}</p>\r\n </div>\r\n </span>\r\n\r\n </div>\r\n\r\n </div>\r\n </div>\r\n\r\n <!-- Time control -->\r\n <div *ngSwitchCase=\"'time'\" class=\"form-group mb-3\">\r\n <span *ngIf=\"formField.option.protected\"\r\n [style]=\"getStyleWithoutClasses(formField?.label?.style).style\"\r\n [class]=\"formField?.label?.style.classes ? formField?.label?.style?.classes[0] : ''\">\r\n <vl-string [formField]=\"formField\" [modalItemInfo]=\"form\">\r\n </vl-string>\r\n </span>\r\n <div *ngIf=\"!formField.option.protected\">\r\n <div [ngStyle]=\"getFieldInnerLayoutStyle(formField)\">\r\n <label\r\n [style]=\"getStyleWithoutClasses(formField?.label?.style).style\"\r\n [class]=\"formField?.label?.style.classes ? formField?.label?.style?.classes[0] : ''\">{{getLabel(formField)}}</label>\r\n <span>\r\n <div class=\"picker-field\">\r\n <p-datepicker #timePicker #timeField=\"ngModel\"\r\n styleClass=\"custom-datepicker\"\r\n [required]=\"formField.option.required\"\r\n [name]=\"formField.scope?.reference\" [timeOnly]=\"true\"\r\n hourFormat=\"24\" [disabled]=\"formField?.option?.disabled\" [autoZIndex]=\"true\" [baseZIndex]=\"10000\"\r\n (onInput)=\"onTimeTyping($event)\"\r\n (ngModelChange)=\"timeChangeEvent(formField, $event)\"\r\n [style]=\"getStyleWithoutClasses(formField?.scope?.style).style\"\r\n [(ngModel)]=\"\r\n form.propertySchema[\r\n getScope(formField.scope?.reference)\r\n ][\r\n formField.scope?.reference.split('/').pop()\r\n ].value\r\n \"\r\n [class]=\"formField?.scope?.style?.classes?.[0] || ''\"\r\n [showIcon]=\"false\" [showOnFocus]=\"false\" appendTo=\"body\"\r\n [panelStyleClass]=\"picker.timePanelClass\"\r\n [vlCustomKeyboard]=\"formField?.option?.keyboardType ?? 'time'\"\r\n (pointerdown)=\"picker.onFieldPointerDown($event, timePicker)\"\r\n (onFocus)=\"picker.onFieldFocus($event)\"\r\n (onShow)=\"picker.onShown()\"\r\n (onClose)=\"picker.onClose(timePicker)\">\r\n </p-datepicker>\r\n <button type=\"button\" class=\"picker-field__icon\" aria-label=\"Open time picker\"\r\n (pointerdown)=\"picker.openFromIcon($event, timePicker)\"\r\n (click)=\"picker.blockIconClick($event)\">\r\n <i class=\"pi pi-clock\"></i>\r\n </button>\r\n </div>\r\n\r\n <!-- Error Message -->\r\n <div *ngIf=\"timeField?.touched && timeField?.invalid\"\r\n [style]=\"getStyleWithoutClasses(formField?.validation?.style).style\">\r\n <p class=\"text-danger\"\r\n *ngIf=\"timeField?.errors?.['required']\">\r\n {{setErroMessage(formField, errorMessages,\r\n \"required\")}}</p>\r\n <p class=\"text-danger\"\r\n *ngIf=\"timeField?.errors?.['email']\">\r\n {{(formField.label?.value ?\r\n formField.label?.value :\r\n form.propertySchema[getScope(formField.scope?.reference)][formField.scope?.reference.split('/').pop()]?.caption)\r\n +\r\n ' ' + errorMessages.pattern}}</p>\r\n </div>\r\n </span>\r\n\r\n </div>\r\n\r\n </div>\r\n </div>\r\n\r\n <!-- Autocomplete control -->\r\n <div *ngSwitchCase=\"'autocomplete'\" class=\"form-group mb-3\">\r\n <span *ngIf=\"formField.option.protected\"\r\n [style]=\"getStyleWithoutClasses(formField?.label?.style).style\"\r\n [class]=\"formField?.label?.style.classes ? formField?.label?.style?.classes[0] : ''\">\r\n <vl-string [formField]=\"formField\" [modalItemInfo]=\"form\">\r\n </vl-string>\r\n </span>\r\n <div *ngIf=\"!formField.option.protected\">\r\n <div [ngStyle]=\"getFieldInnerLayoutStyle(formField)\">\r\n <vl-label [formField]=\"formField\" [modalItemInfo]=\"form\">\r\n </vl-label>\r\n\r\n <span>\r\n <p-autocomplete [suggestions]=\"remoteSuggestions[formField.scope?.reference] ?? []\" (completeMethod)=\"completeRemote($event, formField)\" #autocompleteField=\"ngModel\"\r\n [required]=\"formField.option.required\"\r\n [name]=\"formField.scope?.reference\"\r\n styleClass=\"custom-autocomplete\"\r\n [(ngModel)]=\"form.propertySchema[getScope(formField.scope?.reference)][formField.scope?.reference.split('/').pop()].value\"\r\n [style]=\"getStyleWithoutClasses(formField?.scope?.style).style\"\r\n [class]=\"formField?.scope?.style?.classes ? formField?.scope?.style?.classes[0] : ''\" [dropdown]=\"true\"\r\n [optionLabel]=\"formField.option.autocomplete.response.label\"\r\n [placeholder]=\"form.propertySchema | vlPlaceholder: formField.scope?.reference\"\r\n (ngModelChange)=\"autocompFocusOutEvent($event, formField)\"\r\n [vlCustomKeyboard]=\"formField?.option?.keyboardType ?? 'string'\">\r\n </p-autocomplete>\r\n <!-- Error Message -->\r\n <div\r\n *ngIf=\"autocompleteField?.touched && autocompleteField?.invalid\"\r\n [style]=\"getStyleWithoutClasses(formField?.validation?.style).style\">\r\n <p class=\"text-danger\"\r\n *ngIf=\"autocompleteField?.errors?.['required']\">\r\n {{setErroMessage(formField, errorMessages,\r\n \"required\")}}</p>\r\n <p class=\"text-danger\"\r\n *ngIf=\"autocompleteField?.errors?.['email']\">\r\n {{(formField.label?.value ?\r\n formField.label?.value :\r\n form.propertySchema[getScope(formField.scope?.reference)][formField.scope?.reference.split('/').pop()]?.caption)\r\n +\r\n ' ' + errorMessages.pattern}}</p>\r\n </div>\r\n </span>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- dropdown control -->\r\n <div *ngSwitchCase=\"'dropdown'\" class=\"form-group\"\r\n [ngClass]=\"getStyleWithoutClasses(formField?.scope?.style)?.classes\"\r\n [ngStyle]=\"getStyleWithoutClasses(formField?.scope?.style)?.style\">\r\n <span *ngIf=\"formField?.option?.postfixCaption\">\r\n <select id=\"dynamic-dropdown\" #dropdownField=\"ngModel\"\r\n [ngClass]=\"getStyleWithoutClasses(formField?.scope?.style)?.classes\"\r\n [ngStyle]=\"getStyleWithoutClasses(formField?.scope?.style)?.style\"\r\n [name]=\"formField.scope?.reference\"\r\n [(ngModel)]=\"\r\n form.propertySchema[getScope(formField.scope?.reference)][\r\n formField.scope?.reference.split('/').pop()\r\n ].value\r\n \">\r\n <option *ngFor=\"\r\n let item of form.propertySchema[getScope(formField.scope?.reference)]?.[\r\n formField.scope?.reference.split('/').pop()\r\n ]?.data\r\n \" [value]=\"item[formField?.option?.optionValue]\">\r\n {{ item[formField?.option?.optionLabel] }}\r\n </option>\r\n </select>\r\n\r\n <label\r\n [ngClass]=\"getStyleWithoutClasses(formField?.label?.style)?.classes\"\r\n [ngStyle]=\"getStyleWithoutClasses(formField?.label?.style)?.style\">\r\n {{\r\n form.propertySchema[getScope(formField.scope?.reference)]?.[\r\n formField.scope?.reference.split('/').pop()\r\n ]?.caption\r\n }}\r\n </label>\r\n </span>\r\n\r\n <div *ngIf=\"!formField?.option?.postfixCaption\">\r\n <div [ngStyle]=\"getFieldInnerLayoutStyle(formField)\">\r\n <label\r\n [ngClass]=\"getStyleWithoutClasses(formField?.label?.style)?.classes\"\r\n [ngStyle]=\"getStyleWithoutClasses(formField?.label?.style)?.style\">\r\n {{\r\n form.propertySchema[getScope(formField.scope?.reference)]?.[\r\n formField.scope?.reference.split('/').pop()\r\n ]?.caption\r\n }}\r\n </label>\r\n\r\n <nz-select nzShowSearch nzAllowClear nzPlaceHolder=\"Select\"\r\n #dropdownField=\"ngModel\"\r\n [required]=\"formField?.required\"\r\n [ngClass]=\"getStyleWithoutClasses(formField?.scope?.style)?.classes\"\r\n [ngStyle]=\"getStyleWithoutClasses(formField?.scope?.style)?.style\"\r\n [name]=\"formField.scope?.reference\" [(ngModel)]=\"\r\n form.propertySchema[getScope(formField.scope?.reference)][\r\n formField.scope?.reference.split('/').pop()\r\n ].value\r\n \">\r\n <nz-option *ngFor=\"\r\n let item of form.propertySchema[getScope(formField.scope?.reference)]?.[\r\n formField.scope?.reference.split('/').pop()\r\n ]?.data\r\n \" [nzLabel]=\"item[formField?.option?.optionLabel]\"\r\n [nzValue]=\"item[formField?.option?.optionValue]\"></nz-option>\r\n </nz-select>\r\n </div>\r\n\r\n <div *ngIf=\"dropdownField?.touched && dropdownField?.invalid\"\r\n [ngClass]=\"getStyleWithoutClasses(formField?.validation?.style)?.classes\"\r\n [ngStyle]=\"getStyleWithoutClasses(formField?.validation?.style)?.style\">\r\n <p [class]=\"\r\n formField?.layout === 'horizontal'\r\n ? 'text-red-400 m-0 horizontal-error'\r\n : 'text-red-400 m-0'\r\n \" *ngIf=\"dropdownField?.errors\">\r\n {{ setErroMessage(formField, errorMessages, dropdownField)\r\n }}\r\n </p>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- button/default control -->\r\n <div *ngSwitchCase=\"'default'\">\r\n <button type=\"submit\"\r\n [ngClass]=\"getStyleWithoutClasses(formField?.style)?.classes\"\r\n [ngStyle]=\"getStyleWithoutClasses(formField?.style)?.style\"\r\n (click)=\"invokeFormBtnClick(formField?.option, form.propertySchema)\">\r\n {{ formField?.label?.caption }}\r\n </button>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n </form>\r\n</div>\r\n\r\n<ng-template #formMediaContent let-field=\"field\">\r\n <ng-container *ngIf=\"getMediaSource(field) as source\">\r\n <ng-container [ngSwitch]=\"getMediaKind(field)\">\r\n <img *ngSwitchDefault [src]=\"source\" [alt]=\"getMediaLabel(field)\" loading=\"lazy\" />\r\n <video *ngSwitchCase=\"'video'\" [src]=\"source\"\r\n [attr.aria-label]=\"getMediaLabel(field)\" controls playsinline preload=\"metadata\">\r\n Your browser does not support video playback.\r\n </video>\r\n <audio *ngSwitchCase=\"'audio'\" [src]=\"source\"\r\n [attr.aria-label]=\"getMediaLabel(field)\" controls preload=\"metadata\">\r\n Your browser does not support audio playback.\r\n </audio>\r\n <a *ngSwitchCase=\"'pdf'\" [href]=\"source\" target=\"_blank\" rel=\"noopener noreferrer\">\r\n Open PDF \u2014 {{ getMediaLabel(field) }}\r\n </a>\r\n <a *ngSwitchCase=\"'file'\" [href]=\"source\" target=\"_blank\" rel=\"noopener noreferrer\">\r\n Open file \u2014 {{ getMediaLabel(field) }}\r\n </a>\r\n </ng-container>\r\n </ng-container>\r\n</ng-template>\r\n\r\n", styles: [":host{display:block;width:100%;height:100%;min-height:0}.form-renderer{width:100%;height:100%;min-height:0;overflow-y:auto;overflow-x:hidden;box-sizing:border-box;padding:12px}.section-card{border:1px solid #e5e7eb;border-radius:var(--radius-sm, 8px);padding:12px;margin-bottom:12px;background:#fff;box-sizing:border-box}.section-header{display:flex;align-items:center;justify-content:space-between;margin-bottom:10px;font-weight:600}.section-title{font-size:14px;color:#0f172a}.section-body{position:relative;width:100%;min-height:78px;box-sizing:border-box}.field-row{position:relative;min-width:0;width:100%;box-sizing:border-box}.field-row input,.field-row select,.field-row nz-select,.field-row textarea,.field-row button{max-width:100%;box-sizing:border-box}@media(max-width:768px){.section-body{grid-template-columns:repeat(1,minmax(0,1fr))!important}.field-row{grid-column:span 1!important}}@media(min-width:769px)and (max-width:1024px){.section-body{grid-template-columns:repeat(6,minmax(0,1fr))!important}.field-row{grid-column:span 6!important}}:host-context(.mobile-frame) .section-body,:host-context(.device-mobile) .section-body{grid-template-columns:repeat(1,minmax(0,1fr))!important}:host-context(.mobile-frame) .field-row,:host-context(.device-mobile) .field-row{grid-column:span 1!important}:host-context(.tablet-frame) .section-body,:host-context(.device-tablet) .section-body{grid-template-columns:repeat(6,minmax(0,1fr))!important}:host-context(.tablet-frame) .field-row,:host-context(.device-tablet) .field-row{grid-column:span 6!important}\n"] }]
4757
4915
  }], propDecorators: { errorMessages: [{
4758
4916
  type: Input
4759
4917
  }], creditCardError: [{
@@ -5276,8 +5434,82 @@ class GridComponent {
5276
5434
  return source.includes(search);
5277
5435
  }
5278
5436
  }
5437
+ isMediaColumn(col) {
5438
+ const reference = col?.scope?.reference;
5439
+ if (typeof reference !== 'string')
5440
+ return false;
5441
+ const key = reference.split('/').pop();
5442
+ const type = this.tableitemInfo?.propertySchema?.[this.getScope(reference)]?.[key]?.type;
5443
+ // Preserve existing image properties.
5444
+ return type === 'media' || type === 'image';
5445
+ }
5446
+ getMediaSource(col, data) {
5447
+ const key = col?.scope?.reference?.split('/').pop();
5448
+ const value = col?.option?.src || (key ? data?.[key] : '');
5449
+ return typeof value === 'string' ? value.trim() : '';
5450
+ }
5451
+ getMediaLabel(col) {
5452
+ if (typeof col?.label === 'string' && col.label.trim()) {
5453
+ return col.label;
5454
+ }
5455
+ const reference = col?.scope?.reference;
5456
+ const key = reference?.split('/').pop();
5457
+ const property = reference && key
5458
+ ? this.tableitemInfo?.propertySchema?.[this.getScope(reference)]?.[key]
5459
+ : undefined;
5460
+ return col?.label?.caption || property?.caption || 'Media';
5461
+ }
5462
+ getMediaKind(col, data) {
5463
+ const source = this.getMediaSource(col, data);
5464
+ const mime = /^data:([^;,]+)/i.exec(source)?.[1]?.toLowerCase();
5465
+ if (mime?.startsWith('image/'))
5466
+ return 'image';
5467
+ if (mime?.startsWith('video/'))
5468
+ return 'video';
5469
+ if (mime?.startsWith('audio/'))
5470
+ return 'audio';
5471
+ if (mime === 'application/pdf')
5472
+ return 'pdf';
5473
+ const key = col?.scope?.reference?.split('/').pop();
5474
+ const candidates = [
5475
+ source,
5476
+ col?.option?.fileName,
5477
+ key ? data?.[key] : undefined
5478
+ ];
5479
+ const videos = ['mp4', 'm4v', 'webm', 'mov', 'ogv', 'avi', 'mkv'];
5480
+ const audios = ['mp3', 'wav', 'ogg', 'oga', 'm4a', 'aac', 'flac', 'opus'];
5481
+ const files = [
5482
+ 'doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx',
5483
+ 'txt', 'csv', 'zip', 'rar', '7z'
5484
+ ];
5485
+ for (const candidate of candidates) {
5486
+ if (typeof candidate !== 'string')
5487
+ continue;
5488
+ if (/^(data|blob):/i.test(candidate))
5489
+ continue;
5490
+ let path = candidate.split(/[?#]/)[0];
5491
+ try {
5492
+ path = decodeURIComponent(path);
5493
+ }
5494
+ catch {
5495
+ // Keep the original path.
5496
+ }
5497
+ const extension = /\.([a-z0-9]+)$/i.exec(path)?.[1]?.toLowerCase();
5498
+ if (!extension)
5499
+ continue;
5500
+ if (videos.includes(extension))
5501
+ return 'video';
5502
+ if (audios.includes(extension))
5503
+ return 'audio';
5504
+ if (extension === 'pdf')
5505
+ return 'pdf';
5506
+ if (files.includes(extension))
5507
+ return 'file';
5508
+ }
5509
+ return 'image';
5510
+ }
5279
5511
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.2", ngImport: i0, type: GridComponent, deps: [{ token: RequestService }, { token: UtilityService }, { token: NotificationService }, { token: i4$1.OktaAuthStateService }], target: i0.ɵɵFactoryTarget.Component });
5280
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.2", type: GridComponent, isStandalone: true, selector: "vl-grid", inputs: { errorMessages: "errorMessages", environment: "environment", selectedLanguageInfo: "selectedLanguageInfo", tableitemInfo: "tableitemInfo", form: "form", isTableDataLoad: "isTableDataLoad", currenTableOptions: "currenTableOptions", projectSeleted: "projectSeleted", pageSize: "pageSize", currentPage: "currentPage", pages: "pages", userInfo: "userInfo" }, outputs: { onPageChange: "onPageChange", onPageSizeChange: "onPageSizeChange", onGridScroll: "onGridScroll", showGridLink: "showGridLink", gridButtonClick: "gridButtonClick", gridIncreamentClick: "gridIncreamentClick", gridDecreamentClick: "gridDecreamentClick", gridImgClick: "gridImgClick" }, usesOnChanges: true, ngImport: i0, template: "<!-- Faramarz Yousefian and Agent Toni (Claude Opus 5.5) 2026-10-13\r\n - new: autocompletes get their suggestions from RemoteListService (completeRemote) -->\r\n<!-- Faramarz Yousefian and Agent Toni (Claude Opus 5.5) 2026-10-13\r\n - fix: the placeholder comes from vlPlaceholder (pipes/placeholder.pipe.ts) - empty where the\r\n project defines none; it showed the text \"undefined\" -->\r\n<!-- Faramarz Yousefian and Agent Toni (Claude Opus 5) 2026-10-07\r\n - change: autocomplete fields take the toolkit string keyboard unless option.keyboardType\r\n names another one ('native' keeps the system keyboard)\r\n - change: date and time cells use the shared picker markup (picker-field, DateTimePickerService);\r\n their PrimeNG icon opened the calendar together with the system keyboard -->\r\n\r\n<!-- Shuaib 2026-09-24\r\n - change: grid cells render legacy checkbox fields through the boolean control. -->\r\n\r\n<!-- Faramarz Yousefian and Agent Toni (Claude Opus 5) 2026-09-19\r\n - new: @contract comments on the sorting, on the column filter and on the footer. The filter\r\n reads option.filter and never option.columnFilter, which is the mistake a layout author\r\n makes without being told -->\r\n<div *ngIf=\"!tableitemInfo.data?.length\" class=\"alert alert-warning col-md-12\"\r\n role=\"alert\">\r\n {{ tableitemInfo.layoutSchema?.noRecordMessage}}\r\n</div>\r\n<div *ngIf=\"tableitemInfo.data?.length\" class=\"reservation-container pt-5 px-3\">\r\n <nz-table #basicTable [nzData]=\"gridDisplayData\"\r\n [nzNoResult]=\"'No matching records found'\" [nzBordered]=\"true\"\r\n [nzFrontPagination]=\"currenTableOptions?.pagination?.tabs\"\r\n [style]=\"getStyleWithoutClasses(currenTableOptions?.style).style\"\r\n (scroll)=\"onScrollEvent($event)\"\r\n [nzLoading]=\"isTableDataLoad\">\r\n <thead>\r\n <!-- @contract decision: option.sortable is read here\r\n reality: nzSortFn is wired to getColumnSortFn since 2026-09-16; before that\r\n the key was decoration. The column also needs a scope.reference -\r\n without one getColumnSortFn has nothing to sort by.\r\n seen: grid.component.ts:338 -->\r\n <!-- Column headings and sorting -->\r\n <tr>\r\n <th *ngFor=\"let column of tableitemInfo.layoutSchema.elements\"\r\n [nzSortFn]=\"\r\n column?.option?.sortable\r\n ? getColumnSortFn(column)\r\n : false\r\n \">\r\n\r\n {{ column?.label?.caption }}\r\n </th>\r\n </tr>\r\n\r\n <!-- @contract decision: the column filter reads option.filter, NOT option.columnFilter\r\n reality: option.filter.filtering switches it on, option.filter.defaultOperator\r\n starts the comparison (the renderer falls back to contains), and\r\n option.filter.placeholder labels the input.\r\n failure: option.columnFilter is read nowhere, here or in the runtime app. A\r\n column carrying it looks filterable in the file and is not on screen.\r\n seen: grid.component.ts:450-475; 5 uses of columnFilter across the reference\r\n projects, all of them dead -->\r\n <!-- Column filters -->\r\n <tr *ngIf=\"hasAnyColumnFilter()\" class=\"grid-filter-row\">\r\n\r\n <th *ngFor=\"let column of tableitemInfo.layoutSchema.elements\"\r\n class=\"grid-filter-cell\">\r\n\r\n <ng-container *ngIf=\"\r\n column?.option?.filter?.filtering === true &&\r\n column?.scope?.reference\r\n \">\r\n\r\n <div class=\"grid-filter-input-wrapper\">\r\n <input type=\"text\" class=\"grid-filter-input\"\r\n [placeholder]=\"getColumnFilterPlaceholder(column)\"\r\n [ngModel]=\"getColumnFilterState(column).value\"\r\n (ngModelChange)=\"\r\n setColumnFilterValue(column, $event)\r\n \" />\r\n\r\n <!-- Operator selection button -->\r\n <button type=\"button\"\r\n class=\"grid-filter-operator-button\" nz-dropdown\r\n nzTrigger=\"click\"\r\n [nzDropdownMenu]=\"operatorMenu\"\r\n [class.grid-filter-operator-button--active]=\"\r\n hasActiveColumnFilter(column)\r\n \" [title]=\"\r\n 'Operator: ' +\r\n getFilterOperatorLabel(\r\n getColumnFilterState(column).operator\r\n )\r\n \">\r\n\r\n <span nz-icon nzType=\"filter\"></span>\r\n </button>\r\n\r\n <!-- Clear current column filter -->\r\n <button *ngIf=\"hasActiveColumnFilter(column)\"\r\n type=\"button\" class=\"grid-filter-clear-button\"\r\n aria-label=\"Clear column filter\"\r\n title=\"Clear filter\"\r\n (click)=\"clearColumnFilter(column)\">\r\n\r\n <span nz-icon nzType=\"close\"></span>\r\n </button>\r\n </div>\r\n\r\n <!-- Operator dropdown -->\r\n <nz-dropdown-menu #operatorMenu=\"nzDropdownMenu\">\r\n <ul nz-menu class=\"grid-filter-operator-menu\">\r\n <li *ngFor=\"let operator of filterOperators\"\r\n nz-menu-item [nzSelected]=\"\r\n getColumnFilterState(column).operator ===\r\n operator.value\r\n \" (click)=\"\r\n setColumnFilterOperator(\r\n column,\r\n operator.value\r\n )\r\n \">\r\n\r\n <span *ngIf=\"\r\n getColumnFilterState(column).operator ===\r\n operator.value\r\n \" nz-icon nzType=\"check\">\r\n </span>\r\n\r\n {{ operator.label }}\r\n </li>\r\n </ul>\r\n </nz-dropdown-menu>\r\n </ng-container>\r\n </th>\r\n </tr>\r\n </thead>\r\n <!-- @contract decision: the column chain below, and what it does not carry\r\n reality: string, number, image, quantity, date, time, dropdown, boolean,\r\n autocomplete and dateRange each have their own condition. There is no\r\n branch for the credit card type.\r\n failure: a column whose type has no branch stays empty, with no error.\r\n instead: format the value in the endpoint and send a string.\r\n\r\n @contract decision: columns without scope.reference are valid\r\n reality: with option.actionColumn they render save/delete icons, otherwise a\r\n button. That is why the conditions below all guard on the reference. -->\r\n <tbody>\r\n <tr *ngFor=\"let data of basicTable.data; let i = index\">\r\n <td *ngFor=\"let col of tableitemInfo.layoutSchema.elements\"\r\n [style]=\"getStyleWithoutClasses(col?.scope?.style).style\">\r\n <ng-container\r\n *ngIf=\"tableitemInfo.propertySchema[getScope(col.scope?.reference)] && tableitemInfo.propertySchema[getScope(col.scope?.reference)][col?.scope?.reference?.split('/').pop()]?.type === 'string'\"\r\n [class]=\"getStyleWithoutClasses(col?.scope?.style).classes\"\r\n [style]=\"getStyleWithoutClasses(col?.scope?.style).style\">\r\n <span *ngIf=\"col.option.protected\">\r\n <span *ngIf=\"col.option?.link\"\r\n (click)=\"showLinkDetails(col.option, data)\">\r\n {{data[col.scope?.reference.split('/').pop()]}}\r\n </span>\r\n <span *ngIf=\"!col.option?.link\">\r\n <ng-container\r\n *ngIf=\"col?.option?.dateFormat; else string\">\r\n {{\r\n data[col.scope?.reference.split('/').pop()]\r\n | date:'yyyy-MM-dd' }}\r\n </ng-container>\r\n <ng-template #string>\r\n {{\r\n data[col.scope?.reference.split('/').pop()]\r\n }}\r\n </ng-template>\r\n </span>\r\n </span>\r\n <span *ngIf=\"!col.option.protected\">\r\n <input\r\n [(ngModel)]=\"data[col.scope?.reference.split('/').pop()]\"\r\n class=\"p-inputtext p-component\" />\r\n </span>\r\n </ng-container>\r\n\r\n <ng-container\r\n *ngIf=\"tableitemInfo.propertySchema[getScope(col.scope?.reference)] && tableitemInfo.propertySchema[getScope(col.scope?.reference)][col?.scope?.reference?.split('/').pop()]?.type === 'number'\">\r\n <span *ngIf=\"col.option.protected\">\r\n <span\r\n *ngIf=\"col.option?.innerAction?.action == 'multiply'\">\r\n {{\r\n (data[col.option?.innerAction?.from] *\r\n data[col.option?.innerAction?.to])\r\n | number:'1.2-2'\r\n }}\r\n </span>\r\n <span *ngIf=\"!col.option?.innerAction\">\r\n {{data[col.scope?.reference.split('/').pop()] |\r\n currency:\r\n tableitemInfo.propertySchema[getScope(col.scope?.reference)][col?.scope?.reference?.split('/').pop()]?.currency\r\n :true }}\r\n </span>\r\n </span>\r\n <span *ngIf=\"!col.option.protected\">\r\n <input\r\n [(ngModel)]=\"data[col.scope?.reference.split('/').pop()]\"\r\n type=\"number\"\r\n class=\"p-inputtext p-component\" />\r\n </span>\r\n </ng-container>\r\n\r\n <ng-container\r\n *ngIf=\"tableitemInfo.propertySchema[getScope(col.scope?.reference)] && tableitemInfo.propertySchema[getScope(col.scope?.reference)][col?.scope?.reference?.split('/').pop()]?.type === 'image'\">\r\n <img *ngIf=\"data[col.scope?.reference.split('/').pop()]\"\r\n [src]=\"data[col.scope?.reference.split('/').pop()]\"\r\n alt=\"Image\"\r\n (click)=\"invokeTableImageClick(col, data)\"\r\n [style]=\"getStyleWithoutClasses(col?.scope?.style).style\" />\r\n </ng-container>\r\n\r\n <!-- @contract compatibility: existing checkbox fields render as boolean. -->\r\n <ng-container\r\n *ngIf=\"tableitemInfo.propertySchema[getScope(col.scope?.reference)] && (tableitemInfo.propertySchema[getScope(col.scope?.reference)][col?.scope?.reference?.split('/').pop()]?.type === 'boolean' || isLegacyCheckboxFieldType(tableitemInfo.propertySchema[getScope(col.scope?.reference)][col?.scope?.reference?.split('/').pop()]?.type))\">\r\n <input type=\"checkbox\"\r\n [style]=\"getStyleWithoutClasses(col?.scope?.style).style\"\r\n class=\"form-check-input mr-2\"\r\n [(ngModel)]=\"data[col.scope?.reference.split('/').pop()]\"\r\n [name]=\"col.scope?.reference\" />\r\n </ng-container>\r\n\r\n <ng-container\r\n *ngIf=\"tableitemInfo.propertySchema[getScope(col.scope?.reference)] && tableitemInfo.propertySchema[getScope(col.scope?.reference)][col?.scope?.reference?.split('/').pop()]?.type === 'dateRange'\">\r\n <nz-range-picker #dateRangeField=\"ngModel\"\r\n [required]=\"col.option.required\"\r\n [name]=\"col.scope?.reference\"\r\n [style]=\"getStyleWithoutClasses(col?.style).style\"\r\n [(ngModel)]=\"tableitemInfo.propertySchema[getScope(col.scope?.reference)][col.scope?.reference.split('/').pop()].value\"></nz-range-picker>\r\n </ng-container>\r\n\r\n <ng-container\r\n *ngIf=\"tableitemInfo.propertySchema[getScope(col.scope?.reference)] && tableitemInfo.propertySchema[getScope(col.scope?.reference)][col?.scope?.reference?.split('/').pop()]?.type === 'date'\">\r\n <div class=\"picker-field\">\r\n <p-datepicker #datePicker #dateField=\"ngModel\"\r\n styleClass=\"custom-datepicker\"\r\n [required]=\"col.option.required\"\r\n [name]=\"col.scope?.reference\"\r\n [disabled]=\"col?.option?.disabled\"\r\n [autoZIndex]=\"true\" [baseZIndex]=\"10000\"\r\n [dateFormat]=\"\r\n tableitemInfo.propertySchema[\r\n getScope(col.scope?.reference)\r\n ][\r\n col.scope?.reference.split('/').pop()\r\n ]?.format || 'yy-mm-dd'\r\n \" [(ngModel)]=\"\r\n form.propertySchema[\r\n getScope(col.scope?.reference)\r\n ][\r\n col.scope?.reference.split('/').pop()\r\n ].value\r\n \" [class]=\"col?.scope?.style?.classes?.[0] || ''\"\r\n [style]=\"getStyleWithoutClasses(col?.scope?.style).style\"\r\n [showIcon]=\"false\" [showOnFocus]=\"false\" appendTo=\"body\"\r\n [panelStyleClass]=\"picker.datePanelClass\" [motionOptions]=\"picker.dockedMotion\"\r\n [vlCustomKeyboard]=\"col?.option?.keyboardType ?? 'date'\"\r\n (pointerdown)=\"picker.onFieldPointerDown($event, datePicker)\"\r\n (onFocus)=\"picker.onFieldFocus($event)\"\r\n (onShow)=\"picker.onShown()\"\r\n (onClose)=\"picker.onClose(datePicker)\">\r\n </p-datepicker>\r\n <button type=\"button\" class=\"picker-field__icon\" aria-label=\"Open calendar\"\r\n (pointerdown)=\"picker.openFromIcon($event, datePicker)\"\r\n (click)=\"picker.blockIconClick($event)\">\r\n <i class=\"pi pi-calendar\"></i>\r\n </button>\r\n </div>\r\n </ng-container>\r\n\r\n <ng-container\r\n *ngIf=\"tableitemInfo.propertySchema[getScope(col.scope?.reference)] && tableitemInfo.propertySchema[getScope(col.scope?.reference)][col?.scope?.reference?.split('/').pop()]?.type === 'time'\">\r\n <div class=\"picker-field\">\r\n <p-datepicker #timePicker #timeField=\"ngModel\"\r\n styleClass=\"custom-datepicker\"\r\n [required]=\"col.option.required\"\r\n [name]=\"col.scope?.reference\" [timeOnly]=\"true\"\r\n hourFormat=\"24\" [disabled]=\"col?.option?.disabled\" [autoZIndex]=\"true\"\r\n [baseZIndex]=\"10000\"\r\n [style]=\"getStyleWithoutClasses(col?.scope?.style).style\"\r\n [(ngModel)]=\"\r\n form.propertySchema[\r\n getScope(col.scope?.reference)\r\n ][\r\n col.scope?.reference.split('/').pop()\r\n ].value\r\n \"\r\n [class]=\"col?.scope?.style?.classes?.[0] || ''\"\r\n [showIcon]=\"false\" [showOnFocus]=\"false\" appendTo=\"body\"\r\n [panelStyleClass]=\"picker.timePanelClass\"\r\n [vlCustomKeyboard]=\"col?.option?.keyboardType ?? 'time'\"\r\n (pointerdown)=\"picker.onFieldPointerDown($event, timePicker)\"\r\n (onFocus)=\"picker.onFieldFocus($event)\"\r\n (onShow)=\"picker.onShown()\"\r\n (onClose)=\"picker.onClose(timePicker)\">\r\n </p-datepicker>\r\n <button type=\"button\" class=\"picker-field__icon\" aria-label=\"Open time picker\"\r\n (pointerdown)=\"picker.openFromIcon($event, timePicker)\"\r\n (click)=\"picker.blockIconClick($event)\">\r\n <i class=\"pi pi-clock\"></i>\r\n </button>\r\n </div>\r\n </ng-container>\r\n\r\n <ng-container\r\n *ngIf=\"tableitemInfo.propertySchema[getScope(col.scope?.reference)] && tableitemInfo.propertySchema[getScope(col.scope?.reference)][col?.scope?.reference?.split('/').pop()]?.type === 'autocomplete'\">\r\n <p-autocomplete [suggestions]=\"remoteSuggestions[col.scope?.reference] ?? []\" (completeMethod)=\"completeRemote($event, col)\" #autocompleteField=\"ngModel\"\r\n [required]=\"col.option.required\"\r\n [name]=\"col.scope?.reference\"\r\n styleClass=\"custom-autocomplete\"\r\n [(ngModel)]=\"form.propertySchema[getScope(col.scope?.reference)][col.scope?.reference.split('/').pop()].value\"\r\n [style]=\"getStyleWithoutClasses(col?.scope?.style).style\"\r\n [class]=\"col?.scope?.style?.classes ? col?.scope?.style?.classes[0] : ''\"\r\n [dropdown]=\"true\"\r\n [optionLabel]=\"col.option.autocomplete.response.label\"\r\n [placeholder]=\"form.propertySchema | vlPlaceholder: col.scope?.reference\"\r\n [vlCustomKeyboard]=\"col?.option?.keyboardType ?? 'string'\">\r\n </p-autocomplete>\r\n </ng-container>\r\n\r\n <ng-container\r\n *ngIf=\"tableitemInfo.propertySchema[getScope(col.scope?.reference)] && tableitemInfo.propertySchema[getScope(col.scope?.reference)][col?.scope?.reference?.split('/').pop()]?.type === 'dropdown'\">\r\n <select id=\"dynamic-dropdown\" #dropdownField=\"ngModel\"\r\n [ngClass]=\"getStyleWithoutClasses(col?.scope?.style)?.classes\"\r\n [ngStyle]=\"getStyleWithoutClasses(col?.scope?.style)?.style\"\r\n [name]=\"col.scope?.reference\"\r\n [(ngModel)]=\"\r\n form.propertySchema[getScope(col.scope?.reference)][\r\n col.scope?.reference.split('/').pop()\r\n ].value\r\n \">\r\n <option *ngFor=\"\r\n let item of form.propertySchema[getScope(col.scope?.reference)]?.[\r\n col.scope?.reference.split('/').pop()\r\n ]?.data\r\n \" [value]=\"item[col?.option?.optionValue]\">\r\n {{ item[col?.option?.optionLabel] }}\r\n </option>\r\n </select>\r\n </ng-container>\r\n\r\n <ng-container *ngIf=\"!col?.scope?.reference\">\r\n <span *ngIf=\"col.option?.actionColumn\">\r\n <span nz-icon\r\n *ngIf=\"setActionColumn(col.option?.save, data)\"\r\n [nzType]=\"col.option?.save?.icon\"\r\n [nzTheme]=\"'twotone'\"\r\n [style]=\"col.option?.save?.style\"\r\n [nzTwotoneColor]=\"'#52c41a'\"\r\n [class]=\"col.option?.save?.style?.classes[0]\"\r\n (click)=\"upsertAction(col.option?.save, data)\">\r\n </span>\r\n <span nz-icon\r\n *ngIf=\"setActionColumn(col.option?.delete, data)\"\r\n [nzType]=\"col.option?.delete?.icon\"\r\n [nzTheme]=\"'twotone'\"\r\n [style]=\"col.option?.delete?.style\"\r\n [nzTwotoneColor]=\"'#FF0000'\"\r\n [class]=\"col.option?.delete?.style?.classes[0]\"\r\n (click)=\"upsertAction(col.option?.delete, data)\"></span>\r\n\r\n </span>\r\n <span *ngIf=\"!col.option?.actionColumn\">\r\n <button type=\"submit\"\r\n [style]=\"getStyleWithoutClasses(col?.label?.style).style\"\r\n (click)=\"invokeGridBtnClick(col.option, data)\"\r\n [class]=\"col?.label?.style?.classes[0]\">\r\n {{ col.label?.caption }}\r\n </button>\r\n </span>\r\n </ng-container>\r\n\r\n <!-- For quantity column, display increment/decrement buttons -->\r\n <ng-container\r\n *ngIf=\"tableitemInfo.propertySchema[getScope(col.scope?.reference)] && tableitemInfo.propertySchema[getScope(col.scope?.reference)][col?.scope?.reference?.split('/').pop()]?.type === 'quantity'\">\r\n <div style=\"display: flex; align-items: center;\">\r\n <button pButton icon=\"pi pi-minus\"\r\n (click)=\"decrementQuantity(i,col.scope?.reference.split('/').pop(), col.option)\"\r\n [disabled]=\"data.quantity <= 0\"\r\n style=\"margin-right: 8px; height: 10px; width: 10px;\"></button>\r\n <span>{{ data[col.scope?.reference.split('/').pop()]\r\n }}</span>\r\n <button pButton icon=\"pi pi-plus\"\r\n (click)=\"incrementQuantity(i, col.scope?.reference.split('/').pop(), col.option)\"\r\n style=\"margin-left: 8px; height: 10px; width: 10px;\"></button>\r\n </div>\r\n </ng-container>\r\n </td>\r\n </tr>\r\n </tbody>\r\n </nz-table>\r\n</div>\r\n\r\n<!-- table footer -->\r\n<div *ngIf=\"tableitemInfo?.footer?.formFields && tableitemInfo.data?.length\"\r\n class=\"table-footer flex flex-column align-items-end gap-2 pt-2 mx-4 border-top-1 border-cyan-500\">\r\n <!-- @contract decision: the footer renders string and number only\r\n reality: the switch below carries those two cases and a default. It did NOT change\r\n when the columns gained their types on 2026-09-18.\r\n failure: any other type in a footer field renders empty.\r\n instead: keep aggregates numeric, or pre-format them as text in the endpoint. -->\r\n <div *ngFor=\"let tableField of tableitemInfo?.footer?.formFields\">\r\n <div\r\n [ngSwitch]=\"tableField?.scope?.reference && tableitemInfo.propertySchema[getScope(tableField.scope?.reference)] && tableitemInfo.propertySchema[getScope(tableField.scope?.reference)][tableField.scope?.reference.split('/').pop()] ?\r\n tableitemInfo.propertySchema[getScope(tableField.scope?.reference)][tableField.scope?.reference.split('/').pop()]?.type : 'default'\">\r\n\r\n <!-- string control -->\r\n <div *ngSwitchCase=\"'string'\" class=\"form-group\">\r\n <span *ngIf=\"tableField.option.protected\">\r\n <h5 style=\"display: flex; justify-content: space-between;\">\r\n <span\r\n [style]=\"getStyleWithoutClasses(tableField?.label?.style).style\"\r\n [class]=\"tableField?.label?.style?.classes[0]\">\r\n {{\r\n tableitemInfo.propertySchema[getScope(tableField.scope?.reference)][tableField.scope?.reference.split('/').pop()]?.caption\r\n }}\r\n </span>\r\n <span>\r\n {{\r\n tableitemInfo.propertySchema[getScope(tableField.scope?.reference)][tableField.scope?.reference.split('/').pop()]?.value\r\n }}\r\n </span>\r\n </h5>\r\n </span>\r\n <div *ngIf=\"!tableField.option.protected\">\r\n <div\r\n [class]=\"tableField?.layout == 'horizontal' ? 'horizontal-layout' : 'row'\">\r\n <label\r\n [style]=\"getStyleWithoutClasses(tableField?.label?.style).style\"\r\n [class]=\"tableField?.label?.style?.classes[0]\">{{\r\n tableField.label?.value ?\r\n tableField.label?.value :\r\n tableitemInfo.propertySchema[getScope(tableField.scope?.reference)][tableField.scope?.reference.split('/').pop()]?.caption\r\n }}</label>\r\n <input type=\"text\" #inputField=\"ngModel\"\r\n [required]=\"tableField.option.required\"\r\n [email]=\"tableField.option.email\"\r\n [class]=\"tableField.scope?.style?.classes[0]\"\r\n [style]=\"getStyleWithoutClasses(tableField?.scope?.style).style\"\r\n [(ngModel)]=\"tableitemInfo.propertySchema[getScope(tableField.scope?.reference)][tableField.scope?.reference.split('/').pop()].value\"\r\n [name]=\"tableField.scope?.reference\"\r\n [placeholder]=\"tableitemInfo.propertySchema | vlPlaceholder: tableField.scope?.reference\" />\r\n </div>\r\n <!-- Error Message -->\r\n <div *ngIf=\"inputField?.touched && inputField?.invalid\"\r\n [style]=\"getStyleWithoutClasses(tableField?.validation?.style).style\">\r\n <p class=\"text-danger\"\r\n *ngIf=\"inputField?.errors?.['required']\">{{tableField.label?.value\r\n ?\r\n tableField.label?.value :\r\n tableitemInfo.propertySchema[getScope(tableField.scope?.reference)][tableField.scope?.reference.split('/').pop()]?.caption\r\n +\r\n ' ' + errorMessages.required}}</p>\r\n <p class=\"text-danger\"\r\n *ngIf=\"inputField?.errors?.['email']\">{{(tableField.label?.value\r\n ?\r\n tableField.label?.value :\r\n tableitemInfo.propertySchema[getScope(tableField.scope?.reference)][tableField.scope?.reference.split('/').pop()]?.caption)\r\n +\r\n ' ' + errorMessages.pattern}}</p>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- number control -->\r\n <div *ngSwitchCase=\"'number'\" class=\"form-group\">\r\n <span *ngIf=\"tableField.option.protected\"\r\n [style]=\"getStyleWithoutClasses(tableField?.label?.style).style\"\r\n [class]=\"tableField?.label?.style?.classes[0]\">\r\n <h5>{{\r\n form.propertySchema[getScope(tableField.scope?.reference)][tableField.scope?.reference.split('/').pop()]?.caption\r\n }} {{\r\n form.propertySchema[getScope(tableField.scope?.reference)][tableField.scope?.reference.split('/').pop()]?.value\r\n |\r\n currency:tableField.option.currency :true:\r\n tableField.option?.decimalPoint}}\r\n </h5>\r\n </span>\r\n <span *ngIf=\"!tableField.option.protected\">\r\n <div\r\n [class]=\"tableField?.layout == 'horizontal' ? 'horizontal-layout' : 'row'\">\r\n <label\r\n [style]=\"getStyleWithoutClasses(tableField?.label?.style).style\"\r\n [class]=\"tableField?.label?.style?.classes[0]\">{{\r\n tableField.label?.value ?\r\n tableField.label?.value :\r\n form.propertySchema[getScope(tableField.scope?.reference)][tableField.scope?.reference.split('/').pop()]?.caption\r\n }}</label>\r\n <input type=\"number\"\r\n [class]=\"tableField.scope?.style?.classes[0]\"\r\n [style]=\"getStyleWithoutClasses(tableField?.scope?.style).style\"\r\n [(ngModel)]=\"form.propertySchema[getScope(tableField.scope?.reference)][tableField.scope?.reference.split('/').pop()].value\"\r\n [name]=\"tableField.scope?.reference\"\r\n [placeholder]=\"form.propertySchema | vlPlaceholder: tableField.scope?.reference\" />\r\n </div>\r\n </span>\r\n </div>\r\n\r\n <!-- button control -->\r\n <div *ngSwitchCase=\"'default'\">\r\n <button type=\"submit\"\r\n [style]=\"getStyleWithoutClasses(tableField.label.style).style\"\r\n (click)=\"invokeGridBtnClick(tableField.option, tableitemInfo.propertySchema)\">\r\n {{ tableField.label?.caption }}\r\n </button>\r\n </div>\r\n </div>\r\n </div>\r\n</div>\r\n\r\n<!-- bottom pagination on grid -->\r\n<div\r\n *ngIf=\"tableitemInfo.data?.length && !tableitemInfo?.layoutSchema?.pagination?.top && tableitemInfo?.layoutSchema?.pagination?.bottom\">\r\n <vl-pagination [itemInfo]=\"tableitemInfo\" [pageSize]=\"pageSize\"\r\n [currentPage]=\"currentPage\" [pages]=\"pages\"\r\n (pageSizeChange)=\"invokeOnPageSizeChange($event)\"\r\n (onGoToPage)=\"invokeGoToPage($event)\">\r\n </vl-pagination>\r\n</div>\r\n", styles: [".grid-filter-row th{padding:8px;vertical-align:middle;background:#fafafa}.grid-filter-cell{min-width:150px}.grid-filter-input-wrapper{display:flex;align-items:stretch;width:100%}.grid-filter-input{width:100%;min-width:0;min-height:34px;padding:5px 8px;border:1px solid #d9d9d9;border-right:0;border-radius:4px 0 0 4px;outline:none}.grid-filter-input:focus{border-color:#1677ff}.grid-filter-operator-button,.grid-filter-clear-button{display:inline-flex;align-items:center;justify-content:center;min-width:36px;min-height:34px;padding:0;cursor:pointer;background:#fff;border:1px solid #d9d9d9}.grid-filter-operator-button{color:#595959;border-radius:0 4px 4px 0}.grid-filter-operator-button:hover,.grid-filter-operator-button--active{color:#1677ff;border-color:#1677ff}.grid-filter-clear-button{margin-left:5px;color:#ff4d4f;border-radius:4px}.grid-filter-clear-button:hover{color:#fff;background:#ff4d4f;border-color:#ff4d4f}.grid-filter-operator-menu{min-width:190px}:host ::ng-deep .ant-table-content.has-more-right{-webkit-mask-image:linear-gradient(to right,#000 calc(100% - 36px),transparent);mask-image:linear-gradient(to right,#000 calc(100% - 36px),transparent)}:host ::ng-deep .ant-table-content.has-more-left{-webkit-mask-image:linear-gradient(to left,#000 calc(100% - 36px),transparent);mask-image:linear-gradient(to left,#000 calc(100% - 36px),transparent)}:host ::ng-deep .ant-table-content.has-more-left.has-more-right{-webkit-mask-image:linear-gradient(to right,transparent,#000 36px,#000 calc(100% - 36px),transparent);mask-image:linear-gradient(to right,transparent,#000 36px,#000 calc(100% - 36px),transparent)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i5.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i5.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i5.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i5.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "directive", type: i5.NgSwitch, selector: "[ngSwitch]", inputs: ["ngSwitch"] }, { kind: "directive", type: i5.NgSwitchCase, selector: "[ngSwitchCase]", inputs: ["ngSwitchCase"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i2.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { kind: "directive", type: i2.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { kind: "directive", type: i2.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i2.EmailValidator, selector: "[email][formControlName],[email][formControl],[email][ngModel]", inputs: ["email"] }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: NzTableModule }, { kind: "component", type: i7$1.NzTableComponent, selector: "nz-table", inputs: ["nzTableLayout", "nzShowTotal", "nzItemRender", "nzTitle", "nzFooter", "nzNoResult", "nzPageSizeOptions", "nzVirtualItemSize", "nzVirtualMaxBufferPx", "nzVirtualMinBufferPx", "nzVirtualForTrackBy", "nzLoadingDelay", "nzPageIndex", "nzPageSize", "nzTotal", "nzWidthConfig", "nzData", "nzCustomColumn", "nzPaginationPosition", "nzScroll", "noDataVirtualHeight", "nzPaginationType", "nzFrontPagination", "nzTemplateMode", "nzShowPagination", "nzLoading", "nzOuterBordered", "nzLoadingIndicator", "nzBordered", "nzSize", "nzShowSizeChanger", "nzHideOnSinglePage", "nzShowQuickJumper", "nzSimple"], outputs: ["nzPageSizeChange", "nzPageIndexChange", "nzQueryParams", "nzCurrentPageDataChange", "nzCustomColumnChange"], exportAs: ["nzTable"] }, { kind: "component", type: i7$1.NzThAddOnComponent, selector: "th[nzColumnKey], th[nzSortFn], th[nzSortOrder], th[nzFilters], th[nzShowSort], th[nzShowFilter], th[nzCustomFilter]", inputs: ["nzColumnKey", "nzFilterMultiple", "nzSortOrder", "nzSortPriority", "nzSortDirections", "nzFilters", "nzSortFn", "nzFilterFn", "nzShowSort", "nzShowFilter", "nzCustomFilter"], outputs: ["nzCheckedChange", "nzSortOrderChange", "nzFilterChange"] }, { kind: "directive", type: i7$1.NzTableCellDirective, selector: "th:not(.nz-disable-th), td:not(.nz-disable-td)" }, { kind: "directive", type: i7$1.NzThMeasureDirective, selector: "th", inputs: ["nzWidth", "colspan", "colSpan", "rowspan", "rowSpan"] }, { kind: "component", type: i7$1.NzTheadComponent, selector: "thead:not(.ant-table-thead)", outputs: ["nzSortOrderChange"] }, { kind: "component", type: i7$1.NzTbodyComponent, selector: "tbody" }, { kind: "directive", type: i7$1.NzTrDirective, selector: "tr:not([nz-table-measure-row]):not([nzExpand]):not([nz-table-fixed-row])" }, { kind: "ngmodule", type: NzIconModule }, { kind: "directive", type: i11.NzIconDirective, selector: "nz-icon,[nz-icon]", inputs: ["nzSpin", "nzRotate", "nzType", "nzTheme", "nzTwotoneColor", "nzIconfont"], exportAs: ["nzIcon"] }, { kind: "ngmodule", type: ButtonModule }, { kind: "directive", type: i9.ButtonDirective, selector: "[pButton]", inputs: ["ptButtonDirective", "pButtonPT", "pButtonUnstyled", "hostName", "text", "plain", "raised", "size", "outlined", "rounded", "iconPos", "loadingIcon", "fluid", "label", "icon", "loading", "buttonProps", "severity"] }, { kind: "ngmodule", type: NzDropDownModule }, { kind: "directive", type: i11$1.NzMenuDirective, selector: "[nz-menu]", inputs: ["nzInlineIndent", "nzTheme", "nzMode", "nzInlineCollapsed", "nzSelectable"], outputs: ["nzClick"], exportAs: ["nzMenu"] }, { kind: "component", type: i11$1.NzMenuItemComponent, selector: "[nz-menu-item]", inputs: ["nzPaddingLeft", "nzDisabled", "nzSelected", "nzDanger", "nzMatchRouterExact", "nzMatchRouter"], exportAs: ["nzMenuItem"] }, { kind: "directive", type: i11$2.NzDropdownDirective, selector: "[nz-dropdown]", inputs: ["nzDropdownMenu", "nzTrigger", "nzMatchWidthElement", "nzBackdrop", "nzClickHide", "nzDisabled", "nzVisible", "nzArrow", "nzOverlayClassName", "nzOverlayStyle", "nzPlacement"], outputs: ["nzVisibleChange"], exportAs: ["nzDropdown"] }, { kind: "component", type: i11$2.NzDropdownMenuComponent, selector: "nz-dropdown-menu", exportAs: ["nzDropdownMenu"] }, { kind: "ngmodule", type: NzMenuModule }, { kind: "component", type: PaginationComponent, selector: "vl-pagination", inputs: ["itemInfo", "pageSize", "currentPage", "selectedLanguageInfo", "pages"], outputs: ["pageSizeChange", "onGoToPage"] }, { kind: "ngmodule", type: NzDatePickerModule }, { kind: "component", type: i4.NzDatePickerComponent, selector: "nz-date-picker,nz-week-picker,nz-month-picker,nz-quarter-picker,nz-year-picker,nz-range-picker", inputs: ["nzInline", "nzAllowClear", "nzAutoFocus", "nzDisabled", "nzInputReadOnly", "nzOpen", "nzDisabledDate", "nzLocale", "nzPlaceHolder", "nzPopupStyle", "nzDropdownClassName", "nzSize", "nzStatus", "nzFormat", "nzVariant", "nzDateRender", "nzDisabledTime", "nzRenderExtraFooter", "nzShowToday", "nzMode", "nzShowNow", "nzRanges", "nzDefaultPickerValue", "nzSeparator", "nzSuffixIcon", "nzBackdrop", "nzId", "nzPlacement", "nzShowWeekNumber", "nzShowTime"], outputs: ["nzOnPanelChange", "nzOnCalendarChange", "nzOnOk", "nzOnOpenChange"], exportAs: ["nzDatePicker"] }, { kind: "directive", type: i4.NzRangePickerComponent, selector: "nz-range-picker", exportAs: ["nzRangePicker"] }, { kind: "ngmodule", type: DatePickerModule }, { kind: "component", type: i12.DatePicker, selector: "p-datePicker, p-datepicker, p-date-picker", inputs: ["iconDisplay", "styleClass", "inputStyle", "inputId", "inputStyleClass", "placeholder", "ariaLabelledBy", "ariaLabel", "iconAriaLabel", "dateFormat", "multipleSeparator", "rangeSeparator", "inline", "showOtherMonths", "selectOtherMonths", "showIcon", "icon", "readonlyInput", "shortYearCutoff", "hourFormat", "timeOnly", "stepHour", "stepMinute", "stepSecond", "showSeconds", "showOnFocus", "showWeek", "startWeekFromFirstDayOfYear", "showClear", "dataType", "selectionMode", "maxDateCount", "showButtonBar", "todayButtonStyleClass", "clearButtonStyleClass", "autofocus", "autoZIndex", "baseZIndex", "panelStyleClass", "panelStyle", "keepInvalid", "hideOnDateTimeSelect", "touchUI", "timeSeparator", "focusTrap", "showTransitionOptions", "hideTransitionOptions", "tabindex", "minDate", "maxDate", "disabledDates", "disabledDays", "showTime", "responsiveOptions", "numberOfMonths", "firstDayOfWeek", "view", "defaultDate", "appendTo", "motionOptions"], outputs: ["onFocus", "onBlur", "onClose", "onSelect", "onClear", "onInput", "onTodayClick", "onClearClick", "onMonthChange", "onYearChange", "onClickOutside", "onShow"] }, { kind: "ngmodule", type: AutoCompleteModule }, { kind: "component", type: i18.AutoComplete, selector: "p-autoComplete, p-autocomplete, p-auto-complete", inputs: ["minLength", "minQueryLength", "delay", "panelStyle", "styleClass", "panelStyleClass", "inputStyle", "inputId", "inputStyleClass", "placeholder", "readonly", "scrollHeight", "lazy", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "autoHighlight", "forceSelection", "type", "autoZIndex", "baseZIndex", "ariaLabel", "dropdownAriaLabel", "ariaLabelledBy", "dropdownIcon", "unique", "group", "completeOnFocus", "showClear", "dropdown", "showEmptyMessage", "dropdownMode", "multiple", "addOnTab", "tabindex", "dataKey", "emptyMessage", "showTransitionOptions", "hideTransitionOptions", "autofocus", "autocomplete", "optionGroupChildren", "optionGroupLabel", "overlayOptions", "suggestions", "optionLabel", "optionValue", "id", "searchMessage", "emptySelectionMessage", "selectionMessage", "autoOptionFocus", "selectOnFocus", "searchLocale", "optionDisabled", "focusOnHover", "typeahead", "addOnBlur", "separator", "appendTo", "motionOptions"], outputs: ["completeMethod", "onSelect", "onUnselect", "onAdd", "onFocus", "onBlur", "onDropdownClick", "onClear", "onInputKeydown", "onKeyUp", "onShow", "onHide", "onLazyLoad"] }, { kind: "ngmodule", type: InputTextModule }, { kind: "directive", type: CustomKeyboardDirective, selector: "[vlCustomKeyboard]", inputs: ["vlCustomKeyboard"] }, { kind: "pipe", type: PlaceholderPipe, name: "vlPlaceholder" }, { kind: "pipe", type: i5.DecimalPipe, name: "number" }, { kind: "pipe", type: i5.CurrencyPipe, name: "currency" }, { kind: "pipe", type: i5.DatePipe, name: "date" }] });
5512
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.2", type: GridComponent, isStandalone: true, selector: "vl-grid", inputs: { errorMessages: "errorMessages", environment: "environment", selectedLanguageInfo: "selectedLanguageInfo", tableitemInfo: "tableitemInfo", form: "form", isTableDataLoad: "isTableDataLoad", currenTableOptions: "currenTableOptions", projectSeleted: "projectSeleted", pageSize: "pageSize", currentPage: "currentPage", pages: "pages", userInfo: "userInfo" }, outputs: { onPageChange: "onPageChange", onPageSizeChange: "onPageSizeChange", onGridScroll: "onGridScroll", showGridLink: "showGridLink", gridButtonClick: "gridButtonClick", gridIncreamentClick: "gridIncreamentClick", gridDecreamentClick: "gridDecreamentClick", gridImgClick: "gridImgClick" }, usesOnChanges: true, ngImport: i0, template: "<!-- Faramarz Yousefian and Agent Toni (Claude Opus 5.5) 2026-10-13\r\n - new: autocompletes get their suggestions from RemoteListService (completeRemote) -->\r\n<!-- Faramarz Yousefian and Agent Toni (Claude Opus 5.5) 2026-10-13\r\n - fix: the placeholder comes from vlPlaceholder (pipes/placeholder.pipe.ts) - empty where the\r\n project defines none; it showed the text \"undefined\" -->\r\n<!-- Faramarz Yousefian and Agent Toni (Claude Opus 5) 2026-10-07\r\n - change: autocomplete fields take the toolkit string keyboard unless option.keyboardType\r\n names another one ('native' keeps the system keyboard)\r\n - change: date and time cells use the shared picker markup (picker-field, DateTimePickerService);\r\n their PrimeNG icon opened the calendar together with the system keyboard -->\r\n\r\n<!-- Shuaib 2026-09-24\r\n - change: grid cells render legacy checkbox fields through the boolean control. -->\r\n\r\n<!-- Faramarz Yousefian and Agent Toni (Claude Opus 5) 2026-09-19\r\n - new: @contract comments on the sorting, on the column filter and on the footer. The filter\r\n reads option.filter and never option.columnFilter, which is the mistake a layout author\r\n makes without being told -->\r\n<div *ngIf=\"!tableitemInfo.data?.length\" class=\"alert alert-warning col-md-12\"\r\n role=\"alert\">\r\n {{ tableitemInfo.layoutSchema?.noRecordMessage}}\r\n</div>\r\n<div *ngIf=\"tableitemInfo.data?.length\" class=\"reservation-container pt-5 px-3\">\r\n <nz-table #basicTable [nzData]=\"gridDisplayData\"\r\n [nzNoResult]=\"'No matching records found'\" [nzBordered]=\"true\"\r\n [nzFrontPagination]=\"currenTableOptions?.pagination?.tabs\"\r\n [style]=\"getStyleWithoutClasses(currenTableOptions?.style).style\"\r\n (scroll)=\"onScrollEvent($event)\"\r\n [nzLoading]=\"isTableDataLoad\">\r\n <thead>\r\n <!-- @contract decision: option.sortable is read here\r\n reality: nzSortFn is wired to getColumnSortFn since 2026-09-16; before that\r\n the key was decoration. The column also needs a scope.reference -\r\n without one getColumnSortFn has nothing to sort by.\r\n seen: grid.component.ts:338 -->\r\n <!-- Column headings and sorting -->\r\n <tr>\r\n <th *ngFor=\"let column of tableitemInfo.layoutSchema.elements\"\r\n [nzSortFn]=\"\r\n column?.option?.sortable\r\n ? getColumnSortFn(column)\r\n : false\r\n \">\r\n\r\n {{ column?.label?.caption }}\r\n </th>\r\n </tr>\r\n\r\n <!-- @contract decision: the column filter reads option.filter, NOT option.columnFilter\r\n reality: option.filter.filtering switches it on, option.filter.defaultOperator\r\n starts the comparison (the renderer falls back to contains), and\r\n option.filter.placeholder labels the input.\r\n failure: option.columnFilter is read nowhere, here or in the runtime app. A\r\n column carrying it looks filterable in the file and is not on screen.\r\n seen: grid.component.ts:450-475; 5 uses of columnFilter across the reference\r\n projects, all of them dead -->\r\n <!-- Column filters -->\r\n <tr *ngIf=\"hasAnyColumnFilter()\" class=\"grid-filter-row\">\r\n\r\n <th *ngFor=\"let column of tableitemInfo.layoutSchema.elements\"\r\n class=\"grid-filter-cell\">\r\n\r\n <ng-container *ngIf=\"\r\n column?.option?.filter?.filtering === true &&\r\n column?.scope?.reference\r\n \">\r\n\r\n <div class=\"grid-filter-input-wrapper\">\r\n <input type=\"text\" class=\"grid-filter-input\"\r\n [placeholder]=\"getColumnFilterPlaceholder(column)\"\r\n [ngModel]=\"getColumnFilterState(column).value\"\r\n (ngModelChange)=\"\r\n setColumnFilterValue(column, $event)\r\n \" />\r\n\r\n <!-- Operator selection button -->\r\n <button type=\"button\"\r\n class=\"grid-filter-operator-button\" nz-dropdown\r\n nzTrigger=\"click\"\r\n [nzDropdownMenu]=\"operatorMenu\"\r\n [class.grid-filter-operator-button--active]=\"\r\n hasActiveColumnFilter(column)\r\n \" [title]=\"\r\n 'Operator: ' +\r\n getFilterOperatorLabel(\r\n getColumnFilterState(column).operator\r\n )\r\n \">\r\n\r\n <span nz-icon nzType=\"filter\"></span>\r\n </button>\r\n\r\n <!-- Clear current column filter -->\r\n <button *ngIf=\"hasActiveColumnFilter(column)\"\r\n type=\"button\" class=\"grid-filter-clear-button\"\r\n aria-label=\"Clear column filter\"\r\n title=\"Clear filter\"\r\n (click)=\"clearColumnFilter(column)\">\r\n\r\n <span nz-icon nzType=\"close\"></span>\r\n </button>\r\n </div>\r\n\r\n <!-- Operator dropdown -->\r\n <nz-dropdown-menu #operatorMenu=\"nzDropdownMenu\">\r\n <ul nz-menu class=\"grid-filter-operator-menu\">\r\n <li *ngFor=\"let operator of filterOperators\"\r\n nz-menu-item [nzSelected]=\"\r\n getColumnFilterState(column).operator ===\r\n operator.value\r\n \" (click)=\"\r\n setColumnFilterOperator(\r\n column,\r\n operator.value\r\n )\r\n \">\r\n\r\n <span *ngIf=\"\r\n getColumnFilterState(column).operator ===\r\n operator.value\r\n \" nz-icon nzType=\"check\">\r\n </span>\r\n\r\n {{ operator.label }}\r\n </li>\r\n </ul>\r\n </nz-dropdown-menu>\r\n </ng-container>\r\n </th>\r\n </tr>\r\n </thead>\r\n <!-- @contract decision: the column chain below, and what it does not carry\r\n reality: string, number, image, quantity, date, time, dropdown, boolean,\r\n autocomplete and dateRange each have their own condition. There is no\r\n branch for the credit card type.\r\n failure: a column whose type has no branch stays empty, with no error.\r\n instead: format the value in the endpoint and send a string.\r\n\r\n @contract decision: columns without scope.reference are valid\r\n reality: with option.actionColumn they render save/delete icons, otherwise a\r\n button. That is why the conditions below all guard on the reference. -->\r\n <tbody>\r\n <tr *ngFor=\"let data of basicTable.data; let i = index\">\r\n <td *ngFor=\"let col of tableitemInfo.layoutSchema.elements\"\r\n [style]=\"getStyleWithoutClasses(col?.scope?.style).style\">\r\n <ng-container\r\n *ngIf=\"tableitemInfo.propertySchema[getScope(col.scope?.reference)] && tableitemInfo.propertySchema[getScope(col.scope?.reference)][col?.scope?.reference?.split('/').pop()]?.type === 'string'\"\r\n [class]=\"getStyleWithoutClasses(col?.scope?.style).classes\"\r\n [style]=\"getStyleWithoutClasses(col?.scope?.style).style\">\r\n <span *ngIf=\"col.option.protected\">\r\n <span *ngIf=\"col.option?.link\"\r\n (click)=\"showLinkDetails(col.option, data)\">\r\n {{data[col.scope?.reference.split('/').pop()]}}\r\n </span>\r\n <span *ngIf=\"!col.option?.link\">\r\n <ng-container\r\n *ngIf=\"col?.option?.dateFormat; else string\">\r\n {{\r\n data[col.scope?.reference.split('/').pop()]\r\n | date:'yyyy-MM-dd' }}\r\n </ng-container>\r\n <ng-template #string>\r\n {{\r\n data[col.scope?.reference.split('/').pop()]\r\n }}\r\n </ng-template>\r\n </span>\r\n </span>\r\n <span *ngIf=\"!col.option.protected\">\r\n <input\r\n [(ngModel)]=\"data[col.scope?.reference.split('/').pop()]\"\r\n class=\"p-inputtext p-component\" />\r\n </span>\r\n </ng-container>\r\n\r\n <ng-container\r\n *ngIf=\"tableitemInfo.propertySchema[getScope(col.scope?.reference)] && tableitemInfo.propertySchema[getScope(col.scope?.reference)][col?.scope?.reference?.split('/').pop()]?.type === 'number'\">\r\n <span *ngIf=\"col.option.protected\">\r\n <span\r\n *ngIf=\"col.option?.innerAction?.action == 'multiply'\">\r\n {{\r\n (data[col.option?.innerAction?.from] *\r\n data[col.option?.innerAction?.to])\r\n | number:'1.2-2'\r\n }}\r\n </span>\r\n <span *ngIf=\"!col.option?.innerAction\">\r\n {{data[col.scope?.reference.split('/').pop()] |\r\n currency:\r\n tableitemInfo.propertySchema[getScope(col.scope?.reference)][col?.scope?.reference?.split('/').pop()]?.currency\r\n :true }}\r\n </span>\r\n </span>\r\n <span *ngIf=\"!col.option.protected\">\r\n <input\r\n [(ngModel)]=\"data[col.scope?.reference.split('/').pop()]\"\r\n type=\"number\"\r\n class=\"p-inputtext p-component\" />\r\n </span>\r\n </ng-container>\r\n\r\n <!-- Media control: also supports existing image properties -->\r\n <ng-container *ngIf=\"isMediaColumn(col)\">\r\n <ng-container\r\n *ngIf=\"getMediaSource(col, data) as source\">\r\n <ng-container [ngSwitch]=\"getMediaKind(col, data)\">\r\n\r\n <img\r\n *ngSwitchDefault\r\n [src]=\"source\"\r\n [alt]=\"getMediaLabel(col)\"\r\n [class]=\"getStyleWithoutClasses(col?.scope?.style).classes\"\r\n [ngStyle]=\"getStyleWithoutClasses(col?.scope?.style).style\"\r\n loading=\"lazy\"\r\n (click)=\"invokeTableImageClick(col, data)\" />\r\n\r\n <video\r\n *ngSwitchCase=\"'video'\"\r\n [src]=\"source\"\r\n [attr.aria-label]=\"getMediaLabel(col)\"\r\n [class]=\"getStyleWithoutClasses(col?.scope?.style).classes\"\r\n [ngStyle]=\"getStyleWithoutClasses(col?.scope?.style).style\"\r\n controls\r\n playsinline\r\n preload=\"metadata\">\r\n Your browser does not support video\r\n playback.\r\n </video>\r\n\r\n <audio\r\n *ngSwitchCase=\"'audio'\"\r\n [src]=\"source\"\r\n [attr.aria-label]=\"getMediaLabel(col)\"\r\n [class]=\"getStyleWithoutClasses(col?.scope?.style).classes\"\r\n [ngStyle]=\"getStyleWithoutClasses(col?.scope?.style).style\"\r\n controls\r\n preload=\"metadata\">\r\n Your browser does not support audio\r\n playback.\r\n </audio>\r\n\r\n <a\r\n *ngSwitchCase=\"'pdf'\"\r\n [href]=\"source\"\r\n [class]=\"getStyleWithoutClasses(col?.scope?.style).classes\"\r\n [ngStyle]=\"getStyleWithoutClasses(col?.scope?.style).style\"\r\n target=\"_blank\"\r\n rel=\"noopener noreferrer\">\r\n Open PDF \u2014 {{ getMediaLabel(col) }}\r\n </a>\r\n\r\n <a\r\n *ngSwitchCase=\"'file'\"\r\n [href]=\"source\"\r\n [class]=\"getStyleWithoutClasses(col?.scope?.style).classes\"\r\n [ngStyle]=\"getStyleWithoutClasses(col?.scope?.style).style\"\r\n target=\"_blank\"\r\n rel=\"noopener noreferrer\">\r\n Open file \u2014 {{ getMediaLabel(col) }}\r\n </a>\r\n\r\n </ng-container>\r\n </ng-container>\r\n </ng-container>\r\n\r\n <!-- @contract compatibility: existing checkbox fields render as boolean. -->\r\n <ng-container\r\n *ngIf=\"tableitemInfo.propertySchema[getScope(col.scope?.reference)] && (tableitemInfo.propertySchema[getScope(col.scope?.reference)][col?.scope?.reference?.split('/').pop()]?.type === 'boolean' || isLegacyCheckboxFieldType(tableitemInfo.propertySchema[getScope(col.scope?.reference)][col?.scope?.reference?.split('/').pop()]?.type))\">\r\n <input type=\"checkbox\"\r\n [style]=\"getStyleWithoutClasses(col?.scope?.style).style\"\r\n class=\"form-check-input mr-2\"\r\n [(ngModel)]=\"data[col.scope?.reference.split('/').pop()]\"\r\n [name]=\"col.scope?.reference\" />\r\n </ng-container>\r\n\r\n <ng-container\r\n *ngIf=\"tableitemInfo.propertySchema[getScope(col.scope?.reference)] && tableitemInfo.propertySchema[getScope(col.scope?.reference)][col?.scope?.reference?.split('/').pop()]?.type === 'dateRange'\">\r\n <nz-range-picker #dateRangeField=\"ngModel\"\r\n [required]=\"col.option.required\"\r\n [name]=\"col.scope?.reference\"\r\n [style]=\"getStyleWithoutClasses(col?.style).style\"\r\n [(ngModel)]=\"tableitemInfo.propertySchema[getScope(col.scope?.reference)][col.scope?.reference.split('/').pop()].value\"></nz-range-picker>\r\n </ng-container>\r\n\r\n <ng-container\r\n *ngIf=\"tableitemInfo.propertySchema[getScope(col.scope?.reference)] && tableitemInfo.propertySchema[getScope(col.scope?.reference)][col?.scope?.reference?.split('/').pop()]?.type === 'date'\">\r\n <div class=\"picker-field\">\r\n <p-datepicker #datePicker #dateField=\"ngModel\"\r\n styleClass=\"custom-datepicker\"\r\n [required]=\"col.option.required\"\r\n [name]=\"col.scope?.reference\"\r\n [disabled]=\"col?.option?.disabled\"\r\n [autoZIndex]=\"true\" [baseZIndex]=\"10000\"\r\n [dateFormat]=\"\r\n tableitemInfo.propertySchema[\r\n getScope(col.scope?.reference)\r\n ][\r\n col.scope?.reference.split('/').pop()\r\n ]?.format || 'yy-mm-dd'\r\n \" [(ngModel)]=\"\r\n form.propertySchema[\r\n getScope(col.scope?.reference)\r\n ][\r\n col.scope?.reference.split('/').pop()\r\n ].value\r\n \" [class]=\"col?.scope?.style?.classes?.[0] || ''\"\r\n [style]=\"getStyleWithoutClasses(col?.scope?.style).style\"\r\n [showIcon]=\"false\" [showOnFocus]=\"false\"\r\n appendTo=\"body\"\r\n [panelStyleClass]=\"picker.datePanelClass\"\r\n [motionOptions]=\"picker.dockedMotion\"\r\n [vlCustomKeyboard]=\"col?.option?.keyboardType ?? 'date'\"\r\n (pointerdown)=\"picker.onFieldPointerDown($event, datePicker)\"\r\n (onFocus)=\"picker.onFieldFocus($event)\"\r\n (onShow)=\"picker.onShown()\"\r\n (onClose)=\"picker.onClose(datePicker)\">\r\n </p-datepicker>\r\n <button type=\"button\" class=\"picker-field__icon\"\r\n aria-label=\"Open calendar\"\r\n (pointerdown)=\"picker.openFromIcon($event, datePicker)\"\r\n (click)=\"picker.blockIconClick($event)\">\r\n <i class=\"pi pi-calendar\"></i>\r\n </button>\r\n </div>\r\n </ng-container>\r\n\r\n <ng-container\r\n *ngIf=\"tableitemInfo.propertySchema[getScope(col.scope?.reference)] && tableitemInfo.propertySchema[getScope(col.scope?.reference)][col?.scope?.reference?.split('/').pop()]?.type === 'time'\">\r\n <div class=\"picker-field\">\r\n <p-datepicker #timePicker #timeField=\"ngModel\"\r\n styleClass=\"custom-datepicker\"\r\n [required]=\"col.option.required\"\r\n [name]=\"col.scope?.reference\" [timeOnly]=\"true\"\r\n hourFormat=\"24\"\r\n [disabled]=\"col?.option?.disabled\"\r\n [autoZIndex]=\"true\"\r\n [baseZIndex]=\"10000\"\r\n [style]=\"getStyleWithoutClasses(col?.scope?.style).style\"\r\n [(ngModel)]=\"\r\n form.propertySchema[\r\n getScope(col.scope?.reference)\r\n ][\r\n col.scope?.reference.split('/').pop()\r\n ].value\r\n \"\r\n [class]=\"col?.scope?.style?.classes?.[0] || ''\"\r\n [showIcon]=\"false\" [showOnFocus]=\"false\"\r\n appendTo=\"body\"\r\n [panelStyleClass]=\"picker.timePanelClass\"\r\n [vlCustomKeyboard]=\"col?.option?.keyboardType ?? 'time'\"\r\n (pointerdown)=\"picker.onFieldPointerDown($event, timePicker)\"\r\n (onFocus)=\"picker.onFieldFocus($event)\"\r\n (onShow)=\"picker.onShown()\"\r\n (onClose)=\"picker.onClose(timePicker)\">\r\n </p-datepicker>\r\n <button type=\"button\" class=\"picker-field__icon\"\r\n aria-label=\"Open time picker\"\r\n (pointerdown)=\"picker.openFromIcon($event, timePicker)\"\r\n (click)=\"picker.blockIconClick($event)\">\r\n <i class=\"pi pi-clock\"></i>\r\n </button>\r\n </div>\r\n </ng-container>\r\n\r\n <ng-container\r\n *ngIf=\"tableitemInfo.propertySchema[getScope(col.scope?.reference)] && tableitemInfo.propertySchema[getScope(col.scope?.reference)][col?.scope?.reference?.split('/').pop()]?.type === 'autocomplete'\">\r\n <p-autocomplete\r\n [suggestions]=\"remoteSuggestions[col.scope?.reference] ?? []\"\r\n (completeMethod)=\"completeRemote($event, col)\"\r\n #autocompleteField=\"ngModel\"\r\n [required]=\"col.option.required\"\r\n [name]=\"col.scope?.reference\"\r\n styleClass=\"custom-autocomplete\"\r\n [(ngModel)]=\"form.propertySchema[getScope(col.scope?.reference)][col.scope?.reference.split('/').pop()].value\"\r\n [style]=\"getStyleWithoutClasses(col?.scope?.style).style\"\r\n [class]=\"col?.scope?.style?.classes ? col?.scope?.style?.classes[0] : ''\"\r\n [dropdown]=\"true\"\r\n [optionLabel]=\"col.option.autocomplete.response.label\"\r\n [placeholder]=\"form.propertySchema | vlPlaceholder: col.scope?.reference\"\r\n [vlCustomKeyboard]=\"col?.option?.keyboardType ?? 'string'\">\r\n </p-autocomplete>\r\n </ng-container>\r\n\r\n <ng-container\r\n *ngIf=\"tableitemInfo.propertySchema[getScope(col.scope?.reference)] && tableitemInfo.propertySchema[getScope(col.scope?.reference)][col?.scope?.reference?.split('/').pop()]?.type === 'dropdown'\">\r\n <select id=\"dynamic-dropdown\" #dropdownField=\"ngModel\"\r\n [ngClass]=\"getStyleWithoutClasses(col?.scope?.style)?.classes\"\r\n [ngStyle]=\"getStyleWithoutClasses(col?.scope?.style)?.style\"\r\n [name]=\"col.scope?.reference\"\r\n [(ngModel)]=\"\r\n form.propertySchema[getScope(col.scope?.reference)][\r\n col.scope?.reference.split('/').pop()\r\n ].value\r\n \">\r\n <option *ngFor=\"\r\n let item of form.propertySchema[getScope(col.scope?.reference)]?.[\r\n col.scope?.reference.split('/').pop()\r\n ]?.data\r\n \" [value]=\"item[col?.option?.optionValue]\">\r\n {{ item[col?.option?.optionLabel] }}\r\n </option>\r\n </select>\r\n </ng-container>\r\n\r\n <ng-container *ngIf=\"!col?.scope?.reference\">\r\n <span *ngIf=\"col.option?.actionColumn\">\r\n <span nz-icon\r\n *ngIf=\"setActionColumn(col.option?.save, data)\"\r\n [nzType]=\"col.option?.save?.icon\"\r\n [nzTheme]=\"'twotone'\"\r\n [style]=\"col.option?.save?.style\"\r\n [nzTwotoneColor]=\"'#52c41a'\"\r\n [class]=\"col.option?.save?.style?.classes[0]\"\r\n (click)=\"upsertAction(col.option?.save, data)\">\r\n </span>\r\n <span nz-icon\r\n *ngIf=\"setActionColumn(col.option?.delete, data)\"\r\n [nzType]=\"col.option?.delete?.icon\"\r\n [nzTheme]=\"'twotone'\"\r\n [style]=\"col.option?.delete?.style\"\r\n [nzTwotoneColor]=\"'#FF0000'\"\r\n [class]=\"col.option?.delete?.style?.classes[0]\"\r\n (click)=\"upsertAction(col.option?.delete, data)\"></span>\r\n\r\n </span>\r\n <span *ngIf=\"!col.option?.actionColumn\">\r\n <button type=\"submit\"\r\n [style]=\"getStyleWithoutClasses(col?.label?.style).style\"\r\n (click)=\"invokeGridBtnClick(col.option, data)\"\r\n [class]=\"col?.label?.style?.classes[0]\">\r\n {{ col.label?.caption }}\r\n </button>\r\n </span>\r\n </ng-container>\r\n\r\n <!-- For quantity column, display increment/decrement buttons -->\r\n <ng-container\r\n *ngIf=\"tableitemInfo.propertySchema[getScope(col.scope?.reference)] && tableitemInfo.propertySchema[getScope(col.scope?.reference)][col?.scope?.reference?.split('/').pop()]?.type === 'quantity'\">\r\n <div style=\"display: flex; align-items: center;\">\r\n <button pButton icon=\"pi pi-minus\"\r\n (click)=\"decrementQuantity(i,col.scope?.reference.split('/').pop(), col.option)\"\r\n [disabled]=\"data.quantity <= 0\"\r\n style=\"margin-right: 8px; height: 10px; width: 10px;\"></button>\r\n <span>{{ data[col.scope?.reference.split('/').pop()]\r\n }}</span>\r\n <button pButton icon=\"pi pi-plus\"\r\n (click)=\"incrementQuantity(i, col.scope?.reference.split('/').pop(), col.option)\"\r\n style=\"margin-left: 8px; height: 10px; width: 10px;\"></button>\r\n </div>\r\n </ng-container>\r\n </td>\r\n </tr>\r\n </tbody>\r\n </nz-table>\r\n</div>\r\n\r\n<!-- table footer -->\r\n<div *ngIf=\"tableitemInfo?.footer?.formFields && tableitemInfo.data?.length\"\r\n class=\"table-footer flex flex-column align-items-end gap-2 pt-2 mx-4 border-top-1 border-cyan-500\">\r\n <!-- @contract decision: the footer renders string and number only\r\n reality: the switch below carries those two cases and a default. It did NOT change\r\n when the columns gained their types on 2026-09-18.\r\n failure: any other type in a footer field renders empty.\r\n instead: keep aggregates numeric, or pre-format them as text in the endpoint. -->\r\n <div *ngFor=\"let tableField of tableitemInfo?.footer?.formFields\">\r\n <div\r\n [ngSwitch]=\"tableField?.scope?.reference && tableitemInfo.propertySchema[getScope(tableField.scope?.reference)] && tableitemInfo.propertySchema[getScope(tableField.scope?.reference)][tableField.scope?.reference.split('/').pop()] ?\r\n tableitemInfo.propertySchema[getScope(tableField.scope?.reference)][tableField.scope?.reference.split('/').pop()]?.type : 'default'\">\r\n\r\n <!-- string control -->\r\n <div *ngSwitchCase=\"'string'\" class=\"form-group\">\r\n <span *ngIf=\"tableField.option.protected\">\r\n <h5 style=\"display: flex; justify-content: space-between;\">\r\n <span\r\n [style]=\"getStyleWithoutClasses(tableField?.label?.style).style\"\r\n [class]=\"tableField?.label?.style?.classes[0]\">\r\n {{\r\n tableitemInfo.propertySchema[getScope(tableField.scope?.reference)][tableField.scope?.reference.split('/').pop()]?.caption\r\n }}\r\n </span>\r\n <span>\r\n {{\r\n tableitemInfo.propertySchema[getScope(tableField.scope?.reference)][tableField.scope?.reference.split('/').pop()]?.value\r\n }}\r\n </span>\r\n </h5>\r\n </span>\r\n <div *ngIf=\"!tableField.option.protected\">\r\n <div\r\n [class]=\"tableField?.layout == 'horizontal' ? 'horizontal-layout' : 'row'\">\r\n <label\r\n [style]=\"getStyleWithoutClasses(tableField?.label?.style).style\"\r\n [class]=\"tableField?.label?.style?.classes[0]\">{{\r\n tableField.label?.value ?\r\n tableField.label?.value :\r\n tableitemInfo.propertySchema[getScope(tableField.scope?.reference)][tableField.scope?.reference.split('/').pop()]?.caption\r\n }}</label>\r\n <input type=\"text\" #inputField=\"ngModel\"\r\n [required]=\"tableField.option.required\"\r\n [email]=\"tableField.option.email\"\r\n [class]=\"tableField.scope?.style?.classes[0]\"\r\n [style]=\"getStyleWithoutClasses(tableField?.scope?.style).style\"\r\n [(ngModel)]=\"tableitemInfo.propertySchema[getScope(tableField.scope?.reference)][tableField.scope?.reference.split('/').pop()].value\"\r\n [name]=\"tableField.scope?.reference\"\r\n [placeholder]=\"tableitemInfo.propertySchema | vlPlaceholder: tableField.scope?.reference\" />\r\n </div>\r\n <!-- Error Message -->\r\n <div *ngIf=\"inputField?.touched && inputField?.invalid\"\r\n [style]=\"getStyleWithoutClasses(tableField?.validation?.style).style\">\r\n <p class=\"text-danger\"\r\n *ngIf=\"inputField?.errors?.['required']\">{{tableField.label?.value\r\n ?\r\n tableField.label?.value :\r\n tableitemInfo.propertySchema[getScope(tableField.scope?.reference)][tableField.scope?.reference.split('/').pop()]?.caption\r\n +\r\n ' ' + errorMessages.required}}</p>\r\n <p class=\"text-danger\"\r\n *ngIf=\"inputField?.errors?.['email']\">{{(tableField.label?.value\r\n ?\r\n tableField.label?.value :\r\n tableitemInfo.propertySchema[getScope(tableField.scope?.reference)][tableField.scope?.reference.split('/').pop()]?.caption)\r\n +\r\n ' ' + errorMessages.pattern}}</p>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- number control -->\r\n <div *ngSwitchCase=\"'number'\" class=\"form-group\">\r\n <span *ngIf=\"tableField.option.protected\"\r\n [style]=\"getStyleWithoutClasses(tableField?.label?.style).style\"\r\n [class]=\"tableField?.label?.style?.classes[0]\">\r\n <h5>{{\r\n form.propertySchema[getScope(tableField.scope?.reference)][tableField.scope?.reference.split('/').pop()]?.caption\r\n }} {{\r\n form.propertySchema[getScope(tableField.scope?.reference)][tableField.scope?.reference.split('/').pop()]?.value\r\n |\r\n currency:tableField.option.currency :true:\r\n tableField.option?.decimalPoint}}\r\n </h5>\r\n </span>\r\n <span *ngIf=\"!tableField.option.protected\">\r\n <div\r\n [class]=\"tableField?.layout == 'horizontal' ? 'horizontal-layout' : 'row'\">\r\n <label\r\n [style]=\"getStyleWithoutClasses(tableField?.label?.style).style\"\r\n [class]=\"tableField?.label?.style?.classes[0]\">{{\r\n tableField.label?.value ?\r\n tableField.label?.value :\r\n form.propertySchema[getScope(tableField.scope?.reference)][tableField.scope?.reference.split('/').pop()]?.caption\r\n }}</label>\r\n <input type=\"number\"\r\n [class]=\"tableField.scope?.style?.classes[0]\"\r\n [style]=\"getStyleWithoutClasses(tableField?.scope?.style).style\"\r\n [(ngModel)]=\"form.propertySchema[getScope(tableField.scope?.reference)][tableField.scope?.reference.split('/').pop()].value\"\r\n [name]=\"tableField.scope?.reference\"\r\n [placeholder]=\"form.propertySchema | vlPlaceholder: tableField.scope?.reference\" />\r\n </div>\r\n </span>\r\n </div>\r\n\r\n <!-- button control -->\r\n <div *ngSwitchCase=\"'default'\">\r\n <button type=\"submit\"\r\n [style]=\"getStyleWithoutClasses(tableField.label.style).style\"\r\n (click)=\"invokeGridBtnClick(tableField.option, tableitemInfo.propertySchema)\">\r\n {{ tableField.label?.caption }}\r\n </button>\r\n </div>\r\n </div>\r\n </div>\r\n</div>\r\n\r\n<!-- bottom pagination on grid -->\r\n<div\r\n *ngIf=\"tableitemInfo.data?.length && !tableitemInfo?.layoutSchema?.pagination?.top && tableitemInfo?.layoutSchema?.pagination?.bottom\">\r\n <vl-pagination [itemInfo]=\"tableitemInfo\" [pageSize]=\"pageSize\"\r\n [currentPage]=\"currentPage\" [pages]=\"pages\"\r\n (pageSizeChange)=\"invokeOnPageSizeChange($event)\"\r\n (onGoToPage)=\"invokeGoToPage($event)\">\r\n </vl-pagination>\r\n</div>\r\n", styles: [".grid-filter-row th{padding:8px;vertical-align:middle;background:#fafafa}.grid-filter-cell{min-width:150px}.grid-filter-input-wrapper{display:flex;align-items:stretch;width:100%}.grid-filter-input{width:100%;min-width:0;min-height:34px;padding:5px 8px;border:1px solid #d9d9d9;border-right:0;border-radius:4px 0 0 4px;outline:none}.grid-filter-input:focus{border-color:#1677ff}.grid-filter-operator-button,.grid-filter-clear-button{display:inline-flex;align-items:center;justify-content:center;min-width:36px;min-height:34px;padding:0;cursor:pointer;background:#fff;border:1px solid #d9d9d9}.grid-filter-operator-button{color:#595959;border-radius:0 4px 4px 0}.grid-filter-operator-button:hover,.grid-filter-operator-button--active{color:#1677ff;border-color:#1677ff}.grid-filter-clear-button{margin-left:5px;color:#ff4d4f;border-radius:4px}.grid-filter-clear-button:hover{color:#fff;background:#ff4d4f;border-color:#ff4d4f}.grid-filter-operator-menu{min-width:190px}:host ::ng-deep .ant-table-content.has-more-right{-webkit-mask-image:linear-gradient(to right,#000 calc(100% - 36px),transparent);mask-image:linear-gradient(to right,#000 calc(100% - 36px),transparent)}:host ::ng-deep .ant-table-content.has-more-left{-webkit-mask-image:linear-gradient(to left,#000 calc(100% - 36px),transparent);mask-image:linear-gradient(to left,#000 calc(100% - 36px),transparent)}:host ::ng-deep .ant-table-content.has-more-left.has-more-right{-webkit-mask-image:linear-gradient(to right,transparent,#000 36px,#000 calc(100% - 36px),transparent);mask-image:linear-gradient(to right,transparent,#000 36px,#000 calc(100% - 36px),transparent)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i9.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i9.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i9.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i9.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "directive", type: i9.NgSwitch, selector: "[ngSwitch]", inputs: ["ngSwitch"] }, { kind: "directive", type: i9.NgSwitchCase, selector: "[ngSwitchCase]", inputs: ["ngSwitchCase"] }, { kind: "directive", type: i9.NgSwitchDefault, selector: "[ngSwitchDefault]" }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i2.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { kind: "directive", type: i2.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { kind: "directive", type: i2.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i2.EmailValidator, selector: "[email][formControlName],[email][formControl],[email][ngModel]", inputs: ["email"] }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: NzTableModule }, { kind: "component", type: i7$1.NzTableComponent, selector: "nz-table", inputs: ["nzTableLayout", "nzShowTotal", "nzItemRender", "nzTitle", "nzFooter", "nzNoResult", "nzPageSizeOptions", "nzVirtualItemSize", "nzVirtualMaxBufferPx", "nzVirtualMinBufferPx", "nzVirtualForTrackBy", "nzLoadingDelay", "nzPageIndex", "nzPageSize", "nzTotal", "nzWidthConfig", "nzData", "nzCustomColumn", "nzPaginationPosition", "nzScroll", "noDataVirtualHeight", "nzPaginationType", "nzFrontPagination", "nzTemplateMode", "nzShowPagination", "nzLoading", "nzOuterBordered", "nzLoadingIndicator", "nzBordered", "nzSize", "nzShowSizeChanger", "nzHideOnSinglePage", "nzShowQuickJumper", "nzSimple"], outputs: ["nzPageSizeChange", "nzPageIndexChange", "nzQueryParams", "nzCurrentPageDataChange", "nzCustomColumnChange"], exportAs: ["nzTable"] }, { kind: "component", type: i7$1.NzThAddOnComponent, selector: "th[nzColumnKey], th[nzSortFn], th[nzSortOrder], th[nzFilters], th[nzShowSort], th[nzShowFilter], th[nzCustomFilter]", inputs: ["nzColumnKey", "nzFilterMultiple", "nzSortOrder", "nzSortPriority", "nzSortDirections", "nzFilters", "nzSortFn", "nzFilterFn", "nzShowSort", "nzShowFilter", "nzCustomFilter"], outputs: ["nzCheckedChange", "nzSortOrderChange", "nzFilterChange"] }, { kind: "directive", type: i7$1.NzTableCellDirective, selector: "th:not(.nz-disable-th), td:not(.nz-disable-td)" }, { kind: "directive", type: i7$1.NzThMeasureDirective, selector: "th", inputs: ["nzWidth", "colspan", "colSpan", "rowspan", "rowSpan"] }, { kind: "component", type: i7$1.NzTheadComponent, selector: "thead:not(.ant-table-thead)", outputs: ["nzSortOrderChange"] }, { kind: "component", type: i7$1.NzTbodyComponent, selector: "tbody" }, { kind: "directive", type: i7$1.NzTrDirective, selector: "tr:not([nz-table-measure-row]):not([nzExpand]):not([nz-table-fixed-row])" }, { kind: "ngmodule", type: NzIconModule }, { kind: "directive", type: i11.NzIconDirective, selector: "nz-icon,[nz-icon]", inputs: ["nzSpin", "nzRotate", "nzType", "nzTheme", "nzTwotoneColor", "nzIconfont"], exportAs: ["nzIcon"] }, { kind: "ngmodule", type: ButtonModule }, { kind: "directive", type: i9$1.ButtonDirective, selector: "[pButton]", inputs: ["ptButtonDirective", "pButtonPT", "pButtonUnstyled", "hostName", "text", "plain", "raised", "size", "outlined", "rounded", "iconPos", "loadingIcon", "fluid", "label", "icon", "loading", "buttonProps", "severity"] }, { kind: "ngmodule", type: NzDropDownModule }, { kind: "directive", type: i11$1.NzMenuDirective, selector: "[nz-menu]", inputs: ["nzInlineIndent", "nzTheme", "nzMode", "nzInlineCollapsed", "nzSelectable"], outputs: ["nzClick"], exportAs: ["nzMenu"] }, { kind: "component", type: i11$1.NzMenuItemComponent, selector: "[nz-menu-item]", inputs: ["nzPaddingLeft", "nzDisabled", "nzSelected", "nzDanger", "nzMatchRouterExact", "nzMatchRouter"], exportAs: ["nzMenuItem"] }, { kind: "directive", type: i11$2.NzDropdownDirective, selector: "[nz-dropdown]", inputs: ["nzDropdownMenu", "nzTrigger", "nzMatchWidthElement", "nzBackdrop", "nzClickHide", "nzDisabled", "nzVisible", "nzArrow", "nzOverlayClassName", "nzOverlayStyle", "nzPlacement"], outputs: ["nzVisibleChange"], exportAs: ["nzDropdown"] }, { kind: "component", type: i11$2.NzDropdownMenuComponent, selector: "nz-dropdown-menu", exportAs: ["nzDropdownMenu"] }, { kind: "ngmodule", type: NzMenuModule }, { kind: "component", type: PaginationComponent, selector: "vl-pagination", inputs: ["itemInfo", "pageSize", "currentPage", "selectedLanguageInfo", "pages"], outputs: ["pageSizeChange", "onGoToPage"] }, { kind: "ngmodule", type: NzDatePickerModule }, { kind: "component", type: i4.NzDatePickerComponent, selector: "nz-date-picker,nz-week-picker,nz-month-picker,nz-quarter-picker,nz-year-picker,nz-range-picker", inputs: ["nzInline", "nzAllowClear", "nzAutoFocus", "nzDisabled", "nzInputReadOnly", "nzOpen", "nzDisabledDate", "nzLocale", "nzPlaceHolder", "nzPopupStyle", "nzDropdownClassName", "nzSize", "nzStatus", "nzFormat", "nzVariant", "nzDateRender", "nzDisabledTime", "nzRenderExtraFooter", "nzShowToday", "nzMode", "nzShowNow", "nzRanges", "nzDefaultPickerValue", "nzSeparator", "nzSuffixIcon", "nzBackdrop", "nzId", "nzPlacement", "nzShowWeekNumber", "nzShowTime"], outputs: ["nzOnPanelChange", "nzOnCalendarChange", "nzOnOk", "nzOnOpenChange"], exportAs: ["nzDatePicker"] }, { kind: "directive", type: i4.NzRangePickerComponent, selector: "nz-range-picker", exportAs: ["nzRangePicker"] }, { kind: "ngmodule", type: DatePickerModule }, { kind: "component", type: i12.DatePicker, selector: "p-datePicker, p-datepicker, p-date-picker", inputs: ["iconDisplay", "styleClass", "inputStyle", "inputId", "inputStyleClass", "placeholder", "ariaLabelledBy", "ariaLabel", "iconAriaLabel", "dateFormat", "multipleSeparator", "rangeSeparator", "inline", "showOtherMonths", "selectOtherMonths", "showIcon", "icon", "readonlyInput", "shortYearCutoff", "hourFormat", "timeOnly", "stepHour", "stepMinute", "stepSecond", "showSeconds", "showOnFocus", "showWeek", "startWeekFromFirstDayOfYear", "showClear", "dataType", "selectionMode", "maxDateCount", "showButtonBar", "todayButtonStyleClass", "clearButtonStyleClass", "autofocus", "autoZIndex", "baseZIndex", "panelStyleClass", "panelStyle", "keepInvalid", "hideOnDateTimeSelect", "touchUI", "timeSeparator", "focusTrap", "showTransitionOptions", "hideTransitionOptions", "tabindex", "minDate", "maxDate", "disabledDates", "disabledDays", "showTime", "responsiveOptions", "numberOfMonths", "firstDayOfWeek", "view", "defaultDate", "appendTo", "motionOptions"], outputs: ["onFocus", "onBlur", "onClose", "onSelect", "onClear", "onInput", "onTodayClick", "onClearClick", "onMonthChange", "onYearChange", "onClickOutside", "onShow"] }, { kind: "ngmodule", type: AutoCompleteModule }, { kind: "component", type: i18.AutoComplete, selector: "p-autoComplete, p-autocomplete, p-auto-complete", inputs: ["minLength", "minQueryLength", "delay", "panelStyle", "styleClass", "panelStyleClass", "inputStyle", "inputId", "inputStyleClass", "placeholder", "readonly", "scrollHeight", "lazy", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "autoHighlight", "forceSelection", "type", "autoZIndex", "baseZIndex", "ariaLabel", "dropdownAriaLabel", "ariaLabelledBy", "dropdownIcon", "unique", "group", "completeOnFocus", "showClear", "dropdown", "showEmptyMessage", "dropdownMode", "multiple", "addOnTab", "tabindex", "dataKey", "emptyMessage", "showTransitionOptions", "hideTransitionOptions", "autofocus", "autocomplete", "optionGroupChildren", "optionGroupLabel", "overlayOptions", "suggestions", "optionLabel", "optionValue", "id", "searchMessage", "emptySelectionMessage", "selectionMessage", "autoOptionFocus", "selectOnFocus", "searchLocale", "optionDisabled", "focusOnHover", "typeahead", "addOnBlur", "separator", "appendTo", "motionOptions"], outputs: ["completeMethod", "onSelect", "onUnselect", "onAdd", "onFocus", "onBlur", "onDropdownClick", "onClear", "onInputKeydown", "onKeyUp", "onShow", "onHide", "onLazyLoad"] }, { kind: "ngmodule", type: InputTextModule }, { kind: "directive", type: CustomKeyboardDirective, selector: "[vlCustomKeyboard]", inputs: ["vlCustomKeyboard"] }, { kind: "pipe", type: PlaceholderPipe, name: "vlPlaceholder" }, { kind: "pipe", type: i9.DecimalPipe, name: "number" }, { kind: "pipe", type: i9.CurrencyPipe, name: "currency" }, { kind: "pipe", type: i9.DatePipe, name: "date" }] });
5281
5513
  }
5282
5514
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.2", ngImport: i0, type: GridComponent, decorators: [{
5283
5515
  type: Component,
@@ -5295,7 +5527,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.2", ngImpor
5295
5527
  AutoCompleteModule,
5296
5528
  InputTextModule,
5297
5529
  CustomKeyboardDirective,
5298
- ], selector: 'vl-grid', template: "<!-- Faramarz Yousefian and Agent Toni (Claude Opus 5.5) 2026-10-13\r\n - new: autocompletes get their suggestions from RemoteListService (completeRemote) -->\r\n<!-- Faramarz Yousefian and Agent Toni (Claude Opus 5.5) 2026-10-13\r\n - fix: the placeholder comes from vlPlaceholder (pipes/placeholder.pipe.ts) - empty where the\r\n project defines none; it showed the text \"undefined\" -->\r\n<!-- Faramarz Yousefian and Agent Toni (Claude Opus 5) 2026-10-07\r\n - change: autocomplete fields take the toolkit string keyboard unless option.keyboardType\r\n names another one ('native' keeps the system keyboard)\r\n - change: date and time cells use the shared picker markup (picker-field, DateTimePickerService);\r\n their PrimeNG icon opened the calendar together with the system keyboard -->\r\n\r\n<!-- Shuaib 2026-09-24\r\n - change: grid cells render legacy checkbox fields through the boolean control. -->\r\n\r\n<!-- Faramarz Yousefian and Agent Toni (Claude Opus 5) 2026-09-19\r\n - new: @contract comments on the sorting, on the column filter and on the footer. The filter\r\n reads option.filter and never option.columnFilter, which is the mistake a layout author\r\n makes without being told -->\r\n<div *ngIf=\"!tableitemInfo.data?.length\" class=\"alert alert-warning col-md-12\"\r\n role=\"alert\">\r\n {{ tableitemInfo.layoutSchema?.noRecordMessage}}\r\n</div>\r\n<div *ngIf=\"tableitemInfo.data?.length\" class=\"reservation-container pt-5 px-3\">\r\n <nz-table #basicTable [nzData]=\"gridDisplayData\"\r\n [nzNoResult]=\"'No matching records found'\" [nzBordered]=\"true\"\r\n [nzFrontPagination]=\"currenTableOptions?.pagination?.tabs\"\r\n [style]=\"getStyleWithoutClasses(currenTableOptions?.style).style\"\r\n (scroll)=\"onScrollEvent($event)\"\r\n [nzLoading]=\"isTableDataLoad\">\r\n <thead>\r\n <!-- @contract decision: option.sortable is read here\r\n reality: nzSortFn is wired to getColumnSortFn since 2026-09-16; before that\r\n the key was decoration. The column also needs a scope.reference -\r\n without one getColumnSortFn has nothing to sort by.\r\n seen: grid.component.ts:338 -->\r\n <!-- Column headings and sorting -->\r\n <tr>\r\n <th *ngFor=\"let column of tableitemInfo.layoutSchema.elements\"\r\n [nzSortFn]=\"\r\n column?.option?.sortable\r\n ? getColumnSortFn(column)\r\n : false\r\n \">\r\n\r\n {{ column?.label?.caption }}\r\n </th>\r\n </tr>\r\n\r\n <!-- @contract decision: the column filter reads option.filter, NOT option.columnFilter\r\n reality: option.filter.filtering switches it on, option.filter.defaultOperator\r\n starts the comparison (the renderer falls back to contains), and\r\n option.filter.placeholder labels the input.\r\n failure: option.columnFilter is read nowhere, here or in the runtime app. A\r\n column carrying it looks filterable in the file and is not on screen.\r\n seen: grid.component.ts:450-475; 5 uses of columnFilter across the reference\r\n projects, all of them dead -->\r\n <!-- Column filters -->\r\n <tr *ngIf=\"hasAnyColumnFilter()\" class=\"grid-filter-row\">\r\n\r\n <th *ngFor=\"let column of tableitemInfo.layoutSchema.elements\"\r\n class=\"grid-filter-cell\">\r\n\r\n <ng-container *ngIf=\"\r\n column?.option?.filter?.filtering === true &&\r\n column?.scope?.reference\r\n \">\r\n\r\n <div class=\"grid-filter-input-wrapper\">\r\n <input type=\"text\" class=\"grid-filter-input\"\r\n [placeholder]=\"getColumnFilterPlaceholder(column)\"\r\n [ngModel]=\"getColumnFilterState(column).value\"\r\n (ngModelChange)=\"\r\n setColumnFilterValue(column, $event)\r\n \" />\r\n\r\n <!-- Operator selection button -->\r\n <button type=\"button\"\r\n class=\"grid-filter-operator-button\" nz-dropdown\r\n nzTrigger=\"click\"\r\n [nzDropdownMenu]=\"operatorMenu\"\r\n [class.grid-filter-operator-button--active]=\"\r\n hasActiveColumnFilter(column)\r\n \" [title]=\"\r\n 'Operator: ' +\r\n getFilterOperatorLabel(\r\n getColumnFilterState(column).operator\r\n )\r\n \">\r\n\r\n <span nz-icon nzType=\"filter\"></span>\r\n </button>\r\n\r\n <!-- Clear current column filter -->\r\n <button *ngIf=\"hasActiveColumnFilter(column)\"\r\n type=\"button\" class=\"grid-filter-clear-button\"\r\n aria-label=\"Clear column filter\"\r\n title=\"Clear filter\"\r\n (click)=\"clearColumnFilter(column)\">\r\n\r\n <span nz-icon nzType=\"close\"></span>\r\n </button>\r\n </div>\r\n\r\n <!-- Operator dropdown -->\r\n <nz-dropdown-menu #operatorMenu=\"nzDropdownMenu\">\r\n <ul nz-menu class=\"grid-filter-operator-menu\">\r\n <li *ngFor=\"let operator of filterOperators\"\r\n nz-menu-item [nzSelected]=\"\r\n getColumnFilterState(column).operator ===\r\n operator.value\r\n \" (click)=\"\r\n setColumnFilterOperator(\r\n column,\r\n operator.value\r\n )\r\n \">\r\n\r\n <span *ngIf=\"\r\n getColumnFilterState(column).operator ===\r\n operator.value\r\n \" nz-icon nzType=\"check\">\r\n </span>\r\n\r\n {{ operator.label }}\r\n </li>\r\n </ul>\r\n </nz-dropdown-menu>\r\n </ng-container>\r\n </th>\r\n </tr>\r\n </thead>\r\n <!-- @contract decision: the column chain below, and what it does not carry\r\n reality: string, number, image, quantity, date, time, dropdown, boolean,\r\n autocomplete and dateRange each have their own condition. There is no\r\n branch for the credit card type.\r\n failure: a column whose type has no branch stays empty, with no error.\r\n instead: format the value in the endpoint and send a string.\r\n\r\n @contract decision: columns without scope.reference are valid\r\n reality: with option.actionColumn they render save/delete icons, otherwise a\r\n button. That is why the conditions below all guard on the reference. -->\r\n <tbody>\r\n <tr *ngFor=\"let data of basicTable.data; let i = index\">\r\n <td *ngFor=\"let col of tableitemInfo.layoutSchema.elements\"\r\n [style]=\"getStyleWithoutClasses(col?.scope?.style).style\">\r\n <ng-container\r\n *ngIf=\"tableitemInfo.propertySchema[getScope(col.scope?.reference)] && tableitemInfo.propertySchema[getScope(col.scope?.reference)][col?.scope?.reference?.split('/').pop()]?.type === 'string'\"\r\n [class]=\"getStyleWithoutClasses(col?.scope?.style).classes\"\r\n [style]=\"getStyleWithoutClasses(col?.scope?.style).style\">\r\n <span *ngIf=\"col.option.protected\">\r\n <span *ngIf=\"col.option?.link\"\r\n (click)=\"showLinkDetails(col.option, data)\">\r\n {{data[col.scope?.reference.split('/').pop()]}}\r\n </span>\r\n <span *ngIf=\"!col.option?.link\">\r\n <ng-container\r\n *ngIf=\"col?.option?.dateFormat; else string\">\r\n {{\r\n data[col.scope?.reference.split('/').pop()]\r\n | date:'yyyy-MM-dd' }}\r\n </ng-container>\r\n <ng-template #string>\r\n {{\r\n data[col.scope?.reference.split('/').pop()]\r\n }}\r\n </ng-template>\r\n </span>\r\n </span>\r\n <span *ngIf=\"!col.option.protected\">\r\n <input\r\n [(ngModel)]=\"data[col.scope?.reference.split('/').pop()]\"\r\n class=\"p-inputtext p-component\" />\r\n </span>\r\n </ng-container>\r\n\r\n <ng-container\r\n *ngIf=\"tableitemInfo.propertySchema[getScope(col.scope?.reference)] && tableitemInfo.propertySchema[getScope(col.scope?.reference)][col?.scope?.reference?.split('/').pop()]?.type === 'number'\">\r\n <span *ngIf=\"col.option.protected\">\r\n <span\r\n *ngIf=\"col.option?.innerAction?.action == 'multiply'\">\r\n {{\r\n (data[col.option?.innerAction?.from] *\r\n data[col.option?.innerAction?.to])\r\n | number:'1.2-2'\r\n }}\r\n </span>\r\n <span *ngIf=\"!col.option?.innerAction\">\r\n {{data[col.scope?.reference.split('/').pop()] |\r\n currency:\r\n tableitemInfo.propertySchema[getScope(col.scope?.reference)][col?.scope?.reference?.split('/').pop()]?.currency\r\n :true }}\r\n </span>\r\n </span>\r\n <span *ngIf=\"!col.option.protected\">\r\n <input\r\n [(ngModel)]=\"data[col.scope?.reference.split('/').pop()]\"\r\n type=\"number\"\r\n class=\"p-inputtext p-component\" />\r\n </span>\r\n </ng-container>\r\n\r\n <ng-container\r\n *ngIf=\"tableitemInfo.propertySchema[getScope(col.scope?.reference)] && tableitemInfo.propertySchema[getScope(col.scope?.reference)][col?.scope?.reference?.split('/').pop()]?.type === 'image'\">\r\n <img *ngIf=\"data[col.scope?.reference.split('/').pop()]\"\r\n [src]=\"data[col.scope?.reference.split('/').pop()]\"\r\n alt=\"Image\"\r\n (click)=\"invokeTableImageClick(col, data)\"\r\n [style]=\"getStyleWithoutClasses(col?.scope?.style).style\" />\r\n </ng-container>\r\n\r\n <!-- @contract compatibility: existing checkbox fields render as boolean. -->\r\n <ng-container\r\n *ngIf=\"tableitemInfo.propertySchema[getScope(col.scope?.reference)] && (tableitemInfo.propertySchema[getScope(col.scope?.reference)][col?.scope?.reference?.split('/').pop()]?.type === 'boolean' || isLegacyCheckboxFieldType(tableitemInfo.propertySchema[getScope(col.scope?.reference)][col?.scope?.reference?.split('/').pop()]?.type))\">\r\n <input type=\"checkbox\"\r\n [style]=\"getStyleWithoutClasses(col?.scope?.style).style\"\r\n class=\"form-check-input mr-2\"\r\n [(ngModel)]=\"data[col.scope?.reference.split('/').pop()]\"\r\n [name]=\"col.scope?.reference\" />\r\n </ng-container>\r\n\r\n <ng-container\r\n *ngIf=\"tableitemInfo.propertySchema[getScope(col.scope?.reference)] && tableitemInfo.propertySchema[getScope(col.scope?.reference)][col?.scope?.reference?.split('/').pop()]?.type === 'dateRange'\">\r\n <nz-range-picker #dateRangeField=\"ngModel\"\r\n [required]=\"col.option.required\"\r\n [name]=\"col.scope?.reference\"\r\n [style]=\"getStyleWithoutClasses(col?.style).style\"\r\n [(ngModel)]=\"tableitemInfo.propertySchema[getScope(col.scope?.reference)][col.scope?.reference.split('/').pop()].value\"></nz-range-picker>\r\n </ng-container>\r\n\r\n <ng-container\r\n *ngIf=\"tableitemInfo.propertySchema[getScope(col.scope?.reference)] && tableitemInfo.propertySchema[getScope(col.scope?.reference)][col?.scope?.reference?.split('/').pop()]?.type === 'date'\">\r\n <div class=\"picker-field\">\r\n <p-datepicker #datePicker #dateField=\"ngModel\"\r\n styleClass=\"custom-datepicker\"\r\n [required]=\"col.option.required\"\r\n [name]=\"col.scope?.reference\"\r\n [disabled]=\"col?.option?.disabled\"\r\n [autoZIndex]=\"true\" [baseZIndex]=\"10000\"\r\n [dateFormat]=\"\r\n tableitemInfo.propertySchema[\r\n getScope(col.scope?.reference)\r\n ][\r\n col.scope?.reference.split('/').pop()\r\n ]?.format || 'yy-mm-dd'\r\n \" [(ngModel)]=\"\r\n form.propertySchema[\r\n getScope(col.scope?.reference)\r\n ][\r\n col.scope?.reference.split('/').pop()\r\n ].value\r\n \" [class]=\"col?.scope?.style?.classes?.[0] || ''\"\r\n [style]=\"getStyleWithoutClasses(col?.scope?.style).style\"\r\n [showIcon]=\"false\" [showOnFocus]=\"false\" appendTo=\"body\"\r\n [panelStyleClass]=\"picker.datePanelClass\" [motionOptions]=\"picker.dockedMotion\"\r\n [vlCustomKeyboard]=\"col?.option?.keyboardType ?? 'date'\"\r\n (pointerdown)=\"picker.onFieldPointerDown($event, datePicker)\"\r\n (onFocus)=\"picker.onFieldFocus($event)\"\r\n (onShow)=\"picker.onShown()\"\r\n (onClose)=\"picker.onClose(datePicker)\">\r\n </p-datepicker>\r\n <button type=\"button\" class=\"picker-field__icon\" aria-label=\"Open calendar\"\r\n (pointerdown)=\"picker.openFromIcon($event, datePicker)\"\r\n (click)=\"picker.blockIconClick($event)\">\r\n <i class=\"pi pi-calendar\"></i>\r\n </button>\r\n </div>\r\n </ng-container>\r\n\r\n <ng-container\r\n *ngIf=\"tableitemInfo.propertySchema[getScope(col.scope?.reference)] && tableitemInfo.propertySchema[getScope(col.scope?.reference)][col?.scope?.reference?.split('/').pop()]?.type === 'time'\">\r\n <div class=\"picker-field\">\r\n <p-datepicker #timePicker #timeField=\"ngModel\"\r\n styleClass=\"custom-datepicker\"\r\n [required]=\"col.option.required\"\r\n [name]=\"col.scope?.reference\" [timeOnly]=\"true\"\r\n hourFormat=\"24\" [disabled]=\"col?.option?.disabled\" [autoZIndex]=\"true\"\r\n [baseZIndex]=\"10000\"\r\n [style]=\"getStyleWithoutClasses(col?.scope?.style).style\"\r\n [(ngModel)]=\"\r\n form.propertySchema[\r\n getScope(col.scope?.reference)\r\n ][\r\n col.scope?.reference.split('/').pop()\r\n ].value\r\n \"\r\n [class]=\"col?.scope?.style?.classes?.[0] || ''\"\r\n [showIcon]=\"false\" [showOnFocus]=\"false\" appendTo=\"body\"\r\n [panelStyleClass]=\"picker.timePanelClass\"\r\n [vlCustomKeyboard]=\"col?.option?.keyboardType ?? 'time'\"\r\n (pointerdown)=\"picker.onFieldPointerDown($event, timePicker)\"\r\n (onFocus)=\"picker.onFieldFocus($event)\"\r\n (onShow)=\"picker.onShown()\"\r\n (onClose)=\"picker.onClose(timePicker)\">\r\n </p-datepicker>\r\n <button type=\"button\" class=\"picker-field__icon\" aria-label=\"Open time picker\"\r\n (pointerdown)=\"picker.openFromIcon($event, timePicker)\"\r\n (click)=\"picker.blockIconClick($event)\">\r\n <i class=\"pi pi-clock\"></i>\r\n </button>\r\n </div>\r\n </ng-container>\r\n\r\n <ng-container\r\n *ngIf=\"tableitemInfo.propertySchema[getScope(col.scope?.reference)] && tableitemInfo.propertySchema[getScope(col.scope?.reference)][col?.scope?.reference?.split('/').pop()]?.type === 'autocomplete'\">\r\n <p-autocomplete [suggestions]=\"remoteSuggestions[col.scope?.reference] ?? []\" (completeMethod)=\"completeRemote($event, col)\" #autocompleteField=\"ngModel\"\r\n [required]=\"col.option.required\"\r\n [name]=\"col.scope?.reference\"\r\n styleClass=\"custom-autocomplete\"\r\n [(ngModel)]=\"form.propertySchema[getScope(col.scope?.reference)][col.scope?.reference.split('/').pop()].value\"\r\n [style]=\"getStyleWithoutClasses(col?.scope?.style).style\"\r\n [class]=\"col?.scope?.style?.classes ? col?.scope?.style?.classes[0] : ''\"\r\n [dropdown]=\"true\"\r\n [optionLabel]=\"col.option.autocomplete.response.label\"\r\n [placeholder]=\"form.propertySchema | vlPlaceholder: col.scope?.reference\"\r\n [vlCustomKeyboard]=\"col?.option?.keyboardType ?? 'string'\">\r\n </p-autocomplete>\r\n </ng-container>\r\n\r\n <ng-container\r\n *ngIf=\"tableitemInfo.propertySchema[getScope(col.scope?.reference)] && tableitemInfo.propertySchema[getScope(col.scope?.reference)][col?.scope?.reference?.split('/').pop()]?.type === 'dropdown'\">\r\n <select id=\"dynamic-dropdown\" #dropdownField=\"ngModel\"\r\n [ngClass]=\"getStyleWithoutClasses(col?.scope?.style)?.classes\"\r\n [ngStyle]=\"getStyleWithoutClasses(col?.scope?.style)?.style\"\r\n [name]=\"col.scope?.reference\"\r\n [(ngModel)]=\"\r\n form.propertySchema[getScope(col.scope?.reference)][\r\n col.scope?.reference.split('/').pop()\r\n ].value\r\n \">\r\n <option *ngFor=\"\r\n let item of form.propertySchema[getScope(col.scope?.reference)]?.[\r\n col.scope?.reference.split('/').pop()\r\n ]?.data\r\n \" [value]=\"item[col?.option?.optionValue]\">\r\n {{ item[col?.option?.optionLabel] }}\r\n </option>\r\n </select>\r\n </ng-container>\r\n\r\n <ng-container *ngIf=\"!col?.scope?.reference\">\r\n <span *ngIf=\"col.option?.actionColumn\">\r\n <span nz-icon\r\n *ngIf=\"setActionColumn(col.option?.save, data)\"\r\n [nzType]=\"col.option?.save?.icon\"\r\n [nzTheme]=\"'twotone'\"\r\n [style]=\"col.option?.save?.style\"\r\n [nzTwotoneColor]=\"'#52c41a'\"\r\n [class]=\"col.option?.save?.style?.classes[0]\"\r\n (click)=\"upsertAction(col.option?.save, data)\">\r\n </span>\r\n <span nz-icon\r\n *ngIf=\"setActionColumn(col.option?.delete, data)\"\r\n [nzType]=\"col.option?.delete?.icon\"\r\n [nzTheme]=\"'twotone'\"\r\n [style]=\"col.option?.delete?.style\"\r\n [nzTwotoneColor]=\"'#FF0000'\"\r\n [class]=\"col.option?.delete?.style?.classes[0]\"\r\n (click)=\"upsertAction(col.option?.delete, data)\"></span>\r\n\r\n </span>\r\n <span *ngIf=\"!col.option?.actionColumn\">\r\n <button type=\"submit\"\r\n [style]=\"getStyleWithoutClasses(col?.label?.style).style\"\r\n (click)=\"invokeGridBtnClick(col.option, data)\"\r\n [class]=\"col?.label?.style?.classes[0]\">\r\n {{ col.label?.caption }}\r\n </button>\r\n </span>\r\n </ng-container>\r\n\r\n <!-- For quantity column, display increment/decrement buttons -->\r\n <ng-container\r\n *ngIf=\"tableitemInfo.propertySchema[getScope(col.scope?.reference)] && tableitemInfo.propertySchema[getScope(col.scope?.reference)][col?.scope?.reference?.split('/').pop()]?.type === 'quantity'\">\r\n <div style=\"display: flex; align-items: center;\">\r\n <button pButton icon=\"pi pi-minus\"\r\n (click)=\"decrementQuantity(i,col.scope?.reference.split('/').pop(), col.option)\"\r\n [disabled]=\"data.quantity <= 0\"\r\n style=\"margin-right: 8px; height: 10px; width: 10px;\"></button>\r\n <span>{{ data[col.scope?.reference.split('/').pop()]\r\n }}</span>\r\n <button pButton icon=\"pi pi-plus\"\r\n (click)=\"incrementQuantity(i, col.scope?.reference.split('/').pop(), col.option)\"\r\n style=\"margin-left: 8px; height: 10px; width: 10px;\"></button>\r\n </div>\r\n </ng-container>\r\n </td>\r\n </tr>\r\n </tbody>\r\n </nz-table>\r\n</div>\r\n\r\n<!-- table footer -->\r\n<div *ngIf=\"tableitemInfo?.footer?.formFields && tableitemInfo.data?.length\"\r\n class=\"table-footer flex flex-column align-items-end gap-2 pt-2 mx-4 border-top-1 border-cyan-500\">\r\n <!-- @contract decision: the footer renders string and number only\r\n reality: the switch below carries those two cases and a default. It did NOT change\r\n when the columns gained their types on 2026-09-18.\r\n failure: any other type in a footer field renders empty.\r\n instead: keep aggregates numeric, or pre-format them as text in the endpoint. -->\r\n <div *ngFor=\"let tableField of tableitemInfo?.footer?.formFields\">\r\n <div\r\n [ngSwitch]=\"tableField?.scope?.reference && tableitemInfo.propertySchema[getScope(tableField.scope?.reference)] && tableitemInfo.propertySchema[getScope(tableField.scope?.reference)][tableField.scope?.reference.split('/').pop()] ?\r\n tableitemInfo.propertySchema[getScope(tableField.scope?.reference)][tableField.scope?.reference.split('/').pop()]?.type : 'default'\">\r\n\r\n <!-- string control -->\r\n <div *ngSwitchCase=\"'string'\" class=\"form-group\">\r\n <span *ngIf=\"tableField.option.protected\">\r\n <h5 style=\"display: flex; justify-content: space-between;\">\r\n <span\r\n [style]=\"getStyleWithoutClasses(tableField?.label?.style).style\"\r\n [class]=\"tableField?.label?.style?.classes[0]\">\r\n {{\r\n tableitemInfo.propertySchema[getScope(tableField.scope?.reference)][tableField.scope?.reference.split('/').pop()]?.caption\r\n }}\r\n </span>\r\n <span>\r\n {{\r\n tableitemInfo.propertySchema[getScope(tableField.scope?.reference)][tableField.scope?.reference.split('/').pop()]?.value\r\n }}\r\n </span>\r\n </h5>\r\n </span>\r\n <div *ngIf=\"!tableField.option.protected\">\r\n <div\r\n [class]=\"tableField?.layout == 'horizontal' ? 'horizontal-layout' : 'row'\">\r\n <label\r\n [style]=\"getStyleWithoutClasses(tableField?.label?.style).style\"\r\n [class]=\"tableField?.label?.style?.classes[0]\">{{\r\n tableField.label?.value ?\r\n tableField.label?.value :\r\n tableitemInfo.propertySchema[getScope(tableField.scope?.reference)][tableField.scope?.reference.split('/').pop()]?.caption\r\n }}</label>\r\n <input type=\"text\" #inputField=\"ngModel\"\r\n [required]=\"tableField.option.required\"\r\n [email]=\"tableField.option.email\"\r\n [class]=\"tableField.scope?.style?.classes[0]\"\r\n [style]=\"getStyleWithoutClasses(tableField?.scope?.style).style\"\r\n [(ngModel)]=\"tableitemInfo.propertySchema[getScope(tableField.scope?.reference)][tableField.scope?.reference.split('/').pop()].value\"\r\n [name]=\"tableField.scope?.reference\"\r\n [placeholder]=\"tableitemInfo.propertySchema | vlPlaceholder: tableField.scope?.reference\" />\r\n </div>\r\n <!-- Error Message -->\r\n <div *ngIf=\"inputField?.touched && inputField?.invalid\"\r\n [style]=\"getStyleWithoutClasses(tableField?.validation?.style).style\">\r\n <p class=\"text-danger\"\r\n *ngIf=\"inputField?.errors?.['required']\">{{tableField.label?.value\r\n ?\r\n tableField.label?.value :\r\n tableitemInfo.propertySchema[getScope(tableField.scope?.reference)][tableField.scope?.reference.split('/').pop()]?.caption\r\n +\r\n ' ' + errorMessages.required}}</p>\r\n <p class=\"text-danger\"\r\n *ngIf=\"inputField?.errors?.['email']\">{{(tableField.label?.value\r\n ?\r\n tableField.label?.value :\r\n tableitemInfo.propertySchema[getScope(tableField.scope?.reference)][tableField.scope?.reference.split('/').pop()]?.caption)\r\n +\r\n ' ' + errorMessages.pattern}}</p>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- number control -->\r\n <div *ngSwitchCase=\"'number'\" class=\"form-group\">\r\n <span *ngIf=\"tableField.option.protected\"\r\n [style]=\"getStyleWithoutClasses(tableField?.label?.style).style\"\r\n [class]=\"tableField?.label?.style?.classes[0]\">\r\n <h5>{{\r\n form.propertySchema[getScope(tableField.scope?.reference)][tableField.scope?.reference.split('/').pop()]?.caption\r\n }} {{\r\n form.propertySchema[getScope(tableField.scope?.reference)][tableField.scope?.reference.split('/').pop()]?.value\r\n |\r\n currency:tableField.option.currency :true:\r\n tableField.option?.decimalPoint}}\r\n </h5>\r\n </span>\r\n <span *ngIf=\"!tableField.option.protected\">\r\n <div\r\n [class]=\"tableField?.layout == 'horizontal' ? 'horizontal-layout' : 'row'\">\r\n <label\r\n [style]=\"getStyleWithoutClasses(tableField?.label?.style).style\"\r\n [class]=\"tableField?.label?.style?.classes[0]\">{{\r\n tableField.label?.value ?\r\n tableField.label?.value :\r\n form.propertySchema[getScope(tableField.scope?.reference)][tableField.scope?.reference.split('/').pop()]?.caption\r\n }}</label>\r\n <input type=\"number\"\r\n [class]=\"tableField.scope?.style?.classes[0]\"\r\n [style]=\"getStyleWithoutClasses(tableField?.scope?.style).style\"\r\n [(ngModel)]=\"form.propertySchema[getScope(tableField.scope?.reference)][tableField.scope?.reference.split('/').pop()].value\"\r\n [name]=\"tableField.scope?.reference\"\r\n [placeholder]=\"form.propertySchema | vlPlaceholder: tableField.scope?.reference\" />\r\n </div>\r\n </span>\r\n </div>\r\n\r\n <!-- button control -->\r\n <div *ngSwitchCase=\"'default'\">\r\n <button type=\"submit\"\r\n [style]=\"getStyleWithoutClasses(tableField.label.style).style\"\r\n (click)=\"invokeGridBtnClick(tableField.option, tableitemInfo.propertySchema)\">\r\n {{ tableField.label?.caption }}\r\n </button>\r\n </div>\r\n </div>\r\n </div>\r\n</div>\r\n\r\n<!-- bottom pagination on grid -->\r\n<div\r\n *ngIf=\"tableitemInfo.data?.length && !tableitemInfo?.layoutSchema?.pagination?.top && tableitemInfo?.layoutSchema?.pagination?.bottom\">\r\n <vl-pagination [itemInfo]=\"tableitemInfo\" [pageSize]=\"pageSize\"\r\n [currentPage]=\"currentPage\" [pages]=\"pages\"\r\n (pageSizeChange)=\"invokeOnPageSizeChange($event)\"\r\n (onGoToPage)=\"invokeGoToPage($event)\">\r\n </vl-pagination>\r\n</div>\r\n", styles: [".grid-filter-row th{padding:8px;vertical-align:middle;background:#fafafa}.grid-filter-cell{min-width:150px}.grid-filter-input-wrapper{display:flex;align-items:stretch;width:100%}.grid-filter-input{width:100%;min-width:0;min-height:34px;padding:5px 8px;border:1px solid #d9d9d9;border-right:0;border-radius:4px 0 0 4px;outline:none}.grid-filter-input:focus{border-color:#1677ff}.grid-filter-operator-button,.grid-filter-clear-button{display:inline-flex;align-items:center;justify-content:center;min-width:36px;min-height:34px;padding:0;cursor:pointer;background:#fff;border:1px solid #d9d9d9}.grid-filter-operator-button{color:#595959;border-radius:0 4px 4px 0}.grid-filter-operator-button:hover,.grid-filter-operator-button--active{color:#1677ff;border-color:#1677ff}.grid-filter-clear-button{margin-left:5px;color:#ff4d4f;border-radius:4px}.grid-filter-clear-button:hover{color:#fff;background:#ff4d4f;border-color:#ff4d4f}.grid-filter-operator-menu{min-width:190px}:host ::ng-deep .ant-table-content.has-more-right{-webkit-mask-image:linear-gradient(to right,#000 calc(100% - 36px),transparent);mask-image:linear-gradient(to right,#000 calc(100% - 36px),transparent)}:host ::ng-deep .ant-table-content.has-more-left{-webkit-mask-image:linear-gradient(to left,#000 calc(100% - 36px),transparent);mask-image:linear-gradient(to left,#000 calc(100% - 36px),transparent)}:host ::ng-deep .ant-table-content.has-more-left.has-more-right{-webkit-mask-image:linear-gradient(to right,transparent,#000 36px,#000 calc(100% - 36px),transparent);mask-image:linear-gradient(to right,transparent,#000 36px,#000 calc(100% - 36px),transparent)}\n"] }]
5530
+ ], selector: 'vl-grid', template: "<!-- Faramarz Yousefian and Agent Toni (Claude Opus 5.5) 2026-10-13\r\n - new: autocompletes get their suggestions from RemoteListService (completeRemote) -->\r\n<!-- Faramarz Yousefian and Agent Toni (Claude Opus 5.5) 2026-10-13\r\n - fix: the placeholder comes from vlPlaceholder (pipes/placeholder.pipe.ts) - empty where the\r\n project defines none; it showed the text \"undefined\" -->\r\n<!-- Faramarz Yousefian and Agent Toni (Claude Opus 5) 2026-10-07\r\n - change: autocomplete fields take the toolkit string keyboard unless option.keyboardType\r\n names another one ('native' keeps the system keyboard)\r\n - change: date and time cells use the shared picker markup (picker-field, DateTimePickerService);\r\n their PrimeNG icon opened the calendar together with the system keyboard -->\r\n\r\n<!-- Shuaib 2026-09-24\r\n - change: grid cells render legacy checkbox fields through the boolean control. -->\r\n\r\n<!-- Faramarz Yousefian and Agent Toni (Claude Opus 5) 2026-09-19\r\n - new: @contract comments on the sorting, on the column filter and on the footer. The filter\r\n reads option.filter and never option.columnFilter, which is the mistake a layout author\r\n makes without being told -->\r\n<div *ngIf=\"!tableitemInfo.data?.length\" class=\"alert alert-warning col-md-12\"\r\n role=\"alert\">\r\n {{ tableitemInfo.layoutSchema?.noRecordMessage}}\r\n</div>\r\n<div *ngIf=\"tableitemInfo.data?.length\" class=\"reservation-container pt-5 px-3\">\r\n <nz-table #basicTable [nzData]=\"gridDisplayData\"\r\n [nzNoResult]=\"'No matching records found'\" [nzBordered]=\"true\"\r\n [nzFrontPagination]=\"currenTableOptions?.pagination?.tabs\"\r\n [style]=\"getStyleWithoutClasses(currenTableOptions?.style).style\"\r\n (scroll)=\"onScrollEvent($event)\"\r\n [nzLoading]=\"isTableDataLoad\">\r\n <thead>\r\n <!-- @contract decision: option.sortable is read here\r\n reality: nzSortFn is wired to getColumnSortFn since 2026-09-16; before that\r\n the key was decoration. The column also needs a scope.reference -\r\n without one getColumnSortFn has nothing to sort by.\r\n seen: grid.component.ts:338 -->\r\n <!-- Column headings and sorting -->\r\n <tr>\r\n <th *ngFor=\"let column of tableitemInfo.layoutSchema.elements\"\r\n [nzSortFn]=\"\r\n column?.option?.sortable\r\n ? getColumnSortFn(column)\r\n : false\r\n \">\r\n\r\n {{ column?.label?.caption }}\r\n </th>\r\n </tr>\r\n\r\n <!-- @contract decision: the column filter reads option.filter, NOT option.columnFilter\r\n reality: option.filter.filtering switches it on, option.filter.defaultOperator\r\n starts the comparison (the renderer falls back to contains), and\r\n option.filter.placeholder labels the input.\r\n failure: option.columnFilter is read nowhere, here or in the runtime app. A\r\n column carrying it looks filterable in the file and is not on screen.\r\n seen: grid.component.ts:450-475; 5 uses of columnFilter across the reference\r\n projects, all of them dead -->\r\n <!-- Column filters -->\r\n <tr *ngIf=\"hasAnyColumnFilter()\" class=\"grid-filter-row\">\r\n\r\n <th *ngFor=\"let column of tableitemInfo.layoutSchema.elements\"\r\n class=\"grid-filter-cell\">\r\n\r\n <ng-container *ngIf=\"\r\n column?.option?.filter?.filtering === true &&\r\n column?.scope?.reference\r\n \">\r\n\r\n <div class=\"grid-filter-input-wrapper\">\r\n <input type=\"text\" class=\"grid-filter-input\"\r\n [placeholder]=\"getColumnFilterPlaceholder(column)\"\r\n [ngModel]=\"getColumnFilterState(column).value\"\r\n (ngModelChange)=\"\r\n setColumnFilterValue(column, $event)\r\n \" />\r\n\r\n <!-- Operator selection button -->\r\n <button type=\"button\"\r\n class=\"grid-filter-operator-button\" nz-dropdown\r\n nzTrigger=\"click\"\r\n [nzDropdownMenu]=\"operatorMenu\"\r\n [class.grid-filter-operator-button--active]=\"\r\n hasActiveColumnFilter(column)\r\n \" [title]=\"\r\n 'Operator: ' +\r\n getFilterOperatorLabel(\r\n getColumnFilterState(column).operator\r\n )\r\n \">\r\n\r\n <span nz-icon nzType=\"filter\"></span>\r\n </button>\r\n\r\n <!-- Clear current column filter -->\r\n <button *ngIf=\"hasActiveColumnFilter(column)\"\r\n type=\"button\" class=\"grid-filter-clear-button\"\r\n aria-label=\"Clear column filter\"\r\n title=\"Clear filter\"\r\n (click)=\"clearColumnFilter(column)\">\r\n\r\n <span nz-icon nzType=\"close\"></span>\r\n </button>\r\n </div>\r\n\r\n <!-- Operator dropdown -->\r\n <nz-dropdown-menu #operatorMenu=\"nzDropdownMenu\">\r\n <ul nz-menu class=\"grid-filter-operator-menu\">\r\n <li *ngFor=\"let operator of filterOperators\"\r\n nz-menu-item [nzSelected]=\"\r\n getColumnFilterState(column).operator ===\r\n operator.value\r\n \" (click)=\"\r\n setColumnFilterOperator(\r\n column,\r\n operator.value\r\n )\r\n \">\r\n\r\n <span *ngIf=\"\r\n getColumnFilterState(column).operator ===\r\n operator.value\r\n \" nz-icon nzType=\"check\">\r\n </span>\r\n\r\n {{ operator.label }}\r\n </li>\r\n </ul>\r\n </nz-dropdown-menu>\r\n </ng-container>\r\n </th>\r\n </tr>\r\n </thead>\r\n <!-- @contract decision: the column chain below, and what it does not carry\r\n reality: string, number, image, quantity, date, time, dropdown, boolean,\r\n autocomplete and dateRange each have their own condition. There is no\r\n branch for the credit card type.\r\n failure: a column whose type has no branch stays empty, with no error.\r\n instead: format the value in the endpoint and send a string.\r\n\r\n @contract decision: columns without scope.reference are valid\r\n reality: with option.actionColumn they render save/delete icons, otherwise a\r\n button. That is why the conditions below all guard on the reference. -->\r\n <tbody>\r\n <tr *ngFor=\"let data of basicTable.data; let i = index\">\r\n <td *ngFor=\"let col of tableitemInfo.layoutSchema.elements\"\r\n [style]=\"getStyleWithoutClasses(col?.scope?.style).style\">\r\n <ng-container\r\n *ngIf=\"tableitemInfo.propertySchema[getScope(col.scope?.reference)] && tableitemInfo.propertySchema[getScope(col.scope?.reference)][col?.scope?.reference?.split('/').pop()]?.type === 'string'\"\r\n [class]=\"getStyleWithoutClasses(col?.scope?.style).classes\"\r\n [style]=\"getStyleWithoutClasses(col?.scope?.style).style\">\r\n <span *ngIf=\"col.option.protected\">\r\n <span *ngIf=\"col.option?.link\"\r\n (click)=\"showLinkDetails(col.option, data)\">\r\n {{data[col.scope?.reference.split('/').pop()]}}\r\n </span>\r\n <span *ngIf=\"!col.option?.link\">\r\n <ng-container\r\n *ngIf=\"col?.option?.dateFormat; else string\">\r\n {{\r\n data[col.scope?.reference.split('/').pop()]\r\n | date:'yyyy-MM-dd' }}\r\n </ng-container>\r\n <ng-template #string>\r\n {{\r\n data[col.scope?.reference.split('/').pop()]\r\n }}\r\n </ng-template>\r\n </span>\r\n </span>\r\n <span *ngIf=\"!col.option.protected\">\r\n <input\r\n [(ngModel)]=\"data[col.scope?.reference.split('/').pop()]\"\r\n class=\"p-inputtext p-component\" />\r\n </span>\r\n </ng-container>\r\n\r\n <ng-container\r\n *ngIf=\"tableitemInfo.propertySchema[getScope(col.scope?.reference)] && tableitemInfo.propertySchema[getScope(col.scope?.reference)][col?.scope?.reference?.split('/').pop()]?.type === 'number'\">\r\n <span *ngIf=\"col.option.protected\">\r\n <span\r\n *ngIf=\"col.option?.innerAction?.action == 'multiply'\">\r\n {{\r\n (data[col.option?.innerAction?.from] *\r\n data[col.option?.innerAction?.to])\r\n | number:'1.2-2'\r\n }}\r\n </span>\r\n <span *ngIf=\"!col.option?.innerAction\">\r\n {{data[col.scope?.reference.split('/').pop()] |\r\n currency:\r\n tableitemInfo.propertySchema[getScope(col.scope?.reference)][col?.scope?.reference?.split('/').pop()]?.currency\r\n :true }}\r\n </span>\r\n </span>\r\n <span *ngIf=\"!col.option.protected\">\r\n <input\r\n [(ngModel)]=\"data[col.scope?.reference.split('/').pop()]\"\r\n type=\"number\"\r\n class=\"p-inputtext p-component\" />\r\n </span>\r\n </ng-container>\r\n\r\n <!-- Media control: also supports existing image properties -->\r\n <ng-container *ngIf=\"isMediaColumn(col)\">\r\n <ng-container\r\n *ngIf=\"getMediaSource(col, data) as source\">\r\n <ng-container [ngSwitch]=\"getMediaKind(col, data)\">\r\n\r\n <img\r\n *ngSwitchDefault\r\n [src]=\"source\"\r\n [alt]=\"getMediaLabel(col)\"\r\n [class]=\"getStyleWithoutClasses(col?.scope?.style).classes\"\r\n [ngStyle]=\"getStyleWithoutClasses(col?.scope?.style).style\"\r\n loading=\"lazy\"\r\n (click)=\"invokeTableImageClick(col, data)\" />\r\n\r\n <video\r\n *ngSwitchCase=\"'video'\"\r\n [src]=\"source\"\r\n [attr.aria-label]=\"getMediaLabel(col)\"\r\n [class]=\"getStyleWithoutClasses(col?.scope?.style).classes\"\r\n [ngStyle]=\"getStyleWithoutClasses(col?.scope?.style).style\"\r\n controls\r\n playsinline\r\n preload=\"metadata\">\r\n Your browser does not support video\r\n playback.\r\n </video>\r\n\r\n <audio\r\n *ngSwitchCase=\"'audio'\"\r\n [src]=\"source\"\r\n [attr.aria-label]=\"getMediaLabel(col)\"\r\n [class]=\"getStyleWithoutClasses(col?.scope?.style).classes\"\r\n [ngStyle]=\"getStyleWithoutClasses(col?.scope?.style).style\"\r\n controls\r\n preload=\"metadata\">\r\n Your browser does not support audio\r\n playback.\r\n </audio>\r\n\r\n <a\r\n *ngSwitchCase=\"'pdf'\"\r\n [href]=\"source\"\r\n [class]=\"getStyleWithoutClasses(col?.scope?.style).classes\"\r\n [ngStyle]=\"getStyleWithoutClasses(col?.scope?.style).style\"\r\n target=\"_blank\"\r\n rel=\"noopener noreferrer\">\r\n Open PDF \u2014 {{ getMediaLabel(col) }}\r\n </a>\r\n\r\n <a\r\n *ngSwitchCase=\"'file'\"\r\n [href]=\"source\"\r\n [class]=\"getStyleWithoutClasses(col?.scope?.style).classes\"\r\n [ngStyle]=\"getStyleWithoutClasses(col?.scope?.style).style\"\r\n target=\"_blank\"\r\n rel=\"noopener noreferrer\">\r\n Open file \u2014 {{ getMediaLabel(col) }}\r\n </a>\r\n\r\n </ng-container>\r\n </ng-container>\r\n </ng-container>\r\n\r\n <!-- @contract compatibility: existing checkbox fields render as boolean. -->\r\n <ng-container\r\n *ngIf=\"tableitemInfo.propertySchema[getScope(col.scope?.reference)] && (tableitemInfo.propertySchema[getScope(col.scope?.reference)][col?.scope?.reference?.split('/').pop()]?.type === 'boolean' || isLegacyCheckboxFieldType(tableitemInfo.propertySchema[getScope(col.scope?.reference)][col?.scope?.reference?.split('/').pop()]?.type))\">\r\n <input type=\"checkbox\"\r\n [style]=\"getStyleWithoutClasses(col?.scope?.style).style\"\r\n class=\"form-check-input mr-2\"\r\n [(ngModel)]=\"data[col.scope?.reference.split('/').pop()]\"\r\n [name]=\"col.scope?.reference\" />\r\n </ng-container>\r\n\r\n <ng-container\r\n *ngIf=\"tableitemInfo.propertySchema[getScope(col.scope?.reference)] && tableitemInfo.propertySchema[getScope(col.scope?.reference)][col?.scope?.reference?.split('/').pop()]?.type === 'dateRange'\">\r\n <nz-range-picker #dateRangeField=\"ngModel\"\r\n [required]=\"col.option.required\"\r\n [name]=\"col.scope?.reference\"\r\n [style]=\"getStyleWithoutClasses(col?.style).style\"\r\n [(ngModel)]=\"tableitemInfo.propertySchema[getScope(col.scope?.reference)][col.scope?.reference.split('/').pop()].value\"></nz-range-picker>\r\n </ng-container>\r\n\r\n <ng-container\r\n *ngIf=\"tableitemInfo.propertySchema[getScope(col.scope?.reference)] && tableitemInfo.propertySchema[getScope(col.scope?.reference)][col?.scope?.reference?.split('/').pop()]?.type === 'date'\">\r\n <div class=\"picker-field\">\r\n <p-datepicker #datePicker #dateField=\"ngModel\"\r\n styleClass=\"custom-datepicker\"\r\n [required]=\"col.option.required\"\r\n [name]=\"col.scope?.reference\"\r\n [disabled]=\"col?.option?.disabled\"\r\n [autoZIndex]=\"true\" [baseZIndex]=\"10000\"\r\n [dateFormat]=\"\r\n tableitemInfo.propertySchema[\r\n getScope(col.scope?.reference)\r\n ][\r\n col.scope?.reference.split('/').pop()\r\n ]?.format || 'yy-mm-dd'\r\n \" [(ngModel)]=\"\r\n form.propertySchema[\r\n getScope(col.scope?.reference)\r\n ][\r\n col.scope?.reference.split('/').pop()\r\n ].value\r\n \" [class]=\"col?.scope?.style?.classes?.[0] || ''\"\r\n [style]=\"getStyleWithoutClasses(col?.scope?.style).style\"\r\n [showIcon]=\"false\" [showOnFocus]=\"false\"\r\n appendTo=\"body\"\r\n [panelStyleClass]=\"picker.datePanelClass\"\r\n [motionOptions]=\"picker.dockedMotion\"\r\n [vlCustomKeyboard]=\"col?.option?.keyboardType ?? 'date'\"\r\n (pointerdown)=\"picker.onFieldPointerDown($event, datePicker)\"\r\n (onFocus)=\"picker.onFieldFocus($event)\"\r\n (onShow)=\"picker.onShown()\"\r\n (onClose)=\"picker.onClose(datePicker)\">\r\n </p-datepicker>\r\n <button type=\"button\" class=\"picker-field__icon\"\r\n aria-label=\"Open calendar\"\r\n (pointerdown)=\"picker.openFromIcon($event, datePicker)\"\r\n (click)=\"picker.blockIconClick($event)\">\r\n <i class=\"pi pi-calendar\"></i>\r\n </button>\r\n </div>\r\n </ng-container>\r\n\r\n <ng-container\r\n *ngIf=\"tableitemInfo.propertySchema[getScope(col.scope?.reference)] && tableitemInfo.propertySchema[getScope(col.scope?.reference)][col?.scope?.reference?.split('/').pop()]?.type === 'time'\">\r\n <div class=\"picker-field\">\r\n <p-datepicker #timePicker #timeField=\"ngModel\"\r\n styleClass=\"custom-datepicker\"\r\n [required]=\"col.option.required\"\r\n [name]=\"col.scope?.reference\" [timeOnly]=\"true\"\r\n hourFormat=\"24\"\r\n [disabled]=\"col?.option?.disabled\"\r\n [autoZIndex]=\"true\"\r\n [baseZIndex]=\"10000\"\r\n [style]=\"getStyleWithoutClasses(col?.scope?.style).style\"\r\n [(ngModel)]=\"\r\n form.propertySchema[\r\n getScope(col.scope?.reference)\r\n ][\r\n col.scope?.reference.split('/').pop()\r\n ].value\r\n \"\r\n [class]=\"col?.scope?.style?.classes?.[0] || ''\"\r\n [showIcon]=\"false\" [showOnFocus]=\"false\"\r\n appendTo=\"body\"\r\n [panelStyleClass]=\"picker.timePanelClass\"\r\n [vlCustomKeyboard]=\"col?.option?.keyboardType ?? 'time'\"\r\n (pointerdown)=\"picker.onFieldPointerDown($event, timePicker)\"\r\n (onFocus)=\"picker.onFieldFocus($event)\"\r\n (onShow)=\"picker.onShown()\"\r\n (onClose)=\"picker.onClose(timePicker)\">\r\n </p-datepicker>\r\n <button type=\"button\" class=\"picker-field__icon\"\r\n aria-label=\"Open time picker\"\r\n (pointerdown)=\"picker.openFromIcon($event, timePicker)\"\r\n (click)=\"picker.blockIconClick($event)\">\r\n <i class=\"pi pi-clock\"></i>\r\n </button>\r\n </div>\r\n </ng-container>\r\n\r\n <ng-container\r\n *ngIf=\"tableitemInfo.propertySchema[getScope(col.scope?.reference)] && tableitemInfo.propertySchema[getScope(col.scope?.reference)][col?.scope?.reference?.split('/').pop()]?.type === 'autocomplete'\">\r\n <p-autocomplete\r\n [suggestions]=\"remoteSuggestions[col.scope?.reference] ?? []\"\r\n (completeMethod)=\"completeRemote($event, col)\"\r\n #autocompleteField=\"ngModel\"\r\n [required]=\"col.option.required\"\r\n [name]=\"col.scope?.reference\"\r\n styleClass=\"custom-autocomplete\"\r\n [(ngModel)]=\"form.propertySchema[getScope(col.scope?.reference)][col.scope?.reference.split('/').pop()].value\"\r\n [style]=\"getStyleWithoutClasses(col?.scope?.style).style\"\r\n [class]=\"col?.scope?.style?.classes ? col?.scope?.style?.classes[0] : ''\"\r\n [dropdown]=\"true\"\r\n [optionLabel]=\"col.option.autocomplete.response.label\"\r\n [placeholder]=\"form.propertySchema | vlPlaceholder: col.scope?.reference\"\r\n [vlCustomKeyboard]=\"col?.option?.keyboardType ?? 'string'\">\r\n </p-autocomplete>\r\n </ng-container>\r\n\r\n <ng-container\r\n *ngIf=\"tableitemInfo.propertySchema[getScope(col.scope?.reference)] && tableitemInfo.propertySchema[getScope(col.scope?.reference)][col?.scope?.reference?.split('/').pop()]?.type === 'dropdown'\">\r\n <select id=\"dynamic-dropdown\" #dropdownField=\"ngModel\"\r\n [ngClass]=\"getStyleWithoutClasses(col?.scope?.style)?.classes\"\r\n [ngStyle]=\"getStyleWithoutClasses(col?.scope?.style)?.style\"\r\n [name]=\"col.scope?.reference\"\r\n [(ngModel)]=\"\r\n form.propertySchema[getScope(col.scope?.reference)][\r\n col.scope?.reference.split('/').pop()\r\n ].value\r\n \">\r\n <option *ngFor=\"\r\n let item of form.propertySchema[getScope(col.scope?.reference)]?.[\r\n col.scope?.reference.split('/').pop()\r\n ]?.data\r\n \" [value]=\"item[col?.option?.optionValue]\">\r\n {{ item[col?.option?.optionLabel] }}\r\n </option>\r\n </select>\r\n </ng-container>\r\n\r\n <ng-container *ngIf=\"!col?.scope?.reference\">\r\n <span *ngIf=\"col.option?.actionColumn\">\r\n <span nz-icon\r\n *ngIf=\"setActionColumn(col.option?.save, data)\"\r\n [nzType]=\"col.option?.save?.icon\"\r\n [nzTheme]=\"'twotone'\"\r\n [style]=\"col.option?.save?.style\"\r\n [nzTwotoneColor]=\"'#52c41a'\"\r\n [class]=\"col.option?.save?.style?.classes[0]\"\r\n (click)=\"upsertAction(col.option?.save, data)\">\r\n </span>\r\n <span nz-icon\r\n *ngIf=\"setActionColumn(col.option?.delete, data)\"\r\n [nzType]=\"col.option?.delete?.icon\"\r\n [nzTheme]=\"'twotone'\"\r\n [style]=\"col.option?.delete?.style\"\r\n [nzTwotoneColor]=\"'#FF0000'\"\r\n [class]=\"col.option?.delete?.style?.classes[0]\"\r\n (click)=\"upsertAction(col.option?.delete, data)\"></span>\r\n\r\n </span>\r\n <span *ngIf=\"!col.option?.actionColumn\">\r\n <button type=\"submit\"\r\n [style]=\"getStyleWithoutClasses(col?.label?.style).style\"\r\n (click)=\"invokeGridBtnClick(col.option, data)\"\r\n [class]=\"col?.label?.style?.classes[0]\">\r\n {{ col.label?.caption }}\r\n </button>\r\n </span>\r\n </ng-container>\r\n\r\n <!-- For quantity column, display increment/decrement buttons -->\r\n <ng-container\r\n *ngIf=\"tableitemInfo.propertySchema[getScope(col.scope?.reference)] && tableitemInfo.propertySchema[getScope(col.scope?.reference)][col?.scope?.reference?.split('/').pop()]?.type === 'quantity'\">\r\n <div style=\"display: flex; align-items: center;\">\r\n <button pButton icon=\"pi pi-minus\"\r\n (click)=\"decrementQuantity(i,col.scope?.reference.split('/').pop(), col.option)\"\r\n [disabled]=\"data.quantity <= 0\"\r\n style=\"margin-right: 8px; height: 10px; width: 10px;\"></button>\r\n <span>{{ data[col.scope?.reference.split('/').pop()]\r\n }}</span>\r\n <button pButton icon=\"pi pi-plus\"\r\n (click)=\"incrementQuantity(i, col.scope?.reference.split('/').pop(), col.option)\"\r\n style=\"margin-left: 8px; height: 10px; width: 10px;\"></button>\r\n </div>\r\n </ng-container>\r\n </td>\r\n </tr>\r\n </tbody>\r\n </nz-table>\r\n</div>\r\n\r\n<!-- table footer -->\r\n<div *ngIf=\"tableitemInfo?.footer?.formFields && tableitemInfo.data?.length\"\r\n class=\"table-footer flex flex-column align-items-end gap-2 pt-2 mx-4 border-top-1 border-cyan-500\">\r\n <!-- @contract decision: the footer renders string and number only\r\n reality: the switch below carries those two cases and a default. It did NOT change\r\n when the columns gained their types on 2026-09-18.\r\n failure: any other type in a footer field renders empty.\r\n instead: keep aggregates numeric, or pre-format them as text in the endpoint. -->\r\n <div *ngFor=\"let tableField of tableitemInfo?.footer?.formFields\">\r\n <div\r\n [ngSwitch]=\"tableField?.scope?.reference && tableitemInfo.propertySchema[getScope(tableField.scope?.reference)] && tableitemInfo.propertySchema[getScope(tableField.scope?.reference)][tableField.scope?.reference.split('/').pop()] ?\r\n tableitemInfo.propertySchema[getScope(tableField.scope?.reference)][tableField.scope?.reference.split('/').pop()]?.type : 'default'\">\r\n\r\n <!-- string control -->\r\n <div *ngSwitchCase=\"'string'\" class=\"form-group\">\r\n <span *ngIf=\"tableField.option.protected\">\r\n <h5 style=\"display: flex; justify-content: space-between;\">\r\n <span\r\n [style]=\"getStyleWithoutClasses(tableField?.label?.style).style\"\r\n [class]=\"tableField?.label?.style?.classes[0]\">\r\n {{\r\n tableitemInfo.propertySchema[getScope(tableField.scope?.reference)][tableField.scope?.reference.split('/').pop()]?.caption\r\n }}\r\n </span>\r\n <span>\r\n {{\r\n tableitemInfo.propertySchema[getScope(tableField.scope?.reference)][tableField.scope?.reference.split('/').pop()]?.value\r\n }}\r\n </span>\r\n </h5>\r\n </span>\r\n <div *ngIf=\"!tableField.option.protected\">\r\n <div\r\n [class]=\"tableField?.layout == 'horizontal' ? 'horizontal-layout' : 'row'\">\r\n <label\r\n [style]=\"getStyleWithoutClasses(tableField?.label?.style).style\"\r\n [class]=\"tableField?.label?.style?.classes[0]\">{{\r\n tableField.label?.value ?\r\n tableField.label?.value :\r\n tableitemInfo.propertySchema[getScope(tableField.scope?.reference)][tableField.scope?.reference.split('/').pop()]?.caption\r\n }}</label>\r\n <input type=\"text\" #inputField=\"ngModel\"\r\n [required]=\"tableField.option.required\"\r\n [email]=\"tableField.option.email\"\r\n [class]=\"tableField.scope?.style?.classes[0]\"\r\n [style]=\"getStyleWithoutClasses(tableField?.scope?.style).style\"\r\n [(ngModel)]=\"tableitemInfo.propertySchema[getScope(tableField.scope?.reference)][tableField.scope?.reference.split('/').pop()].value\"\r\n [name]=\"tableField.scope?.reference\"\r\n [placeholder]=\"tableitemInfo.propertySchema | vlPlaceholder: tableField.scope?.reference\" />\r\n </div>\r\n <!-- Error Message -->\r\n <div *ngIf=\"inputField?.touched && inputField?.invalid\"\r\n [style]=\"getStyleWithoutClasses(tableField?.validation?.style).style\">\r\n <p class=\"text-danger\"\r\n *ngIf=\"inputField?.errors?.['required']\">{{tableField.label?.value\r\n ?\r\n tableField.label?.value :\r\n tableitemInfo.propertySchema[getScope(tableField.scope?.reference)][tableField.scope?.reference.split('/').pop()]?.caption\r\n +\r\n ' ' + errorMessages.required}}</p>\r\n <p class=\"text-danger\"\r\n *ngIf=\"inputField?.errors?.['email']\">{{(tableField.label?.value\r\n ?\r\n tableField.label?.value :\r\n tableitemInfo.propertySchema[getScope(tableField.scope?.reference)][tableField.scope?.reference.split('/').pop()]?.caption)\r\n +\r\n ' ' + errorMessages.pattern}}</p>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- number control -->\r\n <div *ngSwitchCase=\"'number'\" class=\"form-group\">\r\n <span *ngIf=\"tableField.option.protected\"\r\n [style]=\"getStyleWithoutClasses(tableField?.label?.style).style\"\r\n [class]=\"tableField?.label?.style?.classes[0]\">\r\n <h5>{{\r\n form.propertySchema[getScope(tableField.scope?.reference)][tableField.scope?.reference.split('/').pop()]?.caption\r\n }} {{\r\n form.propertySchema[getScope(tableField.scope?.reference)][tableField.scope?.reference.split('/').pop()]?.value\r\n |\r\n currency:tableField.option.currency :true:\r\n tableField.option?.decimalPoint}}\r\n </h5>\r\n </span>\r\n <span *ngIf=\"!tableField.option.protected\">\r\n <div\r\n [class]=\"tableField?.layout == 'horizontal' ? 'horizontal-layout' : 'row'\">\r\n <label\r\n [style]=\"getStyleWithoutClasses(tableField?.label?.style).style\"\r\n [class]=\"tableField?.label?.style?.classes[0]\">{{\r\n tableField.label?.value ?\r\n tableField.label?.value :\r\n form.propertySchema[getScope(tableField.scope?.reference)][tableField.scope?.reference.split('/').pop()]?.caption\r\n }}</label>\r\n <input type=\"number\"\r\n [class]=\"tableField.scope?.style?.classes[0]\"\r\n [style]=\"getStyleWithoutClasses(tableField?.scope?.style).style\"\r\n [(ngModel)]=\"form.propertySchema[getScope(tableField.scope?.reference)][tableField.scope?.reference.split('/').pop()].value\"\r\n [name]=\"tableField.scope?.reference\"\r\n [placeholder]=\"form.propertySchema | vlPlaceholder: tableField.scope?.reference\" />\r\n </div>\r\n </span>\r\n </div>\r\n\r\n <!-- button control -->\r\n <div *ngSwitchCase=\"'default'\">\r\n <button type=\"submit\"\r\n [style]=\"getStyleWithoutClasses(tableField.label.style).style\"\r\n (click)=\"invokeGridBtnClick(tableField.option, tableitemInfo.propertySchema)\">\r\n {{ tableField.label?.caption }}\r\n </button>\r\n </div>\r\n </div>\r\n </div>\r\n</div>\r\n\r\n<!-- bottom pagination on grid -->\r\n<div\r\n *ngIf=\"tableitemInfo.data?.length && !tableitemInfo?.layoutSchema?.pagination?.top && tableitemInfo?.layoutSchema?.pagination?.bottom\">\r\n <vl-pagination [itemInfo]=\"tableitemInfo\" [pageSize]=\"pageSize\"\r\n [currentPage]=\"currentPage\" [pages]=\"pages\"\r\n (pageSizeChange)=\"invokeOnPageSizeChange($event)\"\r\n (onGoToPage)=\"invokeGoToPage($event)\">\r\n </vl-pagination>\r\n</div>\r\n", styles: [".grid-filter-row th{padding:8px;vertical-align:middle;background:#fafafa}.grid-filter-cell{min-width:150px}.grid-filter-input-wrapper{display:flex;align-items:stretch;width:100%}.grid-filter-input{width:100%;min-width:0;min-height:34px;padding:5px 8px;border:1px solid #d9d9d9;border-right:0;border-radius:4px 0 0 4px;outline:none}.grid-filter-input:focus{border-color:#1677ff}.grid-filter-operator-button,.grid-filter-clear-button{display:inline-flex;align-items:center;justify-content:center;min-width:36px;min-height:34px;padding:0;cursor:pointer;background:#fff;border:1px solid #d9d9d9}.grid-filter-operator-button{color:#595959;border-radius:0 4px 4px 0}.grid-filter-operator-button:hover,.grid-filter-operator-button--active{color:#1677ff;border-color:#1677ff}.grid-filter-clear-button{margin-left:5px;color:#ff4d4f;border-radius:4px}.grid-filter-clear-button:hover{color:#fff;background:#ff4d4f;border-color:#ff4d4f}.grid-filter-operator-menu{min-width:190px}:host ::ng-deep .ant-table-content.has-more-right{-webkit-mask-image:linear-gradient(to right,#000 calc(100% - 36px),transparent);mask-image:linear-gradient(to right,#000 calc(100% - 36px),transparent)}:host ::ng-deep .ant-table-content.has-more-left{-webkit-mask-image:linear-gradient(to left,#000 calc(100% - 36px),transparent);mask-image:linear-gradient(to left,#000 calc(100% - 36px),transparent)}:host ::ng-deep .ant-table-content.has-more-left.has-more-right{-webkit-mask-image:linear-gradient(to right,transparent,#000 36px,#000 calc(100% - 36px),transparent);mask-image:linear-gradient(to right,transparent,#000 36px,#000 calc(100% - 36px),transparent)}\n"] }]
5299
5531
  }], ctorParameters: () => [{ type: RequestService }, { type: UtilityService }, { type: NotificationService }, { type: i4$1.OktaAuthStateService }], propDecorators: { errorMessages: [{
5300
5532
  type: Input
5301
5533
  }], environment: [{
@@ -5461,7 +5693,7 @@ class HeaderMenuComponent {
5461
5693
  const logoUrl = item?.option?.src;
5462
5694
  if (logoUrl && this.projectSeleted) {
5463
5695
  let projectName = `${this.tenantName}_${this.projectSeleted}`;
5464
- const image = await this.couchdbService.getFileContentFromCouchDb(projectName, `Media/${logoUrl}`);
5696
+ const image = await this.couchdbService.getImageSrcFromCouchDb(projectName, `${logoUrl}`);
5465
5697
  item.option.src = this.utilityService.getMediaSrc(image);
5466
5698
  }
5467
5699
  }
@@ -5469,7 +5701,7 @@ class HeaderMenuComponent {
5469
5701
  return items;
5470
5702
  }
5471
5703
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.2", ngImport: i0, type: HeaderMenuComponent, deps: [{ token: i4$1.OktaAuthStateService }, { token: RequestService }, { token: UtilityService }, { token: Couchdb }, { token: i1.Platform }], target: i0.ɵɵFactoryTarget.Component });
5472
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.2", type: HeaderMenuComponent, isStandalone: true, selector: "vl-header-menu", inputs: { headerItems: "headerItems", headerLayout: "headerLayout", environment: "environment", tenantName: "tenantName", projectSeleted: "projectSeleted", cartInfo: "cartInfo" }, outputs: { buttonClick: "buttonClick", showTableContent: "showTableContent", searchItems: "searchItems" }, usesOnChanges: true, ngImport: i0, template: "<!-- Faramarz Yousefian and Agent Toni (Claude Opus 5.5) 2026-10-13\r\n - fix: a field without a placeholder in the project stays empty; it showed the text \"undefined\" -->\r\n<!-- Faramarz Yousefian and Agent Toni (Claude Opus 5) 2026-09-19\r\n - new: a @contract comment stating that this container resolves by field NAME, not by field\r\n type. A correctly typed field with another name renders nothing, silently -->\r\n<header *ngIf=\"headerItems.length > 0\" [ngStyle]=\"getStyle(headerLayout?.style)\">\r\n\r\n <!-- @contract decision: resolves by field NAME, not by field type\r\n reality: the switch reads the LAST segment of scope.reference. Only logo, cart and\r\n searchInput render; any other name produces an empty element.\r\n failure: a correctly typed field with a different name renders nothing, silently.\r\n instead: name the field logo, cart or searchInput, or put it in another container -->\r\n <ng-container *ngFor=\"let header of headerItems\"\r\n [ngSwitch]=\"header.scope?.reference ? header.scope?.reference.split('/').pop() : 'default'\">\r\n\r\n <!-- Logo -->\r\n <ng-container *ngSwitchCase=\"'logo'\">\r\n <div *ngIf=\"isVisible(header)\" [ngStyle]=\"getStyle(header?.option?.style)\">\r\n\r\n <img [src]=\"header.option.src\" [alt]=\"header.alt || 'Logo'\"\r\n [ngStyle]=\"getStyle(header?.scope?.style)\" />\r\n </div>\r\n </ng-container>\r\n\r\n <!-- Search -->\r\n <ng-container *ngSwitchCase=\"'searchInput'\">\r\n <div *ngIf=\"isVisible(header)\" [ngStyle]=\"getStyle(header?.option?.style)\">\r\n\r\n <input #search type=\"text\" [placeholder]=\"header.option.placeholder ?? ''\"\r\n (keyup.enter)=\"invokeSearchedItems(header.option, search)\"\r\n [ngStyle]=\"getStyle(header?.scope?.style)\" />\r\n\r\n <button *ngIf=\"header.option.button !== false\" type=\"button\"\r\n (click)=\"invokeSearchedItems(header.option, search)\" [ngStyle]=\"getStyle(header?.buttonStyle)\">\r\n <ng-container *ngIf=\"!header.caption; else searchTextContent\">\r\n <i nz-icon [nzType]=\"header.icon\" nzTheme=\"outline\"></i>\r\n </ng-container>\r\n\r\n <ng-template #searchTextContent>\r\n {{ header.caption }}\r\n </ng-template>\r\n </button>\r\n </div>\r\n </ng-container>\r\n\r\n <!-- Cart -->\r\n <ng-container *ngSwitchCase=\"'cart'\">\r\n <div *ngIf=\"isVisible(header)\" [ngStyle]=\"getStyle(header?.option?.style)\"\r\n (click)=\"invokeShowtableContent(header.option)\">\r\n\r\n <span [ngStyle]=\"getStyle(header?.priceStyle)\">\r\n {{ cartInfo.totalPrice | currency : header.option?.currency ? header.option.currency : 'USD' }}\r\n </span>\r\n\r\n <span [ngStyle]=\"getStyle(header?.quantityStyle)\">\r\n {{ cartInfo.quantity }}\r\n </span>\r\n\r\n <i [class]=\"header.icon\" [ngStyle]=\"getStyle(header?.iconStyle)\">\r\n </i>\r\n </div>\r\n </ng-container>\r\n\r\n <!-- Default Button -->\r\n <ng-container *ngSwitchCase=\"'default'\">\r\n @if (header.option && header.option?.action && (header.option?.action == \"cart\")) {\r\n <div *ngIf=\"isVisible(header)\" [ngStyle]=\"getStyle(header?.option?.style)\"\r\n (click)=\"invokeShowtableContent(header.option)\">\r\n\r\n <span [ngStyle]=\"getStyle(header?.priceStyle)\">\r\n {{ cartInfo.totalPrice | currency : header.option?.currency ? header.option.currency : 'USD' }}\r\n </span>\r\n\r\n <span [ngStyle]=\"getStyle(header?.quantityStyle)\">\r\n {{ cartInfo.quantity }}\r\n </span>\r\n\r\n <i [class]=\"header.icon\" [ngStyle]=\"getStyle(header?.iconStyle)\">\r\n </i>\r\n </div>\r\n }@else {\r\n <div *ngIf=\"shouldShowDefaultButton(header)\" [ngStyle]=\"getStyle(header?.option?.style)\">\r\n\r\n <button type=\"button\" (click)=\"invokeHeaderButtonClick(header.option)\"\r\n [ngStyle]=\"getStyle(header?.buttonStyle)\">\r\n <ng-container *ngIf=\"!header.label; else buttonTextContent\">\r\n <i nz-icon [nzType]=\"header.icon\" nzTheme=\"outline\"></i>\r\n </ng-container>\r\n\r\n <ng-template #buttonTextContent>\r\n {{ header.label }}\r\n </ng-template>\r\n </button>\r\n </div>\r\n }\r\n </ng-container>\r\n\r\n </ng-container>\r\n</header>", styles: [""], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i5.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i5.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i5.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "directive", type: i5.NgSwitch, selector: "[ngSwitch]", inputs: ["ngSwitch"] }, { kind: "directive", type: i5.NgSwitchCase, selector: "[ngSwitchCase]", inputs: ["ngSwitchCase"] }, { kind: "ngmodule", type: NzIconModule }, { kind: "directive", type: i11.NzIconDirective, selector: "nz-icon,[nz-icon]", inputs: ["nzSpin", "nzRotate", "nzType", "nzTheme", "nzTwotoneColor", "nzIconfont"], exportAs: ["nzIcon"] }, { kind: "pipe", type: i5.CurrencyPipe, name: "currency" }] });
5704
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.2", type: HeaderMenuComponent, isStandalone: true, selector: "vl-header-menu", inputs: { headerItems: "headerItems", headerLayout: "headerLayout", environment: "environment", tenantName: "tenantName", projectSeleted: "projectSeleted", cartInfo: "cartInfo" }, outputs: { buttonClick: "buttonClick", showTableContent: "showTableContent", searchItems: "searchItems" }, usesOnChanges: true, ngImport: i0, template: "<!-- Faramarz Yousefian and Agent Toni (Claude Opus 5.5) 2026-10-13\r\n - fix: a field without a placeholder in the project stays empty; it showed the text \"undefined\" -->\r\n<!-- Faramarz Yousefian and Agent Toni (Claude Opus 5) 2026-09-19\r\n - new: a @contract comment stating that this container resolves by field NAME, not by field\r\n type. A correctly typed field with another name renders nothing, silently -->\r\n<header *ngIf=\"headerItems.length > 0\" [ngStyle]=\"getStyle(headerLayout?.style)\">\r\n\r\n <!-- @contract decision: resolves by field NAME, not by field type\r\n reality: the switch reads the LAST segment of scope.reference. Only logo, cart and\r\n searchInput render; any other name produces an empty element.\r\n failure: a correctly typed field with a different name renders nothing, silently.\r\n instead: name the field logo, cart or searchInput, or put it in another container -->\r\n <ng-container *ngFor=\"let header of headerItems\"\r\n [ngSwitch]=\"header.scope?.reference ? header.scope?.reference.split('/').pop() : 'default'\">\r\n\r\n <!-- Logo -->\r\n <ng-container *ngSwitchCase=\"'logo'\">\r\n <div *ngIf=\"isVisible(header)\" [ngStyle]=\"getStyle(header?.option?.style)\">\r\n\r\n <img [src]=\"header.option.src\" [alt]=\"header.alt || 'Logo'\"\r\n [ngStyle]=\"getStyle(header?.scope?.style)\" />\r\n </div>\r\n </ng-container>\r\n\r\n <!-- Search -->\r\n <ng-container *ngSwitchCase=\"'searchInput'\">\r\n <div *ngIf=\"isVisible(header)\" [ngStyle]=\"getStyle(header?.option?.style)\">\r\n\r\n <input #search type=\"text\" [placeholder]=\"header.option.placeholder ?? ''\"\r\n (keyup.enter)=\"invokeSearchedItems(header.option, search)\"\r\n [ngStyle]=\"getStyle(header?.scope?.style)\" />\r\n\r\n <button *ngIf=\"header.option.button !== false\" type=\"button\"\r\n (click)=\"invokeSearchedItems(header.option, search)\" [ngStyle]=\"getStyle(header?.buttonStyle)\">\r\n <ng-container *ngIf=\"!header.caption; else searchTextContent\">\r\n <i nz-icon [nzType]=\"header.icon\" nzTheme=\"outline\"></i>\r\n </ng-container>\r\n\r\n <ng-template #searchTextContent>\r\n {{ header.caption }}\r\n </ng-template>\r\n </button>\r\n </div>\r\n </ng-container>\r\n\r\n <!-- Cart -->\r\n <ng-container *ngSwitchCase=\"'cart'\">\r\n <div *ngIf=\"isVisible(header)\" [ngStyle]=\"getStyle(header?.option?.style)\"\r\n (click)=\"invokeShowtableContent(header.option)\">\r\n\r\n <span [ngStyle]=\"getStyle(header?.priceStyle)\">\r\n {{ cartInfo.totalPrice | currency : header.option?.currency ? header.option.currency : 'USD' }}\r\n </span>\r\n\r\n <span [ngStyle]=\"getStyle(header?.quantityStyle)\">\r\n {{ cartInfo.quantity }}\r\n </span>\r\n\r\n <i [class]=\"header.icon\" [ngStyle]=\"getStyle(header?.iconStyle)\">\r\n </i>\r\n </div>\r\n </ng-container>\r\n\r\n <!-- Default Button -->\r\n <ng-container *ngSwitchCase=\"'default'\">\r\n @if (header.option && header.option?.action && (header.option?.action == \"cart\")) {\r\n <div *ngIf=\"isVisible(header)\" [ngStyle]=\"getStyle(header?.option?.style)\"\r\n (click)=\"invokeShowtableContent(header.option)\">\r\n\r\n <span [ngStyle]=\"getStyle(header?.priceStyle)\">\r\n {{ cartInfo.totalPrice | currency : header.option?.currency ? header.option.currency : 'USD' }}\r\n </span>\r\n\r\n <span [ngStyle]=\"getStyle(header?.quantityStyle)\">\r\n {{ cartInfo.quantity }}\r\n </span>\r\n\r\n <i [class]=\"header.icon\" [ngStyle]=\"getStyle(header?.iconStyle)\">\r\n </i>\r\n </div>\r\n }@else {\r\n <div *ngIf=\"shouldShowDefaultButton(header)\" [ngStyle]=\"getStyle(header?.option?.style)\">\r\n\r\n <button type=\"button\" (click)=\"invokeHeaderButtonClick(header.option)\"\r\n [ngStyle]=\"getStyle(header?.buttonStyle)\">\r\n <ng-container *ngIf=\"!header.label; else buttonTextContent\">\r\n <i nz-icon [nzType]=\"header.icon\" nzTheme=\"outline\"></i>\r\n </ng-container>\r\n\r\n <ng-template #buttonTextContent>\r\n {{ header.label }}\r\n </ng-template>\r\n </button>\r\n </div>\r\n }\r\n </ng-container>\r\n\r\n </ng-container>\r\n</header>", styles: [""], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i9.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i9.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i9.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "directive", type: i9.NgSwitch, selector: "[ngSwitch]", inputs: ["ngSwitch"] }, { kind: "directive", type: i9.NgSwitchCase, selector: "[ngSwitchCase]", inputs: ["ngSwitchCase"] }, { kind: "ngmodule", type: NzIconModule }, { kind: "directive", type: i11.NzIconDirective, selector: "nz-icon,[nz-icon]", inputs: ["nzSpin", "nzRotate", "nzType", "nzTheme", "nzTwotoneColor", "nzIconfont"], exportAs: ["nzIcon"] }, { kind: "pipe", type: i9.CurrencyPipe, name: "currency" }] });
5473
5705
  }
5474
5706
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.2", ngImport: i0, type: HeaderMenuComponent, decorators: [{
5475
5707
  type: Component,
@@ -5539,7 +5771,7 @@ class LogsComponent {
5539
5771
  this.expandedRow = this.expandedRow === index ? null : index;
5540
5772
  }
5541
5773
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.2", ngImport: i0, type: LogsComponent, deps: [{ token: NetworkLogService }], target: i0.ɵɵFactoryTarget.Component });
5542
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.2", type: LogsComponent, isStandalone: true, selector: "vl-logs", ngImport: i0, template: "<div class=\"network-log-wrapper\">\r\n\r\n <div class=\"network-log-table\">\r\n <table>\r\n <thead>\r\n <tr>\r\n <th>#</th>\r\n <th>Time</th>\r\n <th>Method</th>\r\n <th>URL</th>\r\n <th>Status</th>\r\n <th>Duration (ms)</th>\r\n <th>Size (KB)</th>\r\n </tr>\r\n </thead>\r\n\r\n <tbody>\r\n <ng-container *ngFor=\"let log of logs; let i = index\">\r\n\r\n <!-- MAIN ROW -->\r\n <tr class=\"log-row\" (click)=\"toggleRow(i)\">\r\n <td>{{ i + 1 }}</td>\r\n <td>{{ log.time }}</td>\r\n\r\n <td>\r\n <span class=\"method\" [class.get]=\"log.method === 'GET'\" [class.post]=\"log.method === 'POST'\"\r\n [class.put]=\"log.method === 'PUT'\" [class.delete]=\"log.method === 'DELETE'\">\r\n {{ log.method }}\r\n </span>\r\n </td>\r\n\r\n <td class=\"ellipsis\" [title]=\"log.url\">\r\n {{ log.url }}\r\n </td>\r\n\r\n <td [class.error]=\"log.status >= 400\">\r\n {{ log.status }}\r\n </td>\r\n\r\n <td>{{ log.duration }}</td>\r\n\r\n <td>{{ log.size | number:'1.0-2' }}</td>\r\n </tr>\r\n\r\n <!-- DETAILS ROW -->\r\n <tr *ngIf=\"expandedRow === i\" class=\"details-row\">\r\n <td colspan=\"7\">\r\n <div class=\"details-container\">\r\n\r\n <!-- META -->\r\n <div class=\"detail-block\">\r\n <h4>Meta</h4>\r\n <p><strong>Date:</strong> {{ log.date }}</p>\r\n <p><strong>Type:</strong> {{ log.type }}</p>\r\n </div>\r\n\r\n <!-- REQUEST -->\r\n <div class=\"detail-block\">\r\n <h4>Request</h4>\r\n <p><strong>Headers</strong></p>\r\n <pre>{{ log.requestHeaders | json }}</pre>\r\n\r\n <p><strong>Body</strong></p>\r\n <pre>{{ log.requestBody | json }}</pre>\r\n </div>\r\n\r\n <!-- RESPONSE -->\r\n <div class=\"detail-block\">\r\n <h4>Response</h4>\r\n <pre>{{ log.responseBody | json }}</pre>\r\n </div>\r\n\r\n <!-- PERFORMANCE -->\r\n <div class=\"detail-block\">\r\n <h4>Performance</h4>\r\n <p><strong>Duration:</strong> {{ log.duration }} ms</p>\r\n <p><strong>Size:</strong> {{ log.size | number:'1.0-2' }} KB</p>\r\n </div>\r\n\r\n </div>\r\n </td>\r\n </tr>\r\n\r\n </ng-container>\r\n </tbody>\r\n </table>\r\n </div>\r\n\r\n</div>", styles: [".network-log-wrapper{padding:12px}.network-log-table{width:100%;overflow-x:auto}table{width:100%;border-collapse:collapse;font-size:13px;min-width:900px}thead th{background:#06b6d4;color:#fff;padding:8px;text-align:left;position:sticky;top:0;z-index:2}tbody td{padding:8px;border-bottom:1px solid #e5e7eb}.log-row{cursor:pointer}.log-row:hover{background:#f1f5f9}.details-row{background:#f8fafc}.method{padding:2px 8px;border-radius:4px;font-weight:600;font-size:11px;color:#fff}.method.get{background:#16a34a}.method.post{background:#2563eb}.method.put{background:#d97706}.method.delete{background:#dc2626}td.error{color:#dc2626;font-weight:700}.ellipsis{max-width:320px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.details-container{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:16px}.detail-block{background:#fff;border:1px solid #e5e7eb;border-radius:6px;padding:10px}.detail-block h4{margin:0 0 6px;font-size:14px;color:#0f172a}pre{background:#020617;color:#e5e7eb;padding:8px;border-radius:6px;max-height:260px;overflow:auto;font-size:12px;white-space:pre-wrap;word-break:break-word}@media(max-width:768px){table{min-width:100%;font-size:12px}.ellipsis{max-width:140px}.details-container{grid-template-columns:1fr}pre{max-height:200px}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i5.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i5.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "pipe", type: i5.JsonPipe, name: "json" }, { kind: "pipe", type: i5.DecimalPipe, name: "number" }] });
5774
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.2", type: LogsComponent, isStandalone: true, selector: "vl-logs", ngImport: i0, template: "<div class=\"network-log-wrapper\">\r\n\r\n <div class=\"network-log-table\">\r\n <table>\r\n <thead>\r\n <tr>\r\n <th>#</th>\r\n <th>Time</th>\r\n <th>Method</th>\r\n <th>URL</th>\r\n <th>Status</th>\r\n <th>Duration (ms)</th>\r\n <th>Size (KB)</th>\r\n </tr>\r\n </thead>\r\n\r\n <tbody>\r\n <ng-container *ngFor=\"let log of logs; let i = index\">\r\n\r\n <!-- MAIN ROW -->\r\n <tr class=\"log-row\" (click)=\"toggleRow(i)\">\r\n <td>{{ i + 1 }}</td>\r\n <td>{{ log.time }}</td>\r\n\r\n <td>\r\n <span class=\"method\" [class.get]=\"log.method === 'GET'\" [class.post]=\"log.method === 'POST'\"\r\n [class.put]=\"log.method === 'PUT'\" [class.delete]=\"log.method === 'DELETE'\">\r\n {{ log.method }}\r\n </span>\r\n </td>\r\n\r\n <td class=\"ellipsis\" [title]=\"log.url\">\r\n {{ log.url }}\r\n </td>\r\n\r\n <td [class.error]=\"log.status >= 400\">\r\n {{ log.status }}\r\n </td>\r\n\r\n <td>{{ log.duration }}</td>\r\n\r\n <td>{{ log.size | number:'1.0-2' }}</td>\r\n </tr>\r\n\r\n <!-- DETAILS ROW -->\r\n <tr *ngIf=\"expandedRow === i\" class=\"details-row\">\r\n <td colspan=\"7\">\r\n <div class=\"details-container\">\r\n\r\n <!-- META -->\r\n <div class=\"detail-block\">\r\n <h4>Meta</h4>\r\n <p><strong>Date:</strong> {{ log.date }}</p>\r\n <p><strong>Type:</strong> {{ log.type }}</p>\r\n </div>\r\n\r\n <!-- REQUEST -->\r\n <div class=\"detail-block\">\r\n <h4>Request</h4>\r\n <p><strong>Headers</strong></p>\r\n <pre>{{ log.requestHeaders | json }}</pre>\r\n\r\n <p><strong>Body</strong></p>\r\n <pre>{{ log.requestBody | json }}</pre>\r\n </div>\r\n\r\n <!-- RESPONSE -->\r\n <div class=\"detail-block\">\r\n <h4>Response</h4>\r\n <pre>{{ log.responseBody | json }}</pre>\r\n </div>\r\n\r\n <!-- PERFORMANCE -->\r\n <div class=\"detail-block\">\r\n <h4>Performance</h4>\r\n <p><strong>Duration:</strong> {{ log.duration }} ms</p>\r\n <p><strong>Size:</strong> {{ log.size | number:'1.0-2' }} KB</p>\r\n </div>\r\n\r\n </div>\r\n </td>\r\n </tr>\r\n\r\n </ng-container>\r\n </tbody>\r\n </table>\r\n </div>\r\n\r\n</div>", styles: [".network-log-wrapper{padding:12px}.network-log-table{width:100%;overflow-x:auto}table{width:100%;border-collapse:collapse;font-size:13px;min-width:900px}thead th{background:#06b6d4;color:#fff;padding:8px;text-align:left;position:sticky;top:0;z-index:2}tbody td{padding:8px;border-bottom:1px solid #e5e7eb}.log-row{cursor:pointer}.log-row:hover{background:#f1f5f9}.details-row{background:#f8fafc}.method{padding:2px 8px;border-radius:4px;font-weight:600;font-size:11px;color:#fff}.method.get{background:#16a34a}.method.post{background:#2563eb}.method.put{background:#d97706}.method.delete{background:#dc2626}td.error{color:#dc2626;font-weight:700}.ellipsis{max-width:320px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.details-container{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:16px}.detail-block{background:#fff;border:1px solid #e5e7eb;border-radius:6px;padding:10px}.detail-block h4{margin:0 0 6px;font-size:14px;color:#0f172a}pre{background:#020617;color:#e5e7eb;padding:8px;border-radius:6px;max-height:260px;overflow:auto;font-size:12px;white-space:pre-wrap;word-break:break-word}@media(max-width:768px){table{min-width:100%;font-size:12px}.ellipsis{max-width:140px}.details-container{grid-template-columns:1fr}pre{max-height:200px}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i9.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i9.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "pipe", type: i9.JsonPipe, name: "json" }, { kind: "pipe", type: i9.DecimalPipe, name: "number" }] });
5543
5775
  }
5544
5776
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.2", ngImport: i0, type: LogsComponent, decorators: [{
5545
5777
  type: Component,
@@ -6152,8 +6384,79 @@ class ModelComponent {
6152
6384
  action: 'cancel'
6153
6385
  });
6154
6386
  }
6387
+ getMediaProperty(field) {
6388
+ const reference = field?.scope?.reference;
6389
+ const key = reference?.split('/').pop();
6390
+ return key
6391
+ ? this.modalItemInfo?.propertySchema?.[this.getScope(reference)]?.[key]
6392
+ : undefined;
6393
+ }
6394
+ getMediaSource(field) {
6395
+ const property = this.getMediaProperty(field);
6396
+ const value = field?.option?.src || property?.value || property?.default || '';
6397
+ return typeof value === 'string' ? value.trim() : '';
6398
+ }
6399
+ getMediaLabel(field) {
6400
+ if (typeof field?.label === 'string' && field.label.trim()) {
6401
+ return field.label;
6402
+ }
6403
+ return field?.label?.value
6404
+ || field?.label?.caption
6405
+ || this.getMediaProperty(field)?.caption
6406
+ || 'Media';
6407
+ }
6408
+ getMediaKind(field) {
6409
+ const source = this.getMediaSource(field);
6410
+ const mime = /^data:([^;,]+)/i.exec(source)?.[1]?.toLowerCase();
6411
+ if (mime?.startsWith('image/'))
6412
+ return 'image';
6413
+ if (mime?.startsWith('video/'))
6414
+ return 'video';
6415
+ if (mime?.startsWith('audio/'))
6416
+ return 'audio';
6417
+ if (mime === 'application/pdf')
6418
+ return 'pdf';
6419
+ const property = this.getMediaProperty(field);
6420
+ const candidates = [
6421
+ source,
6422
+ field?.option?.fileName,
6423
+ property?.value,
6424
+ property?.default
6425
+ ];
6426
+ const videos = ['mp4', 'm4v', 'webm', 'mov', 'ogv', 'avi', 'mkv'];
6427
+ const audios = ['mp3', 'wav', 'ogg', 'oga', 'm4a', 'aac', 'flac', 'opus'];
6428
+ const files = [
6429
+ 'doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx',
6430
+ 'txt', 'csv', 'zip', 'rar', '7z'
6431
+ ];
6432
+ for (const candidate of candidates) {
6433
+ if (typeof candidate !== 'string')
6434
+ continue;
6435
+ if (/^(data|blob):/i.test(candidate))
6436
+ continue;
6437
+ let path = candidate.split(/[?#]/)[0];
6438
+ try {
6439
+ path = decodeURIComponent(path);
6440
+ }
6441
+ catch {
6442
+ // Keep the original path.
6443
+ }
6444
+ const extension = /\.([a-z0-9]+)$/i.exec(path)?.[1]?.toLowerCase();
6445
+ if (!extension)
6446
+ continue;
6447
+ if (videos.includes(extension))
6448
+ return 'video';
6449
+ if (audios.includes(extension))
6450
+ return 'audio';
6451
+ if (extension === 'pdf')
6452
+ return 'pdf';
6453
+ if (files.includes(extension))
6454
+ return 'file';
6455
+ }
6456
+ return 'image';
6457
+ }
6155
6458
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.2", ngImport: i0, type: ModelComponent, deps: [{ token: i0.ChangeDetectorRef }, { token: i1$3.DynamicDialogRef }, { token: i1$3.DynamicDialogConfig }, { token: UtilityService }], target: i0.ɵɵFactoryTarget.Component });
6156
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.2", type: ModelComponent, isStandalone: true, selector: "vl-model", inputs: { errorMessages: "errorMessages", modalItemInfo: "modalItemInfo", selectedLanguageInfo: "selectedLanguageInfo", userInfo: "userInfo", setFormDataHandler: "setFormDataHandler" }, usesOnChanges: true, ngImport: i0, template: "<!-- Faramarz Yousefian and Agent Toni (Claude Opus 5.5) 2026-10-13\r\n - fix: the placeholder comes from vlPlaceholder (pipes/placeholder.pipe.ts) - empty where the\r\n project defines none; it showed the text \"undefined\" -->\r\n<!-- Faramarz Yousefian and Agent Toni (Claude Opus 5) 2026-10-07\r\n - change: number, autocomplete, date and time fields take the toolkit keyboard of their\r\n attribute type (keyboardTypeFor) instead of only an explicit option.keyboardType\r\n - change: the date picker docks at the bottom on the devices (model-datepicker-panel--docked);\r\n the time picker stays attached to its field in a compact form (model-timepicker-panel);\r\n both report which picker closed (onPickerClose(picker)) -->\r\n\r\n<!-- Shuaib 2026-09-24\r\n - change: the model field switch uses renderFieldType so legacy checkbox fields render as boolean. -->\r\n\r\n<!-- Faramarz Yousefian and Agent Toni (Claude Opus 5) 2026-09-19\r\n - new: a @contract comment on the widest type coverage in the toolkit, and one on the credit\r\n card case recording that the rename reached this file first -->\r\n<!-- Loader Spinner -->\r\n<div *ngIf=\"isLoading\" class=\"loader-overlay\">\r\n <div class=\"spinner\"></div>\r\n</div>\r\n<div [style]=\"getStyleWithoutClasses(modalItemInfo?.layoutSchema?.style).style\"\r\n [class]=\"modalItemInfo?.layoutSchema?.style?.classes[0]\">\r\n <form #dynamicForm=\"ngForm\"\r\n *ngIf=\"modalItemInfo?.layoutSchema?.formSections?.length > 0\"\r\n (submit)=\"$event.preventDefault()\">\r\n <div\r\n *ngFor=\"let formSection of modalItemInfo?.layoutSchema?.formSections\">\r\n <div *ngIf=\"formSection?.label?.caption\"\r\n [class]=\"formSection?.label?.style?.classes[0]\"\r\n [style]=\"getStyleWithoutClasses(formSection?.label?.style).style\">\r\n {{formSection.label.caption}}\r\n </div>\r\n <div *ngIf=\"formSection?.formFields?.length > 0\"\r\n [class]=\"formSection?.style?.classes?.[0] || ''\"\r\n [ngStyle]=\"getSectionBodyStyle(formSection)\">\r\n <div *ngFor=\"let formField of formSection.formFields\"\r\n [ngStyle]=\"getFieldWrapperStyle(formField)\"\r\n [class]=\"formField?.style?.classes || ''\">\r\n\r\n <!-- @contract decision: the widest type coverage in the toolkit\r\n reality: every field type except the grid-only quantity renders here.\r\n When another container drops a type, this is the way out.\r\n seen: measured 2026-09-19. Note the file is model.component.html while\r\n the container is called modal in layout files - that costs a\r\n search every time -->\r\n <!-- @contract compatibility: checkbox is rendered as boolean for existing projects. -->\r\n <div [ngSwitch]=\"renderFieldType(\r\n formField?.scope?.reference &&\r\n modalItemInfo?.propertySchema?.[\r\n getScope(formField.scope.reference)\r\n ]\r\n ? modalItemInfo.propertySchema[\r\n getScope(formField.scope.reference)\r\n ]?.[\r\n formField.scope.reference.split('/').pop()\r\n ]?.type\r\n : 'default'\r\n )\">\r\n <!-- image control -->\r\n <div *ngSwitchCase=\"'image'\"\r\n [style]=\"getStyleWithoutClasses(formField?.style).style\"\r\n [class]=\"formField.style?.classes ? formField.style?.classes[0]: ''\">\r\n <img [src]=\"formField.option.src\" [alt]=\"'img'\" />\r\n </div>\r\n\r\n <!-- credit card control -->\r\n <!-- @contract decision: the credit card type is spelled creditCard\r\n reality: this file was renamed on 2026-09-15, form.component.html and\r\n utility.service.ts followed on 2026-09-19. carditCard is read\r\n nowhere any more.\r\n failure: a data object still declaring carditCard renders empty. -->\r\n <div *ngSwitchCase=\"'creditCard'\"\r\n [style]=\"getStyleWithoutClasses(formField?.style).style\"\r\n [class]=\"formField.style?.classes[0]\">\r\n <div id=\"card-element\">\r\n <!-- a Stripe element will be inserted here -->\r\n </div>\r\n <!-- Used to display form errors -->\r\n <div id=\"card-errors\"\r\n class=\"displayError.textContent!=='': 'alert alert-danger mt-1'\">\r\n </div>\r\n </div>\r\n\r\n <!-- string control -->\r\n <div *ngSwitchCase=\"'string'\" class=\"form-group mb-3\">\r\n @if(formField.option && formField.option.control &&\r\n !formField.option.protected){\r\n @switch (formField.option.control) {\r\n @case ('textInput') {\r\n <div\r\n [ngStyle]=\"getFieldInnerLayoutStyle(formField)\">\r\n <vl-label [formField]=\"formField\"\r\n [modalItemInfo]=\"modalItemInfo\">\r\n </vl-label>\r\n <vl-textbox [formField]=\"formField\"\r\n [modalItemInfo]=\"modalItemInfo\">\r\n </vl-textbox>\r\n </div>\r\n <!-- Error Message -->\r\n <!-- <div *ngIf=\"inputField?.touched && inputField?.invalid\"\r\n [style]=\"getStyleWithoutClasses(formField?.validation?.style).style\">\r\n <p class=\"text-danger\" *ngIf=\"inputField?.errors?.['required']\">\r\n {{setErroMessage(formField, errorMessages, \"required\")}}</p>\r\n <p class=\"text-danger\" *ngIf=\"inputField?.errors?.['email']\">\r\n {{(formField.label?.value ?\r\n formField.label?.value :\r\n modalItemInfo.propertySchema[getScope(formField.scope?.reference)][formField.scope?.reference.split('/').pop()]?.caption)\r\n +\r\n ' ' + errorMessages.pattern}}</p>\r\n </div> -->\r\n }\r\n\r\n @case ('password') {\r\n <span>Switch not supported yet</span>\r\n\r\n }\r\n @case ('combobox') {\r\n <span>Combobox not supported yet</span>\r\n }\r\n @case('textArea'){\r\n <span>TextArea not supported yet</span>\r\n }\r\n @case ('switch') {\r\n <span>Switch not supported yet</span>\r\n }\r\n\r\n @case('radiobutton') {\r\n <span>Radiobutton not supported yet</span>\r\n }\r\n\r\n @case ('dropdown') {\r\n <span *ngIf=\"formField.option?.postfixCaption\">\r\n <select id=\"dynamic-dropdown\"\r\n [class]=\"formField.style?.classes ? formField.style?.classes[0]: ''\"\r\n #dropdownField=\"ngModel\"\r\n [style]=\"getStyleWithoutClasses(formField?.style).style\"\r\n [name]=\"formField.scope?.reference\"\r\n [(ngModel)]=\"modalItemInfo.propertySchema[getScope(formField.scope?.reference)][formField.scope?.reference.split('/').pop()].value\">\r\n <option\r\n *ngFor=\"let item of modalItemInfo.propertySchema[getScope(formField.scope?.reference)][formField.scope?.reference.split('/').pop()]?.data\"\r\n [value]=\"formField?.option?.optionValue ? formField.option.optionValue : 'value'\">\r\n {{ formField?.option?.optionLabel ?\r\n formField.option.optionLabel :\r\n 'label'}}</option>\r\n </select>\r\n <label\r\n [style]=\"getStyleWithoutClasses(formField?.label?.style).style\">{{modalItemInfo.propertySchema[getScope(formField.scope)][formField.scope?.reference.split('/').pop()]?.caption\r\n }}</label>\r\n </span>\r\n <div *ngIf=\"!formField.option?.postfixCaption\">\r\n <div\r\n [ngStyle]=\"getFieldInnerLayoutStyle(formField)\">\r\n <label\r\n [style]=\"getStyleWithoutClasses(formField?.label?.style).style\">{{modalItemInfo.propertySchema[getScope(formField.scope?.reference)][formField.scope?.reference.split('/').pop()]?.caption\r\n }}</label>\r\n\r\n <nz-select nzShowSearch nzAllowClear\r\n nzPlaceHolder=\"Select\"\r\n #dropdownField=\"ngModel\"\r\n [required]=\"formField.option.required\"\r\n [class]=\"formField.style?.classes ? formField.style?.classes[0]: ''\"\r\n [style]=\"getStyleWithoutClasses(formField?.style).style\"\r\n [name]=\"formField.scope?.reference\"\r\n [(ngModel)]=\"modalItemInfo.propertySchema[getScope(formField.scope?.reference)][formField.scope?.reference.split('/').pop()].value\">\r\n <nz-option\r\n *ngFor=\"let item of modalItemInfo.propertySchema[getScope(formField.scope?.reference)][formField.scope?.reference.split('/').pop()]?.data\"\r\n [nzLabel]=\"item[formField?.option?.optionLabel ? formField.option.optionLabel : 'label']\"\r\n [nzValue]=\"item[formField?.option?.optionValue ? formField.option.optionValue : 'value']\"></nz-option>\r\n </nz-select>\r\n </div>\r\n <!-- Error Message -->\r\n <div\r\n *ngIf=\"dropdownField?.touched && dropdownField?.invalid\"\r\n [style]=\"getStyleWithoutClasses(formField?.validation?.style).style\">\r\n <p class=\"text-danger\"\r\n *ngIf=\"dropdownField?.errors?.['required']\">\r\n {{formField.label?.value ?\r\n formField.label?.value :\r\n modalItemInfo.propertySchema[getScope(formField.scope?.reference)][formField.scope?.reference.split('/').pop()]?.caption\r\n +\r\n ' ' + errorMessages.required}}</p>\r\n <p class=\"text-danger\"\r\n *ngIf=\"dropdownField?.errors?.['email']\">\r\n {{(formField.label?.value ?\r\n formField.label?.value :\r\n modalItemInfo.propertySchema[getScope(formField.scope?.reference)][formField.scope?.reference.split('/').pop()]?.caption)\r\n +\r\n ' ' + errorMessages.pattern}}</p>\r\n </div>\r\n </div>\r\n }\r\n\r\n @case ('autocomplete') {\r\n <div\r\n [ngStyle]=\"getFieldInnerLayoutStyle(formField)\">\r\n <vl-label [formField]=\"formField\"\r\n [modalItemInfo]=\"modalItemInfo\">\r\n </vl-label>\r\n\r\n <span>\r\n <p-autocomplete\r\n #autocompleteField=\"ngModel\"\r\n [required]=\"formField.option.required\"\r\n [name]=\"formField.scope?.reference\"\r\n styleClass=\"custom-autocomplete\"\r\n [(ngModel)]=\"modalItemInfo.propertySchema[getScope(formField.scope?.reference)][formField.scope?.reference.split('/').pop()].value\"\r\n [style]=\"getStyleWithoutClasses(formField?.scope?.style).style\"\r\n [class]=\"formField?.scope?.style?.classes ? formField?.scope?.style?.classes[0] : ''\"\r\n [suggestions]=\"matchData\"\r\n [dropdown]=\"true\"\r\n [optionLabel]=\"formField?.option?.autocomplete?.response?.label ? formField.option.autocomplete.response.label : 'label'\"\r\n [placeholder]=\"modalItemInfo.propertySchema | vlPlaceholder: formField.scope?.reference\"\r\n (completeMethod)=\"autocompChangeEvent($event, formField)\"\r\n (ngModelChange)=\"autocompFocusOutEvent($event, formField)\"\r\n [vlCustomKeyboard]=\"keyboardTypeFor(formField)\">\r\n </p-autocomplete>\r\n <!-- Error Message -->\r\n <div\r\n *ngIf=\"autocompleteField?.touched && autocompleteField?.invalid\"\r\n [style]=\"getStyleWithoutClasses(formField?.validation?.style).style\">\r\n <p class=\"text-danger\"\r\n *ngIf=\"autocompleteField?.errors?.['required']\">\r\n {{setErroMessage(formField,\r\n errorMessages, \"required\")}}</p>\r\n <p class=\"text-danger\"\r\n *ngIf=\"autocompleteField?.errors?.['email']\">\r\n {{(formField.label?.value ?\r\n formField.label?.value :\r\n modalItemInfo.propertySchema[getScope(formField.scope?.reference)][formField.scope?.reference.split('/').pop()]?.caption)\r\n +\r\n ' ' +\r\n errorMessages.pattern}}</p>\r\n </div>\r\n </span>\r\n </div>\r\n }\r\n }\r\n }@else{\r\n <div *ngIf=\"!formField.option.protected\">\r\n <div\r\n [ngStyle]=\"getFieldInnerLayoutStyle(formField)\">\r\n <vl-label [formField]=\"formField\"\r\n [modalItemInfo]=\"modalItemInfo\">\r\n </vl-label>\r\n <vl-textbox [formField]=\"formField\"\r\n [modalItemInfo]=\"modalItemInfo\">\r\n </vl-textbox>\r\n </div>\r\n <!-- Error Message -->\r\n <!-- <div *ngIf=\"inputField?.touched && inputField?.invalid\"\r\n [style]=\"getStyleWithoutClasses(formField?.validation?.style).style\">\r\n <p class=\"text-danger\" *ngIf=\"inputField?.errors?.['required']\">\r\n {{setErroMessage(formField, errorMessages, \"required\")}}</p>\r\n <p class=\"text-danger\" *ngIf=\"inputField?.errors?.['email']\">\r\n {{(formField.label?.value ?\r\n formField.label?.value :\r\n modalItemInfo.propertySchema[getScope(formField.scope?.reference)][formField.scope?.reference.split('/').pop()]?.caption)\r\n +\r\n ' ' + errorMessages.pattern}}</p>\r\n </div> -->\r\n </div>\r\n }\r\n <span *ngIf=\"formField.option.protected\"\r\n [style]=\"getStyleWithoutClasses(formField?.label?.style).style\"\r\n [class]=\"formField?.label?.style.classes ? formField?.label?.style?.classes[0] : ''\">\r\n <vl-string [formField]=\"formField\"\r\n [modalItemInfo]=\"modalItemInfo\">\r\n </vl-string>\r\n </span>\r\n\r\n </div>\r\n\r\n <!-- number control -->\r\n <div *ngSwitchCase=\"'number'\" class=\"form-group mb-3\">\r\n <span *ngIf=\"formField.option.protected\"\r\n [style]=\"getStyleWithoutClasses(formField?.label?.style).style\"\r\n [class]=\"formField?.label?.style.classes ? formField?.label?.style?.classes[0] : ''\">\r\n <h5>{{\r\n modalItemInfo.propertySchema[getScope(formField.scope?.reference)][formField.scope?.reference.split('/').pop()]?.caption\r\n }} {{\r\n modalItemInfo.propertySchema[getScope(formField.scope?.reference)][formField.scope?.reference.split('/').pop()]?.value\r\n |\r\n currency:formField.option.currency :true:\r\n formField.option?.decimalPoint}}\r\n </h5>\r\n </span>\r\n <span *ngIf=\"!formField.option.protected\">\r\n <div\r\n [ngStyle]=\"getFieldInnerLayoutStyle(formField)\">\r\n <label\r\n [style]=\"getStyleWithoutClasses(formField?.label?.style).style\"\r\n [class]=\"formField?.label?.style.classes ? formField?.label?.style?.classes[0] : ''\">{{\r\n formField.label?.value\r\n ?\r\n formField.label?.value :\r\n modalItemInfo.propertySchema[getScope(formField.scope?.reference)][formField.scope?.reference.split('/').pop()]?.caption\r\n }}</label>\r\n <input type=\"number\"\r\n [class]=\"formField.style?.classes ? formField.style?.classes[0]: ''\"\r\n [vlCustomKeyboard]=\"keyboardTypeFor(formField)\"\r\n [style]=\"getStyleWithoutClasses(formField?.style).style\"\r\n [(ngModel)]=\"modalItemInfo.propertySchema[getScope(formField.scope?.reference)][formField.scope?.reference.split('/').pop()].value\"\r\n [name]=\"formField.scope?.reference\"\r\n [placeholder]=\"modalItemInfo.propertySchema | vlPlaceholder: formField.scope?.reference\" />\r\n </div>\r\n </span>\r\n </div>\r\n\r\n <!-- DateRange control -->\r\n <div *ngSwitchCase=\"'dateRange'\"\r\n class=\"form-group mb-3\">\r\n <span *ngIf=\"formField.option.protected\"\r\n [style]=\"getStyleWithoutClasses(formField?.label?.style).style\"\r\n [class]=\"formField?.label?.style.classes ? formField?.label?.style?.classes[0] : ''\">\r\n <vl-string [formField]=\"formField\"\r\n [modalItemInfo]=\"modalItemInfo\">\r\n </vl-string>\r\n </span>\r\n <div *ngIf=\"!formField.option.protected\">\r\n <div\r\n [ngStyle]=\"getFieldInnerLayoutStyle(formField)\">\r\n <label\r\n [style]=\"getStyleWithoutClasses(formField?.label?.style).style\"\r\n [class]=\"formField?.label?.style.classes ? formField?.label?.style?.classes[0] : ''\">{{\r\n formField.label?.value\r\n ?\r\n formField.label?.value :\r\n modalItemInfo.propertySchema[getScope(formField.scope?.reference)][formField.scope?.reference.split('/').pop()]?.caption\r\n }}</label>\r\n <nz-range-picker #dateRangeField=\"ngModel\"\r\n [required]=\"formField.option.required\"\r\n [name]=\"formField.scope?.reference\"\r\n [style]=\"getStyleWithoutClasses(formField?.style).style\"\r\n [(ngModel)]=\"modalItemInfo.propertySchema[getScope(formField.scope?.reference)][formField.scope?.reference.split('/').pop()].value\"></nz-range-picker>\r\n </div>\r\n <!-- Error Message -->\r\n <div\r\n *ngIf=\"dateRangeField?.touched && dateRangeField?.invalid\"\r\n [style]=\"getStyleWithoutClasses(formField?.validation?.style).style\">\r\n <p class=\"text-danger\"\r\n *ngIf=\"dateRangeField?.errors?.['required']\">\r\n {{formField.label?.value ?\r\n formField.label?.value :\r\n modalItemInfo.propertySchema[getScope(formField.scope?.reference)][formField.scope?.reference.split('/').pop()]?.caption\r\n +\r\n ' ' + errorMessages.required}}</p>\r\n <p class=\"text-danger\"\r\n *ngIf=\"dateRangeField?.errors?.['email']\">\r\n {{(formField.label?.value ?\r\n formField.label?.value :\r\n modalItemInfo.propertySchema[getScope(formField.scope?.reference)][formField.scope?.reference.split('/').pop()]?.caption)\r\n +\r\n ' ' + errorMessages.pattern}}</p>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- Date control -->\r\n <div *ngSwitchCase=\"'date'\" class=\"form-group mb-3\">\r\n <span\r\n *ngIf=\"formField.option.protected\"\r\n [style]=\"getStyleWithoutClasses(formField?.label?.style).style\"\r\n [class]=\"formField?.label?.style.classes ? formField?.label?.style?.classes[0] : ''\">\r\n <vl-string\r\n [formField]=\"formField\"\r\n [modalItemInfo]=\"modalItemInfo\">\r\n </vl-string>\r\n </span>\r\n\r\n <div *ngIf=\"!formField.option.protected\">\r\n <div\r\n [ngStyle]=\"getFieldInnerLayoutStyle(formField)\">\r\n <label\r\n [style]=\"getStyleWithoutClasses(formField?.label?.style).style\"\r\n [class]=\"formField?.label?.style.classes ? formField?.label?.style?.classes[0] : ''\">\r\n {{ getLabel(formField) }}\r\n </label>\r\n\r\n <span>\r\n <div class=\"picker-field\">\r\n <p-datepicker\r\n #datePicker\r\n #dateField=\"ngModel\"\r\n styleClass=\"custom-datepicker\"\r\n [required]=\"formField.option.required\"\r\n [name]=\"formField.scope?.reference\"\r\n [disabled]=\"formField?.option?.disabled\"\r\n [showIcon]=\"false\"\r\n [showOnFocus]=\"false\"\r\n appendTo=\"body\"\r\n [autoZIndex]=\"true\"\r\n [baseZIndex]=\"10000\"\r\n [panelStyleClass]=\"picker.datePanelClass\"\r\n [motionOptions]=\"picker.dockedMotion\"\r\n [vlCustomKeyboard]=\"keyboardTypeFor(formField)\"\r\n (pointerdown)=\"picker.onFieldPointerDown($event, datePicker)\"\r\n (onFocus)=\"picker.onFieldFocus($event)\"\r\n (onShow)=\"picker.onShown()\"\r\n (onClose)=\"picker.onClose(datePicker)\"\r\n (ngModelChange)=\"dateChangeEvent(formField, $event)\"\r\n (onInput)=\"onDateTyping($event)\"\r\n [dateFormat]=\"\r\n modalItemInfo.propertySchema[\r\n getScope(formField.scope?.reference)\r\n ][\r\n formField.scope?.reference.split('/').pop()\r\n ]?.format || 'yy-mm-dd'\r\n \"\r\n [(ngModel)]=\"\r\n modalItemInfo.propertySchema[\r\n getScope(formField.scope?.reference)\r\n ][\r\n formField.scope?.reference.split('/').pop()\r\n ].value\r\n \"\r\n [class]=\"formField?.scope?.style?.classes?.[0] || ''\"\r\n [style]=\"getStyleWithoutClasses(formField?.scope?.style).style\">\r\n </p-datepicker>\r\n\r\n <button\r\n type=\"button\"\r\n class=\"picker-field__icon\"\r\n aria-label=\"Open calendar\"\r\n [disabled]=\"formField?.option?.disabled\"\r\n (pointerdown)=\"picker.openFromIcon($event, datePicker)\"\r\n (click)=\"picker.blockIconClick($event)\">\r\n <i class=\"pi pi-calendar\"></i>\r\n </button>\r\n </div>\r\n\r\n <div\r\n *ngIf=\"dateField?.touched && dateField?.invalid\"\r\n [style]=\"getStyleWithoutClasses(formField?.validation?.style).style\">\r\n <p class=\"text-danger\"\r\n *ngIf=\"dateField?.errors?.['required']\">\r\n {{ setErroMessage(formField,\r\n errorMessages, 'required') }}\r\n </p>\r\n <p class=\"text-danger\"\r\n *ngIf=\"dateField?.errors?.['email']\">\r\n {{\r\n (formField.label?.value\r\n ? formField.label?.value\r\n : modalItemInfo.propertySchema[\r\n getScope(formField.scope?.reference)\r\n ][\r\n formField.scope?.reference.split('/').pop()\r\n ]?.caption)\r\n + ' ' + errorMessages.pattern\r\n }}\r\n </p>\r\n </div>\r\n </span>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- Time control -->\r\n <div *ngSwitchCase=\"'time'\" class=\"form-group mb-3\">\r\n <span\r\n *ngIf=\"formField.option.protected\"\r\n [style]=\"getStyleWithoutClasses(formField?.label?.style).style\"\r\n [class]=\"formField?.label?.style.classes ? formField?.label?.style?.classes[0] : ''\">\r\n <vl-string\r\n [formField]=\"formField\"\r\n [modalItemInfo]=\"modalItemInfo\">\r\n </vl-string>\r\n </span>\r\n\r\n <div *ngIf=\"!formField.option.protected\">\r\n <div\r\n [ngStyle]=\"getFieldInnerLayoutStyle(formField)\">\r\n <label\r\n [style]=\"getStyleWithoutClasses(formField?.label?.style).style\"\r\n [class]=\"formField?.label?.style.classes ? formField?.label?.style?.classes[0] : ''\">\r\n {{ getLabel(formField) }}\r\n </label>\r\n\r\n <span>\r\n <div class=\"picker-field\">\r\n <p-datepicker\r\n #timePicker\r\n #timeField=\"ngModel\"\r\n styleClass=\"custom-datepicker\"\r\n [required]=\"formField.option.required\"\r\n [name]=\"formField.scope?.reference\"\r\n [timeOnly]=\"true\"\r\n hourFormat=\"24\"\r\n [disabled]=\"formField?.option?.disabled\"\r\n [showIcon]=\"false\"\r\n [showOnFocus]=\"false\"\r\n appendTo=\"body\"\r\n [autoZIndex]=\"true\"\r\n [baseZIndex]=\"10000\"\r\n [panelStyleClass]=\"picker.timePanelClass\"\r\n [vlCustomKeyboard]=\"keyboardTypeFor(formField)\"\r\n (pointerdown)=\"picker.onFieldPointerDown($event, timePicker)\"\r\n (onFocus)=\"picker.onFieldFocus($event)\"\r\n (onShow)=\"onTimePanelShow(formField)\"\r\n (onClose)=\"picker.onClose(timePicker)\"\r\n (onInput)=\"onTimeTyping($event)\"\r\n (ngModelChange)=\"timeChangeEvent(formField, $event)\"\r\n [style]=\"getStyleWithoutClasses(formField?.scope?.style).style\"\r\n [(ngModel)]=\"\r\n modalItemInfo.propertySchema[\r\n getScope(formField.scope?.reference)\r\n ][\r\n formField.scope?.reference.split('/').pop()\r\n ].value\r\n \"\r\n [class]=\"formField?.scope?.style?.classes?.[0] || ''\">\r\n </p-datepicker>\r\n\r\n <button\r\n type=\"button\"\r\n class=\"picker-field__icon\"\r\n aria-label=\"Open time picker\"\r\n [disabled]=\"formField?.option?.disabled\"\r\n (pointerdown)=\"picker.openFromIcon($event, timePicker)\"\r\n (click)=\"picker.blockIconClick($event)\">\r\n <i class=\"pi pi-clock\"></i>\r\n </button>\r\n </div>\r\n\r\n <div\r\n *ngIf=\"timeField?.touched && timeField?.invalid\"\r\n [style]=\"getStyleWithoutClasses(formField?.validation?.style).style\">\r\n <p class=\"text-danger\"\r\n *ngIf=\"timeField?.errors?.['required']\">\r\n {{ setErroMessage(formField,\r\n errorMessages, 'required') }}\r\n </p>\r\n <p class=\"text-danger\"\r\n *ngIf=\"timeField?.errors?.['email']\">\r\n {{\r\n (formField.label?.value\r\n ? formField.label?.value\r\n : modalItemInfo.propertySchema[\r\n getScope(formField.scope?.reference)\r\n ][\r\n formField.scope?.reference.split('/').pop()\r\n ]?.caption)\r\n + ' ' + errorMessages.pattern\r\n }}\r\n </p>\r\n </div>\r\n </span>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- Autocomplete control -->\r\n <div *ngSwitchCase=\"'autocomplete'\"\r\n class=\"form-group mb-3\">\r\n <span *ngIf=\"formField.option.protected\"\r\n [style]=\"getStyleWithoutClasses(formField?.label?.style).style\"\r\n [class]=\"formField?.label?.style.classes ? formField?.label?.style?.classes[0] : ''\">\r\n <vl-string [formField]=\"formField\"\r\n [modalItemInfo]=\"modalItemInfo\">\r\n </vl-string>\r\n </span>\r\n <div *ngIf=\"!formField.option.protected\">\r\n <div\r\n [ngStyle]=\"getFieldInnerLayoutStyle(formField)\">\r\n <vl-label [formField]=\"formField\"\r\n [modalItemInfo]=\"modalItemInfo\">\r\n </vl-label>\r\n\r\n <span>\r\n <p-autocomplete\r\n #autocompleteField=\"ngModel\"\r\n [required]=\"formField.option.required\"\r\n [name]=\"formField.scope?.reference\"\r\n styleClass=\"custom-autocomplete\"\r\n [(ngModel)]=\"modalItemInfo.propertySchema[getScope(formField.scope?.reference)][formField.scope?.reference.split('/').pop()].value\"\r\n [style]=\"getStyleWithoutClasses(formField?.scope?.style).style\"\r\n [class]=\"formField?.scope?.style?.classes ? formField?.scope?.style?.classes[0] : ''\"\r\n [suggestions]=\"matchData\"\r\n [dropdown]=\"true\"\r\n [optionLabel]=\"formField?.option?.autocomplete?.response?.label ? formField.option.autocomplete.response.label : 'label'\"\r\n [placeholder]=\"modalItemInfo.propertySchema | vlPlaceholder: formField.scope?.reference\"\r\n (completeMethod)=\"autocompChangeEvent($event, formField)\"\r\n (ngModelChange)=\"autocompFocusOutEvent($event, formField)\"\r\n [vlCustomKeyboard]=\"keyboardTypeFor(formField)\">\r\n </p-autocomplete>\r\n <!-- Error Message -->\r\n <div\r\n *ngIf=\"autocompleteField?.touched && autocompleteField?.invalid\"\r\n [style]=\"getStyleWithoutClasses(formField?.validation?.style).style\">\r\n <p class=\"text-danger\"\r\n *ngIf=\"autocompleteField?.errors?.['required']\">\r\n {{setErroMessage(formField,\r\n errorMessages, \"required\")}}</p>\r\n <p class=\"text-danger\"\r\n *ngIf=\"autocompleteField?.errors?.['email']\">\r\n {{(formField.label?.value ?\r\n formField.label?.value :\r\n modalItemInfo.propertySchema[getScope(formField.scope?.reference)][formField.scope?.reference.split('/').pop()]?.caption)\r\n +\r\n ' ' +\r\n errorMessages.pattern}}</p>\r\n </div>\r\n </span>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- checkBox control -->\r\n <div *ngSwitchCase=\"'boolean'\" class=\"form-group mb-3\"\r\n [style]=\"getStyleWithoutClasses(formField?.style).style\"\r\n [class]=\"formField.style?.classes ? formField.style?.classes[0] : ''\">\r\n <span *ngIf=\"formField.option?.postfixCaption\">\r\n <label class=\"form-check-label\"><input\r\n type=\"checkbox\" class=\"form-check-input\"\r\n [(ngModel)]=\"modalItemInfo.propertySchema[getScope(formField.scope?.reference)][formField.scope?.reference.split('/').pop()].value\"\r\n [name]=\"formField.scope?.reference\"\r\n (ngModelChange)=\"invokeSetformData()\" />{{\r\n modalItemInfo.propertySchema[getScope(formField.scope?.reference)][formField.scope?.reference.split('/').pop()]?.caption\r\n }}</label>\r\n </span>\r\n <div *ngIf=\"!formField.option?.postfixCaption\"\r\n [class]=\"formField?.layout == 'horizontal' ? 'horizontal-layout' : 'row'\">\r\n <label class=\"form-check-label\">{{\r\n modalItemInfo.propertySchema[getScope(formField.scope?.reference)][formField.scope?.reference.split('/').pop()]?.caption\r\n }}\r\n <input type=\"checkbox\"\r\n class=\"form-check-input\"\r\n [(ngModel)]=\"modalItemInfo.propertySchema[getScope(formField.scope?.reference)][formField.scope?.reference.split('/').pop()].value\"\r\n [name]=\"formField.scope?.reference\" /></label>\r\n </div>\r\n </div>\r\n\r\n <!-- dropdown control -->\r\n <div *ngSwitchCase=\"'dropdown'\" class=\"form-group mb-3\"\r\n [style]=\"getStyleWithoutClasses(formField?.style).style\"\r\n [class]=\"formField.style?.classes ? formField.style?.classes[0] : ''\">\r\n <span *ngIf=\"formField.option?.postfixCaption\">\r\n <select id=\"dynamic-dropdown\"\r\n [class]=\"formField.style?.classes ? formField.style?.classes[0]: ''\"\r\n #dropdownField=\"ngModel\"\r\n [style]=\"getStyleWithoutClasses(formField?.style).style\"\r\n [name]=\"formField.scope?.reference\"\r\n [(ngModel)]=\"modalItemInfo.propertySchema[getScope(formField.scope?.reference)][formField.scope?.reference.split('/').pop()].value\">\r\n <option\r\n *ngFor=\"let item of modalItemInfo.propertySchema[getScope(formField.scope?.reference)][formField.scope?.reference.split('/').pop()]?.data\"\r\n [value]=\"formField?.option?.optionValue ? formField.option.optionValue : 'value'\">\r\n {{ formField?.option?.optionLabel ?\r\n formField.option.optionLabel :\r\n 'label'}}</option>\r\n </select>\r\n <label\r\n [style]=\"getStyleWithoutClasses(formField?.label?.style).style\">{{modalItemInfo.propertySchema[getScope(formField.scope)][formField.scope?.reference.split('/').pop()]?.caption\r\n }}</label>\r\n </span>\r\n <div *ngIf=\"!formField.option?.postfixCaption\">\r\n <div\r\n [ngStyle]=\"getFieldInnerLayoutStyle(formField)\">\r\n <label\r\n [style]=\"getStyleWithoutClasses(formField?.label?.style).style\">{{modalItemInfo.propertySchema[getScope(formField.scope?.reference)][formField.scope?.reference.split('/').pop()]?.caption\r\n }}</label>\r\n\r\n <nz-select nzShowSearch nzAllowClear\r\n nzPlaceHolder=\"Select\"\r\n #dropdownField=\"ngModel\"\r\n [required]=\"formField.option.required\"\r\n [class]=\"formField.style?.classes ? formField.style?.classes[0]: ''\"\r\n [style]=\"getStyleWithoutClasses(formField?.style).style\"\r\n [name]=\"formField.scope?.reference\"\r\n [(ngModel)]=\"modalItemInfo.propertySchema[getScope(formField.scope?.reference)][formField.scope?.reference.split('/').pop()].value\">\r\n <nz-option\r\n *ngFor=\"let item of modalItemInfo.propertySchema[getScope(formField.scope?.reference)][formField.scope?.reference.split('/').pop()]?.data\"\r\n [nzLabel]=\"item[formField?.option?.optionLabel ? formField.option.optionLabel : 'label']\"\r\n [nzValue]=\"item[formField?.option?.optionValue ? formField.option.optionValue : 'value']\"></nz-option>\r\n </nz-select>\r\n </div>\r\n <!-- Error Message -->\r\n <div\r\n *ngIf=\"dropdownField?.touched && dropdownField?.invalid\"\r\n [style]=\"getStyleWithoutClasses(formField?.validation?.style).style\">\r\n <p class=\"text-danger\"\r\n *ngIf=\"dropdownField?.errors?.['required']\">\r\n {{formField.label?.value ?\r\n formField.label?.value :\r\n modalItemInfo.propertySchema[getScope(formField.scope?.reference)][formField.scope?.reference.split('/').pop()]?.caption\r\n +\r\n ' ' + errorMessages.required}}</p>\r\n <p class=\"text-danger\"\r\n *ngIf=\"dropdownField?.errors?.['email']\">\r\n {{(formField.label?.value ?\r\n formField.label?.value :\r\n modalItemInfo.propertySchema[getScope(formField.scope?.reference)][formField.scope?.reference.split('/').pop()]?.caption)\r\n +\r\n ' ' + errorMessages.pattern}}</p>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- button control -->\r\n <div *ngSwitchCase=\"'default'\">\r\n <button type=\"button\"\r\n [ngStyle]=\"getStyleWithoutClasses(formField.style).style\"\r\n (click)=\"invokeFormBtnClick(formField.option, modalItemInfo.propertySchema, dynamicForm)\"\r\n class=\"btn btn-primary btn-block\">\r\n {{ getButtonCaption(formField) }}\r\n </button>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n </form>\r\n</div>\r\n", styles: [":host ::ng-deep .custom-datepicker .p-datepicker-dropdown{height:100%;border-radius:4px}:host ::ng-deep .custom-datepicker .p-datepicker-input{border-radius:4px}::ng-deep .p-autocomplete-list{background-color:#fff}:host ::ng-deep .custom-autocomplete{display:flex;width:100%}:host ::ng-deep .custom-autocomplete .p-autocomplete-input{flex:1;width:100%;min-width:0;border:none!important;outline:none!important;box-shadow:none!important;background:transparent!important}:host ::ng-deep .custom-autocomplete .p-autocomplete-dropdown{height:100%;border-radius:4px}:host ::ng-deep .custom-autocomplete .p-autocomplete-input:focus,:host ::ng-deep .custom-autocomplete .p-autocomplete-input:focus-visible,:host ::ng-deep .custom-autocomplete .p-inputtext:enabled:focus{border:none!important;outline:none!important;box-shadow:none!important}.responsive-modal-grid{width:100%;min-width:0;box-sizing:border-box}@media screen and (max-width:767px){.responsive-modal-grid{grid-template-columns:repeat(12,minmax(0,1fr))!important;gap:10px!important}.responsive-modal-field{grid-column:1 / -1!important;width:100%!important;max-width:none!important;min-width:0!important}.responsive-modal-action:nth-last-child(2){grid-column:1 / span 6!important}.responsive-modal-action:last-child{grid-column:7 / span 6!important}.responsive-modal-action{width:100%!important;max-width:none!important;min-width:0!important;justify-self:stretch!important;box-sizing:border-box!important}.responsive-modal-action button{display:block!important;width:100%!important;max-width:none!important;min-width:0!important;margin:0!important;box-sizing:border-box!important}}:host{--modal-field-focus-color: var(--p-primary-color, #10b981);--modal-field-focus-shadow: 0 0 0 2px rgba(16, 185, 129, .16)}:host ::ng-deep input:not([type=checkbox]):not(:disabled):focus,:host ::ng-deep textarea:not(:disabled):focus{border-color:var(--modal-field-focus-color)!important;outline:none!important;box-shadow:var(--modal-field-focus-shadow)!important}:host ::ng-deep .custom-autocomplete:focus-within{border-color:var(--modal-field-focus-color)!important;outline:none!important;box-shadow:var(--modal-field-focus-shadow)!important}:host ::ng-deep .custom-autocomplete:focus-within .p-autocomplete-input{border:none!important;outline:none!important;box-shadow:none!important}:host ::ng-deep select:not(:disabled):focus{border-color:var(--modal-field-focus-color)!important;outline:none!important;box-shadow:var(--modal-field-focus-shadow)!important}:host ::ng-deep .ant-select-focused:not(.ant-select-disabled) .ant-select-selector,:host ::ng-deep nz-select:not(.ant-select-disabled):focus-within .ant-select-selector{border-color:var(--modal-field-focus-color)!important;outline:none!important;box-shadow:var(--modal-field-focus-shadow)!important}:host ::ng-deep .p-select:not(.p-disabled).p-focus,:host ::ng-deep .p-select:not(.p-disabled):focus-within,:host ::ng-deep .p-dropdown:not(.p-disabled).p-focus,:host ::ng-deep .p-dropdown:not(.p-disabled):focus-within{border-color:var(--modal-field-focus-color)!important;outline:none!important;box-shadow:var(--modal-field-focus-shadow)!important}:host ::ng-deep .custom-datepicker:focus-within .p-datepicker-input{border-color:var(--modal-field-focus-color)!important;outline:none!important;box-shadow:var(--modal-field-focus-shadow)!important}:host ::ng-deep input:disabled,:host ::ng-deep textarea:disabled,:host ::ng-deep select:disabled,:host ::ng-deep .p-disabled,:host ::ng-deep .ant-select-disabled .ant-select-selector{box-shadow:none!important}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i5.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i5.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i5.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "directive", type: i5.NgSwitch, selector: "[ngSwitch]", inputs: ["ngSwitch"] }, { kind: "directive", type: i5.NgSwitchCase, selector: "[ngSwitchCase]", inputs: ["ngSwitchCase"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i2.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i2.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { kind: "directive", type: i2.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { kind: "directive", type: i2.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: i2.NgForm, selector: "form:not([ngNoForm]):not([formGroup]):not([formArray]),ng-form,[ngForm]", inputs: ["ngFormOptions"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "ngmodule", type: NzSelectModule }, { kind: "component", type: i3.NzOptionComponent, selector: "nz-option", inputs: ["nzTitle", "nzLabel", "nzValue", "nzKey", "nzDisabled", "nzHide", "nzCustomContent"], exportAs: ["nzOption"] }, { kind: "component", type: i3.NzSelectComponent, selector: "nz-select", inputs: ["nzId", "nzSize", "nzStatus", "nzVariant", "nzOptionHeightPx", "nzOptionOverflowSize", "nzDropdownClassName", "nzDropdownMatchSelectWidth", "nzDropdownStyle", "nzNotFoundContent", "nzPlaceHolder", "nzPlacement", "nzMaxTagCount", "nzDropdownRender", "nzCustomTemplate", "nzPrefix", "nzSuffixIcon", "nzClearIcon", "nzRemoveIcon", "nzMenuItemSelectedIcon", "nzTokenSeparators", "nzMaxTagPlaceholder", "nzMaxMultipleCount", "nzMode", "nzFilterOption", "compareWith", "nzAllowClear", "nzShowSearch", "nzLoading", "nzAutoFocus", "nzAutoClearSearchValue", "nzServerSearch", "nzDisabled", "nzOpen", "nzSelectOnTab", "nzBackdrop", "nzOptions", "nzShowArrow"], outputs: ["nzOnSearch", "nzScrollToBottom", "nzOpenChange", "nzBlur", "nzFocus", "nzOnClear"], exportAs: ["nzSelect"] }, { kind: "ngmodule", type: NzDatePickerModule }, { kind: "component", type: i4.NzDatePickerComponent, selector: "nz-date-picker,nz-week-picker,nz-month-picker,nz-quarter-picker,nz-year-picker,nz-range-picker", inputs: ["nzInline", "nzAllowClear", "nzAutoFocus", "nzDisabled", "nzInputReadOnly", "nzOpen", "nzDisabledDate", "nzLocale", "nzPlaceHolder", "nzPopupStyle", "nzDropdownClassName", "nzSize", "nzStatus", "nzFormat", "nzVariant", "nzDateRender", "nzDisabledTime", "nzRenderExtraFooter", "nzShowToday", "nzMode", "nzShowNow", "nzRanges", "nzDefaultPickerValue", "nzSeparator", "nzSuffixIcon", "nzBackdrop", "nzId", "nzPlacement", "nzShowWeekNumber", "nzShowTime"], outputs: ["nzOnPanelChange", "nzOnCalendarChange", "nzOnOk", "nzOnOpenChange"], exportAs: ["nzDatePicker"] }, { kind: "directive", type: i4.NzRangePickerComponent, selector: "nz-range-picker", exportAs: ["nzRangePicker"] }, { kind: "ngmodule", type: DatePickerModule }, { kind: "component", type: i12.DatePicker, selector: "p-datePicker, p-datepicker, p-date-picker", inputs: ["iconDisplay", "styleClass", "inputStyle", "inputId", "inputStyleClass", "placeholder", "ariaLabelledBy", "ariaLabel", "iconAriaLabel", "dateFormat", "multipleSeparator", "rangeSeparator", "inline", "showOtherMonths", "selectOtherMonths", "showIcon", "icon", "readonlyInput", "shortYearCutoff", "hourFormat", "timeOnly", "stepHour", "stepMinute", "stepSecond", "showSeconds", "showOnFocus", "showWeek", "startWeekFromFirstDayOfYear", "showClear", "dataType", "selectionMode", "maxDateCount", "showButtonBar", "todayButtonStyleClass", "clearButtonStyleClass", "autofocus", "autoZIndex", "baseZIndex", "panelStyleClass", "panelStyle", "keepInvalid", "hideOnDateTimeSelect", "touchUI", "timeSeparator", "focusTrap", "showTransitionOptions", "hideTransitionOptions", "tabindex", "minDate", "maxDate", "disabledDates", "disabledDays", "showTime", "responsiveOptions", "numberOfMonths", "firstDayOfWeek", "view", "defaultDate", "appendTo", "motionOptions"], outputs: ["onFocus", "onBlur", "onClose", "onSelect", "onClear", "onInput", "onTodayClick", "onClearClick", "onMonthChange", "onYearChange", "onClickOutside", "onShow"] }, { kind: "ngmodule", type: AutoCompleteModule }, { kind: "component", type: i18.AutoComplete, selector: "p-autoComplete, p-autocomplete, p-auto-complete", inputs: ["minLength", "minQueryLength", "delay", "panelStyle", "styleClass", "panelStyleClass", "inputStyle", "inputId", "inputStyleClass", "placeholder", "readonly", "scrollHeight", "lazy", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "autoHighlight", "forceSelection", "type", "autoZIndex", "baseZIndex", "ariaLabel", "dropdownAriaLabel", "ariaLabelledBy", "dropdownIcon", "unique", "group", "completeOnFocus", "showClear", "dropdown", "showEmptyMessage", "dropdownMode", "multiple", "addOnTab", "tabindex", "dataKey", "emptyMessage", "showTransitionOptions", "hideTransitionOptions", "autofocus", "autocomplete", "optionGroupChildren", "optionGroupLabel", "overlayOptions", "suggestions", "optionLabel", "optionValue", "id", "searchMessage", "emptySelectionMessage", "selectionMessage", "autoOptionFocus", "selectOnFocus", "searchLocale", "optionDisabled", "focusOnHover", "typeahead", "addOnBlur", "separator", "appendTo", "motionOptions"], outputs: ["completeMethod", "onSelect", "onUnselect", "onAdd", "onFocus", "onBlur", "onDropdownClick", "onClear", "onInputKeydown", "onKeyUp", "onShow", "onHide", "onLazyLoad"] }, { kind: "ngmodule", type: InputTextModule }, { kind: "component", type: Label, selector: "vl-label", inputs: ["formField", "modalItemInfo"] }, { kind: "component", type: String$1, selector: "vl-string", inputs: ["formField", "modalItemInfo"] }, { kind: "component", type: Textbox, selector: "vl-textbox", inputs: ["formField", "modalItemInfo"] }, { kind: "directive", type: CustomKeyboardDirective, selector: "[vlCustomKeyboard]", inputs: ["vlCustomKeyboard"] }, { kind: "pipe", type: PlaceholderPipe, name: "vlPlaceholder" }, { kind: "pipe", type: i5.CurrencyPipe, name: "currency" }] });
6459
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.2", type: ModelComponent, isStandalone: true, selector: "vl-model", inputs: { errorMessages: "errorMessages", modalItemInfo: "modalItemInfo", selectedLanguageInfo: "selectedLanguageInfo", userInfo: "userInfo", setFormDataHandler: "setFormDataHandler" }, usesOnChanges: true, ngImport: i0, template: "<!-- Faramarz Yousefian and Agent Toni (Claude Opus 5.5) 2026-10-13\r\n - fix: the placeholder comes from vlPlaceholder (pipes/placeholder.pipe.ts) - empty where the\r\n project defines none; it showed the text \"undefined\" -->\r\n<!-- Faramarz Yousefian and Agent Toni (Claude Opus 5) 2026-10-07\r\n - change: number, autocomplete, date and time fields take the toolkit keyboard of their\r\n attribute type (keyboardTypeFor) instead of only an explicit option.keyboardType\r\n - change: the date picker docks at the bottom on the devices (model-datepicker-panel--docked);\r\n the time picker stays attached to its field in a compact form (model-timepicker-panel);\r\n both report which picker closed (onPickerClose(picker)) -->\r\n\r\n<!-- Shuaib 2026-09-24\r\n - change: the model field switch uses renderFieldType so legacy checkbox fields render as boolean. -->\r\n\r\n<!-- Faramarz Yousefian and Agent Toni (Claude Opus 5) 2026-09-19\r\n - new: a @contract comment on the widest type coverage in the toolkit, and one on the credit\r\n card case recording that the rename reached this file first -->\r\n<!-- Loader Spinner -->\r\n<div *ngIf=\"isLoading\" class=\"loader-overlay\">\r\n <div class=\"spinner\"></div>\r\n</div>\r\n<div [style]=\"getStyleWithoutClasses(modalItemInfo?.layoutSchema?.style).style\"\r\n [class]=\"modalItemInfo?.layoutSchema?.style?.classes[0]\">\r\n <form #dynamicForm=\"ngForm\"\r\n *ngIf=\"modalItemInfo?.layoutSchema?.formSections?.length > 0\"\r\n (submit)=\"$event.preventDefault()\">\r\n <div\r\n *ngFor=\"let formSection of modalItemInfo?.layoutSchema?.formSections\">\r\n <div *ngIf=\"formSection?.label?.caption\"\r\n [class]=\"formSection?.label?.style?.classes[0]\"\r\n [style]=\"getStyleWithoutClasses(formSection?.label?.style).style\">\r\n {{formSection.label.caption}}\r\n </div>\r\n <div *ngIf=\"formSection?.formFields?.length > 0\"\r\n [class]=\"formSection?.style?.classes?.[0] || ''\"\r\n [ngStyle]=\"getSectionBodyStyle(formSection)\">\r\n <div *ngFor=\"let formField of formSection.formFields\"\r\n [ngStyle]=\"getFieldWrapperStyle(formField)\"\r\n [class]=\"formField?.style?.classes || ''\">\r\n\r\n <!-- @contract decision: the widest type coverage in the toolkit\r\n reality: every field type except the grid-only quantity renders here.\r\n When another container drops a type, this is the way out.\r\n seen: measured 2026-09-19. Note the file is model.component.html while\r\n the container is called modal in layout files - that costs a\r\n search every time -->\r\n <!-- @contract compatibility: checkbox is rendered as boolean for existing projects. -->\r\n <div [ngSwitch]=\"renderFieldType(\r\n formField?.scope?.reference &&\r\n modalItemInfo?.propertySchema?.[\r\n getScope(formField.scope.reference)\r\n ]\r\n ? modalItemInfo.propertySchema[\r\n getScope(formField.scope.reference)\r\n ]?.[\r\n formField.scope.reference.split('/').pop()\r\n ]?.type\r\n : 'default'\r\n )\">\r\n <!-- Media control -->\r\n <div\r\n *ngSwitchCase=\"'media'\"\r\n [style]=\"getStyleWithoutClasses(formField?.style).style\"\r\n [class]=\"formField.style?.classes ? formField.style?.classes[0] : ''\">\r\n\r\n <ng-container\r\n *ngTemplateOutlet=\"modelMediaContent; context: { field: formField }\">\r\n </ng-container>\r\n </div>\r\n\r\n <!-- credit card control -->\r\n <!-- @contract decision: the credit card type is spelled creditCard\r\n reality: this file was renamed on 2026-09-15, form.component.html and\r\n utility.service.ts followed on 2026-09-19. carditCard is read\r\n nowhere any more.\r\n failure: a data object still declaring carditCard renders empty. -->\r\n <div *ngSwitchCase=\"'creditCard'\"\r\n [style]=\"getStyleWithoutClasses(formField?.style).style\"\r\n [class]=\"formField.style?.classes[0]\">\r\n <div id=\"card-element\">\r\n <!-- a Stripe element will be inserted here -->\r\n </div>\r\n <!-- Used to display form errors -->\r\n <div id=\"card-errors\"\r\n class=\"displayError.textContent!=='': 'alert alert-danger mt-1'\">\r\n </div>\r\n </div>\r\n\r\n <!-- string control -->\r\n <div *ngSwitchCase=\"'string'\" class=\"form-group mb-3\">\r\n @if(formField.option && formField.option.control &&\r\n !formField.option.protected){\r\n @switch (formField.option.control) {\r\n @case ('textInput') {\r\n <div\r\n [ngStyle]=\"getFieldInnerLayoutStyle(formField)\">\r\n <vl-label [formField]=\"formField\"\r\n [modalItemInfo]=\"modalItemInfo\">\r\n </vl-label>\r\n <vl-textbox [formField]=\"formField\"\r\n [modalItemInfo]=\"modalItemInfo\">\r\n </vl-textbox>\r\n </div>\r\n <!-- Error Message -->\r\n <!-- <div *ngIf=\"inputField?.touched && inputField?.invalid\"\r\n [style]=\"getStyleWithoutClasses(formField?.validation?.style).style\">\r\n <p class=\"text-danger\" *ngIf=\"inputField?.errors?.['required']\">\r\n {{setErroMessage(formField, errorMessages, \"required\")}}</p>\r\n <p class=\"text-danger\" *ngIf=\"inputField?.errors?.['email']\">\r\n {{(formField.label?.value ?\r\n formField.label?.value :\r\n modalItemInfo.propertySchema[getScope(formField.scope?.reference)][formField.scope?.reference.split('/').pop()]?.caption)\r\n +\r\n ' ' + errorMessages.pattern}}</p>\r\n </div> -->\r\n }\r\n\r\n @case ('password') {\r\n <span>Switch not supported yet</span>\r\n\r\n }\r\n @case ('combobox') {\r\n <span>Combobox not supported yet</span>\r\n }\r\n @case('textArea'){\r\n <span>TextArea not supported yet</span>\r\n }\r\n @case ('switch') {\r\n <span>Switch not supported yet</span>\r\n }\r\n\r\n @case('radiobutton') {\r\n <span>Radiobutton not supported yet</span>\r\n }\r\n\r\n @case ('dropdown') {\r\n <span *ngIf=\"formField.option?.postfixCaption\">\r\n <select id=\"dynamic-dropdown\"\r\n [class]=\"formField.style?.classes ? formField.style?.classes[0]: ''\"\r\n #dropdownField=\"ngModel\"\r\n [style]=\"getStyleWithoutClasses(formField?.style).style\"\r\n [name]=\"formField.scope?.reference\"\r\n [(ngModel)]=\"modalItemInfo.propertySchema[getScope(formField.scope?.reference)][formField.scope?.reference.split('/').pop()].value\">\r\n <option\r\n *ngFor=\"let item of modalItemInfo.propertySchema[getScope(formField.scope?.reference)][formField.scope?.reference.split('/').pop()]?.data\"\r\n [value]=\"formField?.option?.optionValue ? formField.option.optionValue : 'value'\">\r\n {{ formField?.option?.optionLabel ?\r\n formField.option.optionLabel :\r\n 'label'}}</option>\r\n </select>\r\n <label\r\n [style]=\"getStyleWithoutClasses(formField?.label?.style).style\">{{modalItemInfo.propertySchema[getScope(formField.scope)][formField.scope?.reference.split('/').pop()]?.caption\r\n }}</label>\r\n </span>\r\n <div *ngIf=\"!formField.option?.postfixCaption\">\r\n <div\r\n [ngStyle]=\"getFieldInnerLayoutStyle(formField)\">\r\n <label\r\n [style]=\"getStyleWithoutClasses(formField?.label?.style).style\">{{modalItemInfo.propertySchema[getScope(formField.scope?.reference)][formField.scope?.reference.split('/').pop()]?.caption\r\n }}</label>\r\n\r\n <nz-select nzShowSearch nzAllowClear\r\n nzPlaceHolder=\"Select\"\r\n #dropdownField=\"ngModel\"\r\n [required]=\"formField.option.required\"\r\n [class]=\"formField.style?.classes ? formField.style?.classes[0]: ''\"\r\n [style]=\"getStyleWithoutClasses(formField?.style).style\"\r\n [name]=\"formField.scope?.reference\"\r\n [(ngModel)]=\"modalItemInfo.propertySchema[getScope(formField.scope?.reference)][formField.scope?.reference.split('/').pop()].value\">\r\n <nz-option\r\n *ngFor=\"let item of modalItemInfo.propertySchema[getScope(formField.scope?.reference)][formField.scope?.reference.split('/').pop()]?.data\"\r\n [nzLabel]=\"item[formField?.option?.optionLabel ? formField.option.optionLabel : 'label']\"\r\n [nzValue]=\"item[formField?.option?.optionValue ? formField.option.optionValue : 'value']\"></nz-option>\r\n </nz-select>\r\n </div>\r\n <!-- Error Message -->\r\n <div\r\n *ngIf=\"dropdownField?.touched && dropdownField?.invalid\"\r\n [style]=\"getStyleWithoutClasses(formField?.validation?.style).style\">\r\n <p class=\"text-danger\"\r\n *ngIf=\"dropdownField?.errors?.['required']\">\r\n {{formField.label?.value ?\r\n formField.label?.value :\r\n modalItemInfo.propertySchema[getScope(formField.scope?.reference)][formField.scope?.reference.split('/').pop()]?.caption\r\n +\r\n ' ' + errorMessages.required}}</p>\r\n <p class=\"text-danger\"\r\n *ngIf=\"dropdownField?.errors?.['email']\">\r\n {{(formField.label?.value ?\r\n formField.label?.value :\r\n modalItemInfo.propertySchema[getScope(formField.scope?.reference)][formField.scope?.reference.split('/').pop()]?.caption)\r\n +\r\n ' ' + errorMessages.pattern}}</p>\r\n </div>\r\n </div>\r\n }\r\n\r\n @case ('autocomplete') {\r\n <div\r\n [ngStyle]=\"getFieldInnerLayoutStyle(formField)\">\r\n <vl-label [formField]=\"formField\"\r\n [modalItemInfo]=\"modalItemInfo\">\r\n </vl-label>\r\n\r\n <span>\r\n <p-autocomplete\r\n #autocompleteField=\"ngModel\"\r\n [required]=\"formField.option.required\"\r\n [name]=\"formField.scope?.reference\"\r\n styleClass=\"custom-autocomplete\"\r\n [(ngModel)]=\"modalItemInfo.propertySchema[getScope(formField.scope?.reference)][formField.scope?.reference.split('/').pop()].value\"\r\n [style]=\"getStyleWithoutClasses(formField?.scope?.style).style\"\r\n [class]=\"formField?.scope?.style?.classes ? formField?.scope?.style?.classes[0] : ''\"\r\n [suggestions]=\"matchData\"\r\n [dropdown]=\"true\"\r\n [optionLabel]=\"formField?.option?.autocomplete?.response?.label ? formField.option.autocomplete.response.label : 'label'\"\r\n [placeholder]=\"modalItemInfo.propertySchema | vlPlaceholder: formField.scope?.reference\"\r\n (completeMethod)=\"autocompChangeEvent($event, formField)\"\r\n (ngModelChange)=\"autocompFocusOutEvent($event, formField)\"\r\n [vlCustomKeyboard]=\"keyboardTypeFor(formField)\">\r\n </p-autocomplete>\r\n <!-- Error Message -->\r\n <div\r\n *ngIf=\"autocompleteField?.touched && autocompleteField?.invalid\"\r\n [style]=\"getStyleWithoutClasses(formField?.validation?.style).style\">\r\n <p class=\"text-danger\"\r\n *ngIf=\"autocompleteField?.errors?.['required']\">\r\n {{setErroMessage(formField,\r\n errorMessages, \"required\")}}</p>\r\n <p class=\"text-danger\"\r\n *ngIf=\"autocompleteField?.errors?.['email']\">\r\n {{(formField.label?.value ?\r\n formField.label?.value :\r\n modalItemInfo.propertySchema[getScope(formField.scope?.reference)][formField.scope?.reference.split('/').pop()]?.caption)\r\n +\r\n ' ' +\r\n errorMessages.pattern}}</p>\r\n </div>\r\n </span>\r\n </div>\r\n }\r\n }\r\n }@else{\r\n <div *ngIf=\"!formField.option.protected\">\r\n <div\r\n [ngStyle]=\"getFieldInnerLayoutStyle(formField)\">\r\n <vl-label [formField]=\"formField\"\r\n [modalItemInfo]=\"modalItemInfo\">\r\n </vl-label>\r\n <vl-textbox [formField]=\"formField\"\r\n [modalItemInfo]=\"modalItemInfo\">\r\n </vl-textbox>\r\n </div>\r\n <!-- Error Message -->\r\n <!-- <div *ngIf=\"inputField?.touched && inputField?.invalid\"\r\n [style]=\"getStyleWithoutClasses(formField?.validation?.style).style\">\r\n <p class=\"text-danger\" *ngIf=\"inputField?.errors?.['required']\">\r\n {{setErroMessage(formField, errorMessages, \"required\")}}</p>\r\n <p class=\"text-danger\" *ngIf=\"inputField?.errors?.['email']\">\r\n {{(formField.label?.value ?\r\n formField.label?.value :\r\n modalItemInfo.propertySchema[getScope(formField.scope?.reference)][formField.scope?.reference.split('/').pop()]?.caption)\r\n +\r\n ' ' + errorMessages.pattern}}</p>\r\n </div> -->\r\n </div>\r\n }\r\n <span *ngIf=\"formField.option.protected\"\r\n [style]=\"getStyleWithoutClasses(formField?.label?.style).style\"\r\n [class]=\"formField?.label?.style.classes ? formField?.label?.style?.classes[0] : ''\">\r\n <vl-string [formField]=\"formField\"\r\n [modalItemInfo]=\"modalItemInfo\">\r\n </vl-string>\r\n </span>\r\n\r\n </div>\r\n\r\n <!-- number control -->\r\n <div *ngSwitchCase=\"'number'\" class=\"form-group mb-3\">\r\n <span *ngIf=\"formField.option.protected\"\r\n [style]=\"getStyleWithoutClasses(formField?.label?.style).style\"\r\n [class]=\"formField?.label?.style.classes ? formField?.label?.style?.classes[0] : ''\">\r\n <h5>{{\r\n modalItemInfo.propertySchema[getScope(formField.scope?.reference)][formField.scope?.reference.split('/').pop()]?.caption\r\n }} {{\r\n modalItemInfo.propertySchema[getScope(formField.scope?.reference)][formField.scope?.reference.split('/').pop()]?.value\r\n |\r\n currency:formField.option.currency :true:\r\n formField.option?.decimalPoint}}\r\n </h5>\r\n </span>\r\n <span *ngIf=\"!formField.option.protected\">\r\n <div\r\n [ngStyle]=\"getFieldInnerLayoutStyle(formField)\">\r\n <label\r\n [style]=\"getStyleWithoutClasses(formField?.label?.style).style\"\r\n [class]=\"formField?.label?.style.classes ? formField?.label?.style?.classes[0] : ''\">{{\r\n formField.label?.value\r\n ?\r\n formField.label?.value :\r\n modalItemInfo.propertySchema[getScope(formField.scope?.reference)][formField.scope?.reference.split('/').pop()]?.caption\r\n }}</label>\r\n <input type=\"number\"\r\n [class]=\"formField.style?.classes ? formField.style?.classes[0]: ''\"\r\n [vlCustomKeyboard]=\"keyboardTypeFor(formField)\"\r\n [style]=\"getStyleWithoutClasses(formField?.style).style\"\r\n [(ngModel)]=\"modalItemInfo.propertySchema[getScope(formField.scope?.reference)][formField.scope?.reference.split('/').pop()].value\"\r\n [name]=\"formField.scope?.reference\"\r\n [placeholder]=\"modalItemInfo.propertySchema | vlPlaceholder: formField.scope?.reference\" />\r\n </div>\r\n </span>\r\n </div>\r\n\r\n <!-- DateRange control -->\r\n <div *ngSwitchCase=\"'dateRange'\"\r\n class=\"form-group mb-3\">\r\n <span *ngIf=\"formField.option.protected\"\r\n [style]=\"getStyleWithoutClasses(formField?.label?.style).style\"\r\n [class]=\"formField?.label?.style.classes ? formField?.label?.style?.classes[0] : ''\">\r\n <vl-string [formField]=\"formField\"\r\n [modalItemInfo]=\"modalItemInfo\">\r\n </vl-string>\r\n </span>\r\n <div *ngIf=\"!formField.option.protected\">\r\n <div\r\n [ngStyle]=\"getFieldInnerLayoutStyle(formField)\">\r\n <label\r\n [style]=\"getStyleWithoutClasses(formField?.label?.style).style\"\r\n [class]=\"formField?.label?.style.classes ? formField?.label?.style?.classes[0] : ''\">{{\r\n formField.label?.value\r\n ?\r\n formField.label?.value :\r\n modalItemInfo.propertySchema[getScope(formField.scope?.reference)][formField.scope?.reference.split('/').pop()]?.caption\r\n }}</label>\r\n <nz-range-picker #dateRangeField=\"ngModel\"\r\n [required]=\"formField.option.required\"\r\n [name]=\"formField.scope?.reference\"\r\n [style]=\"getStyleWithoutClasses(formField?.style).style\"\r\n [(ngModel)]=\"modalItemInfo.propertySchema[getScope(formField.scope?.reference)][formField.scope?.reference.split('/').pop()].value\"></nz-range-picker>\r\n </div>\r\n <!-- Error Message -->\r\n <div\r\n *ngIf=\"dateRangeField?.touched && dateRangeField?.invalid\"\r\n [style]=\"getStyleWithoutClasses(formField?.validation?.style).style\">\r\n <p class=\"text-danger\"\r\n *ngIf=\"dateRangeField?.errors?.['required']\">\r\n {{formField.label?.value ?\r\n formField.label?.value :\r\n modalItemInfo.propertySchema[getScope(formField.scope?.reference)][formField.scope?.reference.split('/').pop()]?.caption\r\n +\r\n ' ' + errorMessages.required}}</p>\r\n <p class=\"text-danger\"\r\n *ngIf=\"dateRangeField?.errors?.['email']\">\r\n {{(formField.label?.value ?\r\n formField.label?.value :\r\n modalItemInfo.propertySchema[getScope(formField.scope?.reference)][formField.scope?.reference.split('/').pop()]?.caption)\r\n +\r\n ' ' + errorMessages.pattern}}</p>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- Date control -->\r\n <div *ngSwitchCase=\"'date'\" class=\"form-group mb-3\">\r\n <span\r\n *ngIf=\"formField.option.protected\"\r\n [style]=\"getStyleWithoutClasses(formField?.label?.style).style\"\r\n [class]=\"formField?.label?.style.classes ? formField?.label?.style?.classes[0] : ''\">\r\n <vl-string\r\n [formField]=\"formField\"\r\n [modalItemInfo]=\"modalItemInfo\">\r\n </vl-string>\r\n </span>\r\n\r\n <div *ngIf=\"!formField.option.protected\">\r\n <div\r\n [ngStyle]=\"getFieldInnerLayoutStyle(formField)\">\r\n <label\r\n [style]=\"getStyleWithoutClasses(formField?.label?.style).style\"\r\n [class]=\"formField?.label?.style.classes ? formField?.label?.style?.classes[0] : ''\">\r\n {{ getLabel(formField) }}\r\n </label>\r\n\r\n <span>\r\n <div class=\"picker-field\">\r\n <p-datepicker\r\n #datePicker\r\n #dateField=\"ngModel\"\r\n styleClass=\"custom-datepicker\"\r\n [required]=\"formField.option.required\"\r\n [name]=\"formField.scope?.reference\"\r\n [disabled]=\"formField?.option?.disabled\"\r\n [showIcon]=\"false\"\r\n [showOnFocus]=\"false\"\r\n appendTo=\"body\"\r\n [autoZIndex]=\"true\"\r\n [baseZIndex]=\"10000\"\r\n [panelStyleClass]=\"picker.datePanelClass\"\r\n [motionOptions]=\"picker.dockedMotion\"\r\n [vlCustomKeyboard]=\"keyboardTypeFor(formField)\"\r\n (pointerdown)=\"picker.onFieldPointerDown($event, datePicker)\"\r\n (onFocus)=\"picker.onFieldFocus($event)\"\r\n (onShow)=\"picker.onShown()\"\r\n (onClose)=\"picker.onClose(datePicker)\"\r\n (ngModelChange)=\"dateChangeEvent(formField, $event)\"\r\n (onInput)=\"onDateTyping($event)\"\r\n [dateFormat]=\"\r\n modalItemInfo.propertySchema[\r\n getScope(formField.scope?.reference)\r\n ][\r\n formField.scope?.reference.split('/').pop()\r\n ]?.format || 'yy-mm-dd'\r\n \"\r\n [(ngModel)]=\"\r\n modalItemInfo.propertySchema[\r\n getScope(formField.scope?.reference)\r\n ][\r\n formField.scope?.reference.split('/').pop()\r\n ].value\r\n \"\r\n [class]=\"formField?.scope?.style?.classes?.[0] || ''\"\r\n [style]=\"getStyleWithoutClasses(formField?.scope?.style).style\">\r\n </p-datepicker>\r\n\r\n <button\r\n type=\"button\"\r\n class=\"picker-field__icon\"\r\n aria-label=\"Open calendar\"\r\n [disabled]=\"formField?.option?.disabled\"\r\n (pointerdown)=\"picker.openFromIcon($event, datePicker)\"\r\n (click)=\"picker.blockIconClick($event)\">\r\n <i class=\"pi pi-calendar\"></i>\r\n </button>\r\n </div>\r\n\r\n <div\r\n *ngIf=\"dateField?.touched && dateField?.invalid\"\r\n [style]=\"getStyleWithoutClasses(formField?.validation?.style).style\">\r\n <p class=\"text-danger\"\r\n *ngIf=\"dateField?.errors?.['required']\">\r\n {{ setErroMessage(formField,\r\n errorMessages, 'required') }}\r\n </p>\r\n <p class=\"text-danger\"\r\n *ngIf=\"dateField?.errors?.['email']\">\r\n {{\r\n (formField.label?.value\r\n ? formField.label?.value\r\n : modalItemInfo.propertySchema[\r\n getScope(formField.scope?.reference)\r\n ][\r\n formField.scope?.reference.split('/').pop()\r\n ]?.caption)\r\n + ' ' + errorMessages.pattern\r\n }}\r\n </p>\r\n </div>\r\n </span>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- Time control -->\r\n <div *ngSwitchCase=\"'time'\" class=\"form-group mb-3\">\r\n <span\r\n *ngIf=\"formField.option.protected\"\r\n [style]=\"getStyleWithoutClasses(formField?.label?.style).style\"\r\n [class]=\"formField?.label?.style.classes ? formField?.label?.style?.classes[0] : ''\">\r\n <vl-string\r\n [formField]=\"formField\"\r\n [modalItemInfo]=\"modalItemInfo\">\r\n </vl-string>\r\n </span>\r\n\r\n <div *ngIf=\"!formField.option.protected\">\r\n <div\r\n [ngStyle]=\"getFieldInnerLayoutStyle(formField)\">\r\n <label\r\n [style]=\"getStyleWithoutClasses(formField?.label?.style).style\"\r\n [class]=\"formField?.label?.style.classes ? formField?.label?.style?.classes[0] : ''\">\r\n {{ getLabel(formField) }}\r\n </label>\r\n\r\n <span>\r\n <div class=\"picker-field\">\r\n <p-datepicker\r\n #timePicker\r\n #timeField=\"ngModel\"\r\n styleClass=\"custom-datepicker\"\r\n [required]=\"formField.option.required\"\r\n [name]=\"formField.scope?.reference\"\r\n [timeOnly]=\"true\"\r\n hourFormat=\"24\"\r\n [disabled]=\"formField?.option?.disabled\"\r\n [showIcon]=\"false\"\r\n [showOnFocus]=\"false\"\r\n appendTo=\"body\"\r\n [autoZIndex]=\"true\"\r\n [baseZIndex]=\"10000\"\r\n [panelStyleClass]=\"picker.timePanelClass\"\r\n [vlCustomKeyboard]=\"keyboardTypeFor(formField)\"\r\n (pointerdown)=\"picker.onFieldPointerDown($event, timePicker)\"\r\n (onFocus)=\"picker.onFieldFocus($event)\"\r\n (onShow)=\"onTimePanelShow(formField)\"\r\n (onClose)=\"picker.onClose(timePicker)\"\r\n (onInput)=\"onTimeTyping($event)\"\r\n (ngModelChange)=\"timeChangeEvent(formField, $event)\"\r\n [style]=\"getStyleWithoutClasses(formField?.scope?.style).style\"\r\n [(ngModel)]=\"\r\n modalItemInfo.propertySchema[\r\n getScope(formField.scope?.reference)\r\n ][\r\n formField.scope?.reference.split('/').pop()\r\n ].value\r\n \"\r\n [class]=\"formField?.scope?.style?.classes?.[0] || ''\">\r\n </p-datepicker>\r\n\r\n <button\r\n type=\"button\"\r\n class=\"picker-field__icon\"\r\n aria-label=\"Open time picker\"\r\n [disabled]=\"formField?.option?.disabled\"\r\n (pointerdown)=\"picker.openFromIcon($event, timePicker)\"\r\n (click)=\"picker.blockIconClick($event)\">\r\n <i class=\"pi pi-clock\"></i>\r\n </button>\r\n </div>\r\n\r\n <div\r\n *ngIf=\"timeField?.touched && timeField?.invalid\"\r\n [style]=\"getStyleWithoutClasses(formField?.validation?.style).style\">\r\n <p class=\"text-danger\"\r\n *ngIf=\"timeField?.errors?.['required']\">\r\n {{ setErroMessage(formField,\r\n errorMessages, 'required') }}\r\n </p>\r\n <p class=\"text-danger\"\r\n *ngIf=\"timeField?.errors?.['email']\">\r\n {{\r\n (formField.label?.value\r\n ? formField.label?.value\r\n : modalItemInfo.propertySchema[\r\n getScope(formField.scope?.reference)\r\n ][\r\n formField.scope?.reference.split('/').pop()\r\n ]?.caption)\r\n + ' ' + errorMessages.pattern\r\n }}\r\n </p>\r\n </div>\r\n </span>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- Autocomplete control -->\r\n <div *ngSwitchCase=\"'autocomplete'\"\r\n class=\"form-group mb-3\">\r\n <span *ngIf=\"formField.option.protected\"\r\n [style]=\"getStyleWithoutClasses(formField?.label?.style).style\"\r\n [class]=\"formField?.label?.style.classes ? formField?.label?.style?.classes[0] : ''\">\r\n <vl-string [formField]=\"formField\"\r\n [modalItemInfo]=\"modalItemInfo\">\r\n </vl-string>\r\n </span>\r\n <div *ngIf=\"!formField.option.protected\">\r\n <div\r\n [ngStyle]=\"getFieldInnerLayoutStyle(formField)\">\r\n <vl-label [formField]=\"formField\"\r\n [modalItemInfo]=\"modalItemInfo\">\r\n </vl-label>\r\n\r\n <span>\r\n <p-autocomplete\r\n #autocompleteField=\"ngModel\"\r\n [required]=\"formField.option.required\"\r\n [name]=\"formField.scope?.reference\"\r\n styleClass=\"custom-autocomplete\"\r\n [(ngModel)]=\"modalItemInfo.propertySchema[getScope(formField.scope?.reference)][formField.scope?.reference.split('/').pop()].value\"\r\n [style]=\"getStyleWithoutClasses(formField?.scope?.style).style\"\r\n [class]=\"formField?.scope?.style?.classes ? formField?.scope?.style?.classes[0] : ''\"\r\n [suggestions]=\"matchData\"\r\n [dropdown]=\"true\"\r\n [optionLabel]=\"formField?.option?.autocomplete?.response?.label ? formField.option.autocomplete.response.label : 'label'\"\r\n [placeholder]=\"modalItemInfo.propertySchema | vlPlaceholder: formField.scope?.reference\"\r\n (completeMethod)=\"autocompChangeEvent($event, formField)\"\r\n (ngModelChange)=\"autocompFocusOutEvent($event, formField)\"\r\n [vlCustomKeyboard]=\"keyboardTypeFor(formField)\">\r\n </p-autocomplete>\r\n <!-- Error Message -->\r\n <div\r\n *ngIf=\"autocompleteField?.touched && autocompleteField?.invalid\"\r\n [style]=\"getStyleWithoutClasses(formField?.validation?.style).style\">\r\n <p class=\"text-danger\"\r\n *ngIf=\"autocompleteField?.errors?.['required']\">\r\n {{setErroMessage(formField,\r\n errorMessages, \"required\")}}</p>\r\n <p class=\"text-danger\"\r\n *ngIf=\"autocompleteField?.errors?.['email']\">\r\n {{(formField.label?.value ?\r\n formField.label?.value :\r\n modalItemInfo.propertySchema[getScope(formField.scope?.reference)][formField.scope?.reference.split('/').pop()]?.caption)\r\n +\r\n ' ' +\r\n errorMessages.pattern}}</p>\r\n </div>\r\n </span>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- checkBox control -->\r\n <div *ngSwitchCase=\"'boolean'\" class=\"form-group mb-3\"\r\n [style]=\"getStyleWithoutClasses(formField?.style).style\"\r\n [class]=\"formField.style?.classes ? formField.style?.classes[0] : ''\">\r\n <span *ngIf=\"formField.option?.postfixCaption\">\r\n <label class=\"form-check-label\"><input\r\n type=\"checkbox\" class=\"form-check-input\"\r\n [(ngModel)]=\"modalItemInfo.propertySchema[getScope(formField.scope?.reference)][formField.scope?.reference.split('/').pop()].value\"\r\n [name]=\"formField.scope?.reference\"\r\n (ngModelChange)=\"invokeSetformData()\" />{{\r\n modalItemInfo.propertySchema[getScope(formField.scope?.reference)][formField.scope?.reference.split('/').pop()]?.caption\r\n }}</label>\r\n </span>\r\n <div *ngIf=\"!formField.option?.postfixCaption\"\r\n [class]=\"formField?.layout == 'horizontal' ? 'horizontal-layout' : 'row'\">\r\n <label class=\"form-check-label\">{{\r\n modalItemInfo.propertySchema[getScope(formField.scope?.reference)][formField.scope?.reference.split('/').pop()]?.caption\r\n }}\r\n <input type=\"checkbox\"\r\n class=\"form-check-input\"\r\n [(ngModel)]=\"modalItemInfo.propertySchema[getScope(formField.scope?.reference)][formField.scope?.reference.split('/').pop()].value\"\r\n [name]=\"formField.scope?.reference\" /></label>\r\n </div>\r\n </div>\r\n\r\n <!-- dropdown control -->\r\n <div *ngSwitchCase=\"'dropdown'\" class=\"form-group mb-3\"\r\n [style]=\"getStyleWithoutClasses(formField?.style).style\"\r\n [class]=\"formField.style?.classes ? formField.style?.classes[0] : ''\">\r\n <span *ngIf=\"formField.option?.postfixCaption\">\r\n <select id=\"dynamic-dropdown\"\r\n [class]=\"formField.style?.classes ? formField.style?.classes[0]: ''\"\r\n #dropdownField=\"ngModel\"\r\n [style]=\"getStyleWithoutClasses(formField?.style).style\"\r\n [name]=\"formField.scope?.reference\"\r\n [(ngModel)]=\"modalItemInfo.propertySchema[getScope(formField.scope?.reference)][formField.scope?.reference.split('/').pop()].value\">\r\n <option\r\n *ngFor=\"let item of modalItemInfo.propertySchema[getScope(formField.scope?.reference)][formField.scope?.reference.split('/').pop()]?.data\"\r\n [value]=\"formField?.option?.optionValue ? formField.option.optionValue : 'value'\">\r\n {{ formField?.option?.optionLabel ?\r\n formField.option.optionLabel :\r\n 'label'}}</option>\r\n </select>\r\n <label\r\n [style]=\"getStyleWithoutClasses(formField?.label?.style).style\">{{modalItemInfo.propertySchema[getScope(formField.scope)][formField.scope?.reference.split('/').pop()]?.caption\r\n }}</label>\r\n </span>\r\n <div *ngIf=\"!formField.option?.postfixCaption\">\r\n <div\r\n [ngStyle]=\"getFieldInnerLayoutStyle(formField)\">\r\n <label\r\n [style]=\"getStyleWithoutClasses(formField?.label?.style).style\">{{modalItemInfo.propertySchema[getScope(formField.scope?.reference)][formField.scope?.reference.split('/').pop()]?.caption\r\n }}</label>\r\n\r\n <nz-select nzShowSearch nzAllowClear\r\n nzPlaceHolder=\"Select\"\r\n #dropdownField=\"ngModel\"\r\n [required]=\"formField.option.required\"\r\n [class]=\"formField.style?.classes ? formField.style?.classes[0]: ''\"\r\n [style]=\"getStyleWithoutClasses(formField?.style).style\"\r\n [name]=\"formField.scope?.reference\"\r\n [(ngModel)]=\"modalItemInfo.propertySchema[getScope(formField.scope?.reference)][formField.scope?.reference.split('/').pop()].value\">\r\n <nz-option\r\n *ngFor=\"let item of modalItemInfo.propertySchema[getScope(formField.scope?.reference)][formField.scope?.reference.split('/').pop()]?.data\"\r\n [nzLabel]=\"item[formField?.option?.optionLabel ? formField.option.optionLabel : 'label']\"\r\n [nzValue]=\"item[formField?.option?.optionValue ? formField.option.optionValue : 'value']\"></nz-option>\r\n </nz-select>\r\n </div>\r\n <!-- Error Message -->\r\n <div\r\n *ngIf=\"dropdownField?.touched && dropdownField?.invalid\"\r\n [style]=\"getStyleWithoutClasses(formField?.validation?.style).style\">\r\n <p class=\"text-danger\"\r\n *ngIf=\"dropdownField?.errors?.['required']\">\r\n {{formField.label?.value ?\r\n formField.label?.value :\r\n modalItemInfo.propertySchema[getScope(formField.scope?.reference)][formField.scope?.reference.split('/').pop()]?.caption\r\n +\r\n ' ' + errorMessages.required}}</p>\r\n <p class=\"text-danger\"\r\n *ngIf=\"dropdownField?.errors?.['email']\">\r\n {{(formField.label?.value ?\r\n formField.label?.value :\r\n modalItemInfo.propertySchema[getScope(formField.scope?.reference)][formField.scope?.reference.split('/').pop()]?.caption)\r\n +\r\n ' ' + errorMessages.pattern}}</p>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- button control -->\r\n <div *ngSwitchCase=\"'default'\">\r\n <button type=\"button\"\r\n [ngStyle]=\"getStyleWithoutClasses(formField.style).style\"\r\n (click)=\"invokeFormBtnClick(formField.option, modalItemInfo.propertySchema, dynamicForm)\"\r\n class=\"btn btn-primary btn-block\">\r\n {{ getButtonCaption(formField) }}\r\n </button>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n </form>\r\n</div>\r\n<ng-template #modelMediaContent let-field=\"field\">\r\n <ng-container *ngIf=\"getMediaSource(field) as source\">\r\n <ng-container [ngSwitch]=\"getMediaKind(field)\">\r\n\r\n <img\r\n *ngSwitchDefault\r\n [src]=\"source\"\r\n [alt]=\"getMediaLabel(field)\"\r\n loading=\"lazy\" />\r\n\r\n <video\r\n *ngSwitchCase=\"'video'\"\r\n [src]=\"source\"\r\n [attr.aria-label]=\"getMediaLabel(field)\"\r\n controls\r\n playsinline\r\n preload=\"metadata\">\r\n Your browser does not support video playback.\r\n </video>\r\n\r\n <audio\r\n *ngSwitchCase=\"'audio'\"\r\n [src]=\"source\"\r\n [attr.aria-label]=\"getMediaLabel(field)\"\r\n controls\r\n preload=\"metadata\">\r\n Your browser does not support audio playback.\r\n </audio>\r\n\r\n <a\r\n *ngSwitchCase=\"'pdf'\"\r\n [href]=\"source\"\r\n target=\"_blank\"\r\n rel=\"noopener noreferrer\">\r\n Open PDF \u2014 {{ getMediaLabel(field) }}\r\n </a>\r\n\r\n <a\r\n *ngSwitchCase=\"'file'\"\r\n [href]=\"source\"\r\n target=\"_blank\"\r\n rel=\"noopener noreferrer\">\r\n Open file \u2014 {{ getMediaLabel(field) }}\r\n </a>\r\n\r\n </ng-container>\r\n </ng-container>\r\n</ng-template>", styles: [":host ::ng-deep .custom-datepicker .p-datepicker-dropdown{height:100%;border-radius:4px}:host ::ng-deep .custom-datepicker .p-datepicker-input{border-radius:4px}::ng-deep .p-autocomplete-list{background-color:#fff}:host ::ng-deep .custom-autocomplete{display:flex;width:100%}:host ::ng-deep .custom-autocomplete .p-autocomplete-input{flex:1;width:100%;min-width:0;border:none!important;outline:none!important;box-shadow:none!important;background:transparent!important}:host ::ng-deep .custom-autocomplete .p-autocomplete-dropdown{height:100%;border-radius:4px}:host ::ng-deep .custom-autocomplete .p-autocomplete-input:focus,:host ::ng-deep .custom-autocomplete .p-autocomplete-input:focus-visible,:host ::ng-deep .custom-autocomplete .p-inputtext:enabled:focus{border:none!important;outline:none!important;box-shadow:none!important}.responsive-modal-grid{width:100%;min-width:0;box-sizing:border-box}@media screen and (max-width:767px){.responsive-modal-grid{grid-template-columns:repeat(12,minmax(0,1fr))!important;gap:10px!important}.responsive-modal-field{grid-column:1 / -1!important;width:100%!important;max-width:none!important;min-width:0!important}.responsive-modal-action:nth-last-child(2){grid-column:1 / span 6!important}.responsive-modal-action:last-child{grid-column:7 / span 6!important}.responsive-modal-action{width:100%!important;max-width:none!important;min-width:0!important;justify-self:stretch!important;box-sizing:border-box!important}.responsive-modal-action button{display:block!important;width:100%!important;max-width:none!important;min-width:0!important;margin:0!important;box-sizing:border-box!important}}:host{--modal-field-focus-color: var(--p-primary-color, #10b981);--modal-field-focus-shadow: 0 0 0 2px rgba(16, 185, 129, .16)}:host ::ng-deep input:not([type=checkbox]):not(:disabled):focus,:host ::ng-deep textarea:not(:disabled):focus{border-color:var(--modal-field-focus-color)!important;outline:none!important;box-shadow:var(--modal-field-focus-shadow)!important}:host ::ng-deep .custom-autocomplete:focus-within{border-color:var(--modal-field-focus-color)!important;outline:none!important;box-shadow:var(--modal-field-focus-shadow)!important}:host ::ng-deep .custom-autocomplete:focus-within .p-autocomplete-input{border:none!important;outline:none!important;box-shadow:none!important}:host ::ng-deep select:not(:disabled):focus{border-color:var(--modal-field-focus-color)!important;outline:none!important;box-shadow:var(--modal-field-focus-shadow)!important}:host ::ng-deep .ant-select-focused:not(.ant-select-disabled) .ant-select-selector,:host ::ng-deep nz-select:not(.ant-select-disabled):focus-within .ant-select-selector{border-color:var(--modal-field-focus-color)!important;outline:none!important;box-shadow:var(--modal-field-focus-shadow)!important}:host ::ng-deep .p-select:not(.p-disabled).p-focus,:host ::ng-deep .p-select:not(.p-disabled):focus-within,:host ::ng-deep .p-dropdown:not(.p-disabled).p-focus,:host ::ng-deep .p-dropdown:not(.p-disabled):focus-within{border-color:var(--modal-field-focus-color)!important;outline:none!important;box-shadow:var(--modal-field-focus-shadow)!important}:host ::ng-deep .custom-datepicker:focus-within .p-datepicker-input{border-color:var(--modal-field-focus-color)!important;outline:none!important;box-shadow:var(--modal-field-focus-shadow)!important}:host ::ng-deep input:disabled,:host ::ng-deep textarea:disabled,:host ::ng-deep select:disabled,:host ::ng-deep .p-disabled,:host ::ng-deep .ant-select-disabled .ant-select-selector{box-shadow:none!important}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i9.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i9.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i9.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: i9.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "directive", type: i9.NgSwitch, selector: "[ngSwitch]", inputs: ["ngSwitch"] }, { kind: "directive", type: i9.NgSwitchCase, selector: "[ngSwitchCase]", inputs: ["ngSwitchCase"] }, { kind: "directive", type: i9.NgSwitchDefault, selector: "[ngSwitchDefault]" }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i2.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i2.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { kind: "directive", type: i2.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { kind: "directive", type: i2.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: i2.NgForm, selector: "form:not([ngNoForm]):not([formGroup]):not([formArray]),ng-form,[ngForm]", inputs: ["ngFormOptions"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "ngmodule", type: NzSelectModule }, { kind: "component", type: i3.NzOptionComponent, selector: "nz-option", inputs: ["nzTitle", "nzLabel", "nzValue", "nzKey", "nzDisabled", "nzHide", "nzCustomContent"], exportAs: ["nzOption"] }, { kind: "component", type: i3.NzSelectComponent, selector: "nz-select", inputs: ["nzId", "nzSize", "nzStatus", "nzVariant", "nzOptionHeightPx", "nzOptionOverflowSize", "nzDropdownClassName", "nzDropdownMatchSelectWidth", "nzDropdownStyle", "nzNotFoundContent", "nzPlaceHolder", "nzPlacement", "nzMaxTagCount", "nzDropdownRender", "nzCustomTemplate", "nzPrefix", "nzSuffixIcon", "nzClearIcon", "nzRemoveIcon", "nzMenuItemSelectedIcon", "nzTokenSeparators", "nzMaxTagPlaceholder", "nzMaxMultipleCount", "nzMode", "nzFilterOption", "compareWith", "nzAllowClear", "nzShowSearch", "nzLoading", "nzAutoFocus", "nzAutoClearSearchValue", "nzServerSearch", "nzDisabled", "nzOpen", "nzSelectOnTab", "nzBackdrop", "nzOptions", "nzShowArrow"], outputs: ["nzOnSearch", "nzScrollToBottom", "nzOpenChange", "nzBlur", "nzFocus", "nzOnClear"], exportAs: ["nzSelect"] }, { kind: "ngmodule", type: NzDatePickerModule }, { kind: "component", type: i4.NzDatePickerComponent, selector: "nz-date-picker,nz-week-picker,nz-month-picker,nz-quarter-picker,nz-year-picker,nz-range-picker", inputs: ["nzInline", "nzAllowClear", "nzAutoFocus", "nzDisabled", "nzInputReadOnly", "nzOpen", "nzDisabledDate", "nzLocale", "nzPlaceHolder", "nzPopupStyle", "nzDropdownClassName", "nzSize", "nzStatus", "nzFormat", "nzVariant", "nzDateRender", "nzDisabledTime", "nzRenderExtraFooter", "nzShowToday", "nzMode", "nzShowNow", "nzRanges", "nzDefaultPickerValue", "nzSeparator", "nzSuffixIcon", "nzBackdrop", "nzId", "nzPlacement", "nzShowWeekNumber", "nzShowTime"], outputs: ["nzOnPanelChange", "nzOnCalendarChange", "nzOnOk", "nzOnOpenChange"], exportAs: ["nzDatePicker"] }, { kind: "directive", type: i4.NzRangePickerComponent, selector: "nz-range-picker", exportAs: ["nzRangePicker"] }, { kind: "ngmodule", type: DatePickerModule }, { kind: "component", type: i12.DatePicker, selector: "p-datePicker, p-datepicker, p-date-picker", inputs: ["iconDisplay", "styleClass", "inputStyle", "inputId", "inputStyleClass", "placeholder", "ariaLabelledBy", "ariaLabel", "iconAriaLabel", "dateFormat", "multipleSeparator", "rangeSeparator", "inline", "showOtherMonths", "selectOtherMonths", "showIcon", "icon", "readonlyInput", "shortYearCutoff", "hourFormat", "timeOnly", "stepHour", "stepMinute", "stepSecond", "showSeconds", "showOnFocus", "showWeek", "startWeekFromFirstDayOfYear", "showClear", "dataType", "selectionMode", "maxDateCount", "showButtonBar", "todayButtonStyleClass", "clearButtonStyleClass", "autofocus", "autoZIndex", "baseZIndex", "panelStyleClass", "panelStyle", "keepInvalid", "hideOnDateTimeSelect", "touchUI", "timeSeparator", "focusTrap", "showTransitionOptions", "hideTransitionOptions", "tabindex", "minDate", "maxDate", "disabledDates", "disabledDays", "showTime", "responsiveOptions", "numberOfMonths", "firstDayOfWeek", "view", "defaultDate", "appendTo", "motionOptions"], outputs: ["onFocus", "onBlur", "onClose", "onSelect", "onClear", "onInput", "onTodayClick", "onClearClick", "onMonthChange", "onYearChange", "onClickOutside", "onShow"] }, { kind: "ngmodule", type: AutoCompleteModule }, { kind: "component", type: i18.AutoComplete, selector: "p-autoComplete, p-autocomplete, p-auto-complete", inputs: ["minLength", "minQueryLength", "delay", "panelStyle", "styleClass", "panelStyleClass", "inputStyle", "inputId", "inputStyleClass", "placeholder", "readonly", "scrollHeight", "lazy", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "autoHighlight", "forceSelection", "type", "autoZIndex", "baseZIndex", "ariaLabel", "dropdownAriaLabel", "ariaLabelledBy", "dropdownIcon", "unique", "group", "completeOnFocus", "showClear", "dropdown", "showEmptyMessage", "dropdownMode", "multiple", "addOnTab", "tabindex", "dataKey", "emptyMessage", "showTransitionOptions", "hideTransitionOptions", "autofocus", "autocomplete", "optionGroupChildren", "optionGroupLabel", "overlayOptions", "suggestions", "optionLabel", "optionValue", "id", "searchMessage", "emptySelectionMessage", "selectionMessage", "autoOptionFocus", "selectOnFocus", "searchLocale", "optionDisabled", "focusOnHover", "typeahead", "addOnBlur", "separator", "appendTo", "motionOptions"], outputs: ["completeMethod", "onSelect", "onUnselect", "onAdd", "onFocus", "onBlur", "onDropdownClick", "onClear", "onInputKeydown", "onKeyUp", "onShow", "onHide", "onLazyLoad"] }, { kind: "ngmodule", type: InputTextModule }, { kind: "component", type: Label, selector: "vl-label", inputs: ["formField", "modalItemInfo"] }, { kind: "component", type: String$1, selector: "vl-string", inputs: ["formField", "modalItemInfo"] }, { kind: "component", type: Textbox, selector: "vl-textbox", inputs: ["formField", "modalItemInfo"] }, { kind: "directive", type: CustomKeyboardDirective, selector: "[vlCustomKeyboard]", inputs: ["vlCustomKeyboard"] }, { kind: "pipe", type: PlaceholderPipe, name: "vlPlaceholder" }, { kind: "pipe", type: i9.CurrencyPipe, name: "currency" }] });
6157
6460
  }
6158
6461
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.2", ngImport: i0, type: ModelComponent, decorators: [{
6159
6462
  type: Component,
@@ -6169,7 +6472,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.2", ngImpor
6169
6472
  String$1,
6170
6473
  Textbox,
6171
6474
  CustomKeyboardDirective,
6172
- ], template: "<!-- Faramarz Yousefian and Agent Toni (Claude Opus 5.5) 2026-10-13\r\n - fix: the placeholder comes from vlPlaceholder (pipes/placeholder.pipe.ts) - empty where the\r\n project defines none; it showed the text \"undefined\" -->\r\n<!-- Faramarz Yousefian and Agent Toni (Claude Opus 5) 2026-10-07\r\n - change: number, autocomplete, date and time fields take the toolkit keyboard of their\r\n attribute type (keyboardTypeFor) instead of only an explicit option.keyboardType\r\n - change: the date picker docks at the bottom on the devices (model-datepicker-panel--docked);\r\n the time picker stays attached to its field in a compact form (model-timepicker-panel);\r\n both report which picker closed (onPickerClose(picker)) -->\r\n\r\n<!-- Shuaib 2026-09-24\r\n - change: the model field switch uses renderFieldType so legacy checkbox fields render as boolean. -->\r\n\r\n<!-- Faramarz Yousefian and Agent Toni (Claude Opus 5) 2026-09-19\r\n - new: a @contract comment on the widest type coverage in the toolkit, and one on the credit\r\n card case recording that the rename reached this file first -->\r\n<!-- Loader Spinner -->\r\n<div *ngIf=\"isLoading\" class=\"loader-overlay\">\r\n <div class=\"spinner\"></div>\r\n</div>\r\n<div [style]=\"getStyleWithoutClasses(modalItemInfo?.layoutSchema?.style).style\"\r\n [class]=\"modalItemInfo?.layoutSchema?.style?.classes[0]\">\r\n <form #dynamicForm=\"ngForm\"\r\n *ngIf=\"modalItemInfo?.layoutSchema?.formSections?.length > 0\"\r\n (submit)=\"$event.preventDefault()\">\r\n <div\r\n *ngFor=\"let formSection of modalItemInfo?.layoutSchema?.formSections\">\r\n <div *ngIf=\"formSection?.label?.caption\"\r\n [class]=\"formSection?.label?.style?.classes[0]\"\r\n [style]=\"getStyleWithoutClasses(formSection?.label?.style).style\">\r\n {{formSection.label.caption}}\r\n </div>\r\n <div *ngIf=\"formSection?.formFields?.length > 0\"\r\n [class]=\"formSection?.style?.classes?.[0] || ''\"\r\n [ngStyle]=\"getSectionBodyStyle(formSection)\">\r\n <div *ngFor=\"let formField of formSection.formFields\"\r\n [ngStyle]=\"getFieldWrapperStyle(formField)\"\r\n [class]=\"formField?.style?.classes || ''\">\r\n\r\n <!-- @contract decision: the widest type coverage in the toolkit\r\n reality: every field type except the grid-only quantity renders here.\r\n When another container drops a type, this is the way out.\r\n seen: measured 2026-09-19. Note the file is model.component.html while\r\n the container is called modal in layout files - that costs a\r\n search every time -->\r\n <!-- @contract compatibility: checkbox is rendered as boolean for existing projects. -->\r\n <div [ngSwitch]=\"renderFieldType(\r\n formField?.scope?.reference &&\r\n modalItemInfo?.propertySchema?.[\r\n getScope(formField.scope.reference)\r\n ]\r\n ? modalItemInfo.propertySchema[\r\n getScope(formField.scope.reference)\r\n ]?.[\r\n formField.scope.reference.split('/').pop()\r\n ]?.type\r\n : 'default'\r\n )\">\r\n <!-- image control -->\r\n <div *ngSwitchCase=\"'image'\"\r\n [style]=\"getStyleWithoutClasses(formField?.style).style\"\r\n [class]=\"formField.style?.classes ? formField.style?.classes[0]: ''\">\r\n <img [src]=\"formField.option.src\" [alt]=\"'img'\" />\r\n </div>\r\n\r\n <!-- credit card control -->\r\n <!-- @contract decision: the credit card type is spelled creditCard\r\n reality: this file was renamed on 2026-09-15, form.component.html and\r\n utility.service.ts followed on 2026-09-19. carditCard is read\r\n nowhere any more.\r\n failure: a data object still declaring carditCard renders empty. -->\r\n <div *ngSwitchCase=\"'creditCard'\"\r\n [style]=\"getStyleWithoutClasses(formField?.style).style\"\r\n [class]=\"formField.style?.classes[0]\">\r\n <div id=\"card-element\">\r\n <!-- a Stripe element will be inserted here -->\r\n </div>\r\n <!-- Used to display form errors -->\r\n <div id=\"card-errors\"\r\n class=\"displayError.textContent!=='': 'alert alert-danger mt-1'\">\r\n </div>\r\n </div>\r\n\r\n <!-- string control -->\r\n <div *ngSwitchCase=\"'string'\" class=\"form-group mb-3\">\r\n @if(formField.option && formField.option.control &&\r\n !formField.option.protected){\r\n @switch (formField.option.control) {\r\n @case ('textInput') {\r\n <div\r\n [ngStyle]=\"getFieldInnerLayoutStyle(formField)\">\r\n <vl-label [formField]=\"formField\"\r\n [modalItemInfo]=\"modalItemInfo\">\r\n </vl-label>\r\n <vl-textbox [formField]=\"formField\"\r\n [modalItemInfo]=\"modalItemInfo\">\r\n </vl-textbox>\r\n </div>\r\n <!-- Error Message -->\r\n <!-- <div *ngIf=\"inputField?.touched && inputField?.invalid\"\r\n [style]=\"getStyleWithoutClasses(formField?.validation?.style).style\">\r\n <p class=\"text-danger\" *ngIf=\"inputField?.errors?.['required']\">\r\n {{setErroMessage(formField, errorMessages, \"required\")}}</p>\r\n <p class=\"text-danger\" *ngIf=\"inputField?.errors?.['email']\">\r\n {{(formField.label?.value ?\r\n formField.label?.value :\r\n modalItemInfo.propertySchema[getScope(formField.scope?.reference)][formField.scope?.reference.split('/').pop()]?.caption)\r\n +\r\n ' ' + errorMessages.pattern}}</p>\r\n </div> -->\r\n }\r\n\r\n @case ('password') {\r\n <span>Switch not supported yet</span>\r\n\r\n }\r\n @case ('combobox') {\r\n <span>Combobox not supported yet</span>\r\n }\r\n @case('textArea'){\r\n <span>TextArea not supported yet</span>\r\n }\r\n @case ('switch') {\r\n <span>Switch not supported yet</span>\r\n }\r\n\r\n @case('radiobutton') {\r\n <span>Radiobutton not supported yet</span>\r\n }\r\n\r\n @case ('dropdown') {\r\n <span *ngIf=\"formField.option?.postfixCaption\">\r\n <select id=\"dynamic-dropdown\"\r\n [class]=\"formField.style?.classes ? formField.style?.classes[0]: ''\"\r\n #dropdownField=\"ngModel\"\r\n [style]=\"getStyleWithoutClasses(formField?.style).style\"\r\n [name]=\"formField.scope?.reference\"\r\n [(ngModel)]=\"modalItemInfo.propertySchema[getScope(formField.scope?.reference)][formField.scope?.reference.split('/').pop()].value\">\r\n <option\r\n *ngFor=\"let item of modalItemInfo.propertySchema[getScope(formField.scope?.reference)][formField.scope?.reference.split('/').pop()]?.data\"\r\n [value]=\"formField?.option?.optionValue ? formField.option.optionValue : 'value'\">\r\n {{ formField?.option?.optionLabel ?\r\n formField.option.optionLabel :\r\n 'label'}}</option>\r\n </select>\r\n <label\r\n [style]=\"getStyleWithoutClasses(formField?.label?.style).style\">{{modalItemInfo.propertySchema[getScope(formField.scope)][formField.scope?.reference.split('/').pop()]?.caption\r\n }}</label>\r\n </span>\r\n <div *ngIf=\"!formField.option?.postfixCaption\">\r\n <div\r\n [ngStyle]=\"getFieldInnerLayoutStyle(formField)\">\r\n <label\r\n [style]=\"getStyleWithoutClasses(formField?.label?.style).style\">{{modalItemInfo.propertySchema[getScope(formField.scope?.reference)][formField.scope?.reference.split('/').pop()]?.caption\r\n }}</label>\r\n\r\n <nz-select nzShowSearch nzAllowClear\r\n nzPlaceHolder=\"Select\"\r\n #dropdownField=\"ngModel\"\r\n [required]=\"formField.option.required\"\r\n [class]=\"formField.style?.classes ? formField.style?.classes[0]: ''\"\r\n [style]=\"getStyleWithoutClasses(formField?.style).style\"\r\n [name]=\"formField.scope?.reference\"\r\n [(ngModel)]=\"modalItemInfo.propertySchema[getScope(formField.scope?.reference)][formField.scope?.reference.split('/').pop()].value\">\r\n <nz-option\r\n *ngFor=\"let item of modalItemInfo.propertySchema[getScope(formField.scope?.reference)][formField.scope?.reference.split('/').pop()]?.data\"\r\n [nzLabel]=\"item[formField?.option?.optionLabel ? formField.option.optionLabel : 'label']\"\r\n [nzValue]=\"item[formField?.option?.optionValue ? formField.option.optionValue : 'value']\"></nz-option>\r\n </nz-select>\r\n </div>\r\n <!-- Error Message -->\r\n <div\r\n *ngIf=\"dropdownField?.touched && dropdownField?.invalid\"\r\n [style]=\"getStyleWithoutClasses(formField?.validation?.style).style\">\r\n <p class=\"text-danger\"\r\n *ngIf=\"dropdownField?.errors?.['required']\">\r\n {{formField.label?.value ?\r\n formField.label?.value :\r\n modalItemInfo.propertySchema[getScope(formField.scope?.reference)][formField.scope?.reference.split('/').pop()]?.caption\r\n +\r\n ' ' + errorMessages.required}}</p>\r\n <p class=\"text-danger\"\r\n *ngIf=\"dropdownField?.errors?.['email']\">\r\n {{(formField.label?.value ?\r\n formField.label?.value :\r\n modalItemInfo.propertySchema[getScope(formField.scope?.reference)][formField.scope?.reference.split('/').pop()]?.caption)\r\n +\r\n ' ' + errorMessages.pattern}}</p>\r\n </div>\r\n </div>\r\n }\r\n\r\n @case ('autocomplete') {\r\n <div\r\n [ngStyle]=\"getFieldInnerLayoutStyle(formField)\">\r\n <vl-label [formField]=\"formField\"\r\n [modalItemInfo]=\"modalItemInfo\">\r\n </vl-label>\r\n\r\n <span>\r\n <p-autocomplete\r\n #autocompleteField=\"ngModel\"\r\n [required]=\"formField.option.required\"\r\n [name]=\"formField.scope?.reference\"\r\n styleClass=\"custom-autocomplete\"\r\n [(ngModel)]=\"modalItemInfo.propertySchema[getScope(formField.scope?.reference)][formField.scope?.reference.split('/').pop()].value\"\r\n [style]=\"getStyleWithoutClasses(formField?.scope?.style).style\"\r\n [class]=\"formField?.scope?.style?.classes ? formField?.scope?.style?.classes[0] : ''\"\r\n [suggestions]=\"matchData\"\r\n [dropdown]=\"true\"\r\n [optionLabel]=\"formField?.option?.autocomplete?.response?.label ? formField.option.autocomplete.response.label : 'label'\"\r\n [placeholder]=\"modalItemInfo.propertySchema | vlPlaceholder: formField.scope?.reference\"\r\n (completeMethod)=\"autocompChangeEvent($event, formField)\"\r\n (ngModelChange)=\"autocompFocusOutEvent($event, formField)\"\r\n [vlCustomKeyboard]=\"keyboardTypeFor(formField)\">\r\n </p-autocomplete>\r\n <!-- Error Message -->\r\n <div\r\n *ngIf=\"autocompleteField?.touched && autocompleteField?.invalid\"\r\n [style]=\"getStyleWithoutClasses(formField?.validation?.style).style\">\r\n <p class=\"text-danger\"\r\n *ngIf=\"autocompleteField?.errors?.['required']\">\r\n {{setErroMessage(formField,\r\n errorMessages, \"required\")}}</p>\r\n <p class=\"text-danger\"\r\n *ngIf=\"autocompleteField?.errors?.['email']\">\r\n {{(formField.label?.value ?\r\n formField.label?.value :\r\n modalItemInfo.propertySchema[getScope(formField.scope?.reference)][formField.scope?.reference.split('/').pop()]?.caption)\r\n +\r\n ' ' +\r\n errorMessages.pattern}}</p>\r\n </div>\r\n </span>\r\n </div>\r\n }\r\n }\r\n }@else{\r\n <div *ngIf=\"!formField.option.protected\">\r\n <div\r\n [ngStyle]=\"getFieldInnerLayoutStyle(formField)\">\r\n <vl-label [formField]=\"formField\"\r\n [modalItemInfo]=\"modalItemInfo\">\r\n </vl-label>\r\n <vl-textbox [formField]=\"formField\"\r\n [modalItemInfo]=\"modalItemInfo\">\r\n </vl-textbox>\r\n </div>\r\n <!-- Error Message -->\r\n <!-- <div *ngIf=\"inputField?.touched && inputField?.invalid\"\r\n [style]=\"getStyleWithoutClasses(formField?.validation?.style).style\">\r\n <p class=\"text-danger\" *ngIf=\"inputField?.errors?.['required']\">\r\n {{setErroMessage(formField, errorMessages, \"required\")}}</p>\r\n <p class=\"text-danger\" *ngIf=\"inputField?.errors?.['email']\">\r\n {{(formField.label?.value ?\r\n formField.label?.value :\r\n modalItemInfo.propertySchema[getScope(formField.scope?.reference)][formField.scope?.reference.split('/').pop()]?.caption)\r\n +\r\n ' ' + errorMessages.pattern}}</p>\r\n </div> -->\r\n </div>\r\n }\r\n <span *ngIf=\"formField.option.protected\"\r\n [style]=\"getStyleWithoutClasses(formField?.label?.style).style\"\r\n [class]=\"formField?.label?.style.classes ? formField?.label?.style?.classes[0] : ''\">\r\n <vl-string [formField]=\"formField\"\r\n [modalItemInfo]=\"modalItemInfo\">\r\n </vl-string>\r\n </span>\r\n\r\n </div>\r\n\r\n <!-- number control -->\r\n <div *ngSwitchCase=\"'number'\" class=\"form-group mb-3\">\r\n <span *ngIf=\"formField.option.protected\"\r\n [style]=\"getStyleWithoutClasses(formField?.label?.style).style\"\r\n [class]=\"formField?.label?.style.classes ? formField?.label?.style?.classes[0] : ''\">\r\n <h5>{{\r\n modalItemInfo.propertySchema[getScope(formField.scope?.reference)][formField.scope?.reference.split('/').pop()]?.caption\r\n }} {{\r\n modalItemInfo.propertySchema[getScope(formField.scope?.reference)][formField.scope?.reference.split('/').pop()]?.value\r\n |\r\n currency:formField.option.currency :true:\r\n formField.option?.decimalPoint}}\r\n </h5>\r\n </span>\r\n <span *ngIf=\"!formField.option.protected\">\r\n <div\r\n [ngStyle]=\"getFieldInnerLayoutStyle(formField)\">\r\n <label\r\n [style]=\"getStyleWithoutClasses(formField?.label?.style).style\"\r\n [class]=\"formField?.label?.style.classes ? formField?.label?.style?.classes[0] : ''\">{{\r\n formField.label?.value\r\n ?\r\n formField.label?.value :\r\n modalItemInfo.propertySchema[getScope(formField.scope?.reference)][formField.scope?.reference.split('/').pop()]?.caption\r\n }}</label>\r\n <input type=\"number\"\r\n [class]=\"formField.style?.classes ? formField.style?.classes[0]: ''\"\r\n [vlCustomKeyboard]=\"keyboardTypeFor(formField)\"\r\n [style]=\"getStyleWithoutClasses(formField?.style).style\"\r\n [(ngModel)]=\"modalItemInfo.propertySchema[getScope(formField.scope?.reference)][formField.scope?.reference.split('/').pop()].value\"\r\n [name]=\"formField.scope?.reference\"\r\n [placeholder]=\"modalItemInfo.propertySchema | vlPlaceholder: formField.scope?.reference\" />\r\n </div>\r\n </span>\r\n </div>\r\n\r\n <!-- DateRange control -->\r\n <div *ngSwitchCase=\"'dateRange'\"\r\n class=\"form-group mb-3\">\r\n <span *ngIf=\"formField.option.protected\"\r\n [style]=\"getStyleWithoutClasses(formField?.label?.style).style\"\r\n [class]=\"formField?.label?.style.classes ? formField?.label?.style?.classes[0] : ''\">\r\n <vl-string [formField]=\"formField\"\r\n [modalItemInfo]=\"modalItemInfo\">\r\n </vl-string>\r\n </span>\r\n <div *ngIf=\"!formField.option.protected\">\r\n <div\r\n [ngStyle]=\"getFieldInnerLayoutStyle(formField)\">\r\n <label\r\n [style]=\"getStyleWithoutClasses(formField?.label?.style).style\"\r\n [class]=\"formField?.label?.style.classes ? formField?.label?.style?.classes[0] : ''\">{{\r\n formField.label?.value\r\n ?\r\n formField.label?.value :\r\n modalItemInfo.propertySchema[getScope(formField.scope?.reference)][formField.scope?.reference.split('/').pop()]?.caption\r\n }}</label>\r\n <nz-range-picker #dateRangeField=\"ngModel\"\r\n [required]=\"formField.option.required\"\r\n [name]=\"formField.scope?.reference\"\r\n [style]=\"getStyleWithoutClasses(formField?.style).style\"\r\n [(ngModel)]=\"modalItemInfo.propertySchema[getScope(formField.scope?.reference)][formField.scope?.reference.split('/').pop()].value\"></nz-range-picker>\r\n </div>\r\n <!-- Error Message -->\r\n <div\r\n *ngIf=\"dateRangeField?.touched && dateRangeField?.invalid\"\r\n [style]=\"getStyleWithoutClasses(formField?.validation?.style).style\">\r\n <p class=\"text-danger\"\r\n *ngIf=\"dateRangeField?.errors?.['required']\">\r\n {{formField.label?.value ?\r\n formField.label?.value :\r\n modalItemInfo.propertySchema[getScope(formField.scope?.reference)][formField.scope?.reference.split('/').pop()]?.caption\r\n +\r\n ' ' + errorMessages.required}}</p>\r\n <p class=\"text-danger\"\r\n *ngIf=\"dateRangeField?.errors?.['email']\">\r\n {{(formField.label?.value ?\r\n formField.label?.value :\r\n modalItemInfo.propertySchema[getScope(formField.scope?.reference)][formField.scope?.reference.split('/').pop()]?.caption)\r\n +\r\n ' ' + errorMessages.pattern}}</p>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- Date control -->\r\n <div *ngSwitchCase=\"'date'\" class=\"form-group mb-3\">\r\n <span\r\n *ngIf=\"formField.option.protected\"\r\n [style]=\"getStyleWithoutClasses(formField?.label?.style).style\"\r\n [class]=\"formField?.label?.style.classes ? formField?.label?.style?.classes[0] : ''\">\r\n <vl-string\r\n [formField]=\"formField\"\r\n [modalItemInfo]=\"modalItemInfo\">\r\n </vl-string>\r\n </span>\r\n\r\n <div *ngIf=\"!formField.option.protected\">\r\n <div\r\n [ngStyle]=\"getFieldInnerLayoutStyle(formField)\">\r\n <label\r\n [style]=\"getStyleWithoutClasses(formField?.label?.style).style\"\r\n [class]=\"formField?.label?.style.classes ? formField?.label?.style?.classes[0] : ''\">\r\n {{ getLabel(formField) }}\r\n </label>\r\n\r\n <span>\r\n <div class=\"picker-field\">\r\n <p-datepicker\r\n #datePicker\r\n #dateField=\"ngModel\"\r\n styleClass=\"custom-datepicker\"\r\n [required]=\"formField.option.required\"\r\n [name]=\"formField.scope?.reference\"\r\n [disabled]=\"formField?.option?.disabled\"\r\n [showIcon]=\"false\"\r\n [showOnFocus]=\"false\"\r\n appendTo=\"body\"\r\n [autoZIndex]=\"true\"\r\n [baseZIndex]=\"10000\"\r\n [panelStyleClass]=\"picker.datePanelClass\"\r\n [motionOptions]=\"picker.dockedMotion\"\r\n [vlCustomKeyboard]=\"keyboardTypeFor(formField)\"\r\n (pointerdown)=\"picker.onFieldPointerDown($event, datePicker)\"\r\n (onFocus)=\"picker.onFieldFocus($event)\"\r\n (onShow)=\"picker.onShown()\"\r\n (onClose)=\"picker.onClose(datePicker)\"\r\n (ngModelChange)=\"dateChangeEvent(formField, $event)\"\r\n (onInput)=\"onDateTyping($event)\"\r\n [dateFormat]=\"\r\n modalItemInfo.propertySchema[\r\n getScope(formField.scope?.reference)\r\n ][\r\n formField.scope?.reference.split('/').pop()\r\n ]?.format || 'yy-mm-dd'\r\n \"\r\n [(ngModel)]=\"\r\n modalItemInfo.propertySchema[\r\n getScope(formField.scope?.reference)\r\n ][\r\n formField.scope?.reference.split('/').pop()\r\n ].value\r\n \"\r\n [class]=\"formField?.scope?.style?.classes?.[0] || ''\"\r\n [style]=\"getStyleWithoutClasses(formField?.scope?.style).style\">\r\n </p-datepicker>\r\n\r\n <button\r\n type=\"button\"\r\n class=\"picker-field__icon\"\r\n aria-label=\"Open calendar\"\r\n [disabled]=\"formField?.option?.disabled\"\r\n (pointerdown)=\"picker.openFromIcon($event, datePicker)\"\r\n (click)=\"picker.blockIconClick($event)\">\r\n <i class=\"pi pi-calendar\"></i>\r\n </button>\r\n </div>\r\n\r\n <div\r\n *ngIf=\"dateField?.touched && dateField?.invalid\"\r\n [style]=\"getStyleWithoutClasses(formField?.validation?.style).style\">\r\n <p class=\"text-danger\"\r\n *ngIf=\"dateField?.errors?.['required']\">\r\n {{ setErroMessage(formField,\r\n errorMessages, 'required') }}\r\n </p>\r\n <p class=\"text-danger\"\r\n *ngIf=\"dateField?.errors?.['email']\">\r\n {{\r\n (formField.label?.value\r\n ? formField.label?.value\r\n : modalItemInfo.propertySchema[\r\n getScope(formField.scope?.reference)\r\n ][\r\n formField.scope?.reference.split('/').pop()\r\n ]?.caption)\r\n + ' ' + errorMessages.pattern\r\n }}\r\n </p>\r\n </div>\r\n </span>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- Time control -->\r\n <div *ngSwitchCase=\"'time'\" class=\"form-group mb-3\">\r\n <span\r\n *ngIf=\"formField.option.protected\"\r\n [style]=\"getStyleWithoutClasses(formField?.label?.style).style\"\r\n [class]=\"formField?.label?.style.classes ? formField?.label?.style?.classes[0] : ''\">\r\n <vl-string\r\n [formField]=\"formField\"\r\n [modalItemInfo]=\"modalItemInfo\">\r\n </vl-string>\r\n </span>\r\n\r\n <div *ngIf=\"!formField.option.protected\">\r\n <div\r\n [ngStyle]=\"getFieldInnerLayoutStyle(formField)\">\r\n <label\r\n [style]=\"getStyleWithoutClasses(formField?.label?.style).style\"\r\n [class]=\"formField?.label?.style.classes ? formField?.label?.style?.classes[0] : ''\">\r\n {{ getLabel(formField) }}\r\n </label>\r\n\r\n <span>\r\n <div class=\"picker-field\">\r\n <p-datepicker\r\n #timePicker\r\n #timeField=\"ngModel\"\r\n styleClass=\"custom-datepicker\"\r\n [required]=\"formField.option.required\"\r\n [name]=\"formField.scope?.reference\"\r\n [timeOnly]=\"true\"\r\n hourFormat=\"24\"\r\n [disabled]=\"formField?.option?.disabled\"\r\n [showIcon]=\"false\"\r\n [showOnFocus]=\"false\"\r\n appendTo=\"body\"\r\n [autoZIndex]=\"true\"\r\n [baseZIndex]=\"10000\"\r\n [panelStyleClass]=\"picker.timePanelClass\"\r\n [vlCustomKeyboard]=\"keyboardTypeFor(formField)\"\r\n (pointerdown)=\"picker.onFieldPointerDown($event, timePicker)\"\r\n (onFocus)=\"picker.onFieldFocus($event)\"\r\n (onShow)=\"onTimePanelShow(formField)\"\r\n (onClose)=\"picker.onClose(timePicker)\"\r\n (onInput)=\"onTimeTyping($event)\"\r\n (ngModelChange)=\"timeChangeEvent(formField, $event)\"\r\n [style]=\"getStyleWithoutClasses(formField?.scope?.style).style\"\r\n [(ngModel)]=\"\r\n modalItemInfo.propertySchema[\r\n getScope(formField.scope?.reference)\r\n ][\r\n formField.scope?.reference.split('/').pop()\r\n ].value\r\n \"\r\n [class]=\"formField?.scope?.style?.classes?.[0] || ''\">\r\n </p-datepicker>\r\n\r\n <button\r\n type=\"button\"\r\n class=\"picker-field__icon\"\r\n aria-label=\"Open time picker\"\r\n [disabled]=\"formField?.option?.disabled\"\r\n (pointerdown)=\"picker.openFromIcon($event, timePicker)\"\r\n (click)=\"picker.blockIconClick($event)\">\r\n <i class=\"pi pi-clock\"></i>\r\n </button>\r\n </div>\r\n\r\n <div\r\n *ngIf=\"timeField?.touched && timeField?.invalid\"\r\n [style]=\"getStyleWithoutClasses(formField?.validation?.style).style\">\r\n <p class=\"text-danger\"\r\n *ngIf=\"timeField?.errors?.['required']\">\r\n {{ setErroMessage(formField,\r\n errorMessages, 'required') }}\r\n </p>\r\n <p class=\"text-danger\"\r\n *ngIf=\"timeField?.errors?.['email']\">\r\n {{\r\n (formField.label?.value\r\n ? formField.label?.value\r\n : modalItemInfo.propertySchema[\r\n getScope(formField.scope?.reference)\r\n ][\r\n formField.scope?.reference.split('/').pop()\r\n ]?.caption)\r\n + ' ' + errorMessages.pattern\r\n }}\r\n </p>\r\n </div>\r\n </span>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- Autocomplete control -->\r\n <div *ngSwitchCase=\"'autocomplete'\"\r\n class=\"form-group mb-3\">\r\n <span *ngIf=\"formField.option.protected\"\r\n [style]=\"getStyleWithoutClasses(formField?.label?.style).style\"\r\n [class]=\"formField?.label?.style.classes ? formField?.label?.style?.classes[0] : ''\">\r\n <vl-string [formField]=\"formField\"\r\n [modalItemInfo]=\"modalItemInfo\">\r\n </vl-string>\r\n </span>\r\n <div *ngIf=\"!formField.option.protected\">\r\n <div\r\n [ngStyle]=\"getFieldInnerLayoutStyle(formField)\">\r\n <vl-label [formField]=\"formField\"\r\n [modalItemInfo]=\"modalItemInfo\">\r\n </vl-label>\r\n\r\n <span>\r\n <p-autocomplete\r\n #autocompleteField=\"ngModel\"\r\n [required]=\"formField.option.required\"\r\n [name]=\"formField.scope?.reference\"\r\n styleClass=\"custom-autocomplete\"\r\n [(ngModel)]=\"modalItemInfo.propertySchema[getScope(formField.scope?.reference)][formField.scope?.reference.split('/').pop()].value\"\r\n [style]=\"getStyleWithoutClasses(formField?.scope?.style).style\"\r\n [class]=\"formField?.scope?.style?.classes ? formField?.scope?.style?.classes[0] : ''\"\r\n [suggestions]=\"matchData\"\r\n [dropdown]=\"true\"\r\n [optionLabel]=\"formField?.option?.autocomplete?.response?.label ? formField.option.autocomplete.response.label : 'label'\"\r\n [placeholder]=\"modalItemInfo.propertySchema | vlPlaceholder: formField.scope?.reference\"\r\n (completeMethod)=\"autocompChangeEvent($event, formField)\"\r\n (ngModelChange)=\"autocompFocusOutEvent($event, formField)\"\r\n [vlCustomKeyboard]=\"keyboardTypeFor(formField)\">\r\n </p-autocomplete>\r\n <!-- Error Message -->\r\n <div\r\n *ngIf=\"autocompleteField?.touched && autocompleteField?.invalid\"\r\n [style]=\"getStyleWithoutClasses(formField?.validation?.style).style\">\r\n <p class=\"text-danger\"\r\n *ngIf=\"autocompleteField?.errors?.['required']\">\r\n {{setErroMessage(formField,\r\n errorMessages, \"required\")}}</p>\r\n <p class=\"text-danger\"\r\n *ngIf=\"autocompleteField?.errors?.['email']\">\r\n {{(formField.label?.value ?\r\n formField.label?.value :\r\n modalItemInfo.propertySchema[getScope(formField.scope?.reference)][formField.scope?.reference.split('/').pop()]?.caption)\r\n +\r\n ' ' +\r\n errorMessages.pattern}}</p>\r\n </div>\r\n </span>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- checkBox control -->\r\n <div *ngSwitchCase=\"'boolean'\" class=\"form-group mb-3\"\r\n [style]=\"getStyleWithoutClasses(formField?.style).style\"\r\n [class]=\"formField.style?.classes ? formField.style?.classes[0] : ''\">\r\n <span *ngIf=\"formField.option?.postfixCaption\">\r\n <label class=\"form-check-label\"><input\r\n type=\"checkbox\" class=\"form-check-input\"\r\n [(ngModel)]=\"modalItemInfo.propertySchema[getScope(formField.scope?.reference)][formField.scope?.reference.split('/').pop()].value\"\r\n [name]=\"formField.scope?.reference\"\r\n (ngModelChange)=\"invokeSetformData()\" />{{\r\n modalItemInfo.propertySchema[getScope(formField.scope?.reference)][formField.scope?.reference.split('/').pop()]?.caption\r\n }}</label>\r\n </span>\r\n <div *ngIf=\"!formField.option?.postfixCaption\"\r\n [class]=\"formField?.layout == 'horizontal' ? 'horizontal-layout' : 'row'\">\r\n <label class=\"form-check-label\">{{\r\n modalItemInfo.propertySchema[getScope(formField.scope?.reference)][formField.scope?.reference.split('/').pop()]?.caption\r\n }}\r\n <input type=\"checkbox\"\r\n class=\"form-check-input\"\r\n [(ngModel)]=\"modalItemInfo.propertySchema[getScope(formField.scope?.reference)][formField.scope?.reference.split('/').pop()].value\"\r\n [name]=\"formField.scope?.reference\" /></label>\r\n </div>\r\n </div>\r\n\r\n <!-- dropdown control -->\r\n <div *ngSwitchCase=\"'dropdown'\" class=\"form-group mb-3\"\r\n [style]=\"getStyleWithoutClasses(formField?.style).style\"\r\n [class]=\"formField.style?.classes ? formField.style?.classes[0] : ''\">\r\n <span *ngIf=\"formField.option?.postfixCaption\">\r\n <select id=\"dynamic-dropdown\"\r\n [class]=\"formField.style?.classes ? formField.style?.classes[0]: ''\"\r\n #dropdownField=\"ngModel\"\r\n [style]=\"getStyleWithoutClasses(formField?.style).style\"\r\n [name]=\"formField.scope?.reference\"\r\n [(ngModel)]=\"modalItemInfo.propertySchema[getScope(formField.scope?.reference)][formField.scope?.reference.split('/').pop()].value\">\r\n <option\r\n *ngFor=\"let item of modalItemInfo.propertySchema[getScope(formField.scope?.reference)][formField.scope?.reference.split('/').pop()]?.data\"\r\n [value]=\"formField?.option?.optionValue ? formField.option.optionValue : 'value'\">\r\n {{ formField?.option?.optionLabel ?\r\n formField.option.optionLabel :\r\n 'label'}}</option>\r\n </select>\r\n <label\r\n [style]=\"getStyleWithoutClasses(formField?.label?.style).style\">{{modalItemInfo.propertySchema[getScope(formField.scope)][formField.scope?.reference.split('/').pop()]?.caption\r\n }}</label>\r\n </span>\r\n <div *ngIf=\"!formField.option?.postfixCaption\">\r\n <div\r\n [ngStyle]=\"getFieldInnerLayoutStyle(formField)\">\r\n <label\r\n [style]=\"getStyleWithoutClasses(formField?.label?.style).style\">{{modalItemInfo.propertySchema[getScope(formField.scope?.reference)][formField.scope?.reference.split('/').pop()]?.caption\r\n }}</label>\r\n\r\n <nz-select nzShowSearch nzAllowClear\r\n nzPlaceHolder=\"Select\"\r\n #dropdownField=\"ngModel\"\r\n [required]=\"formField.option.required\"\r\n [class]=\"formField.style?.classes ? formField.style?.classes[0]: ''\"\r\n [style]=\"getStyleWithoutClasses(formField?.style).style\"\r\n [name]=\"formField.scope?.reference\"\r\n [(ngModel)]=\"modalItemInfo.propertySchema[getScope(formField.scope?.reference)][formField.scope?.reference.split('/').pop()].value\">\r\n <nz-option\r\n *ngFor=\"let item of modalItemInfo.propertySchema[getScope(formField.scope?.reference)][formField.scope?.reference.split('/').pop()]?.data\"\r\n [nzLabel]=\"item[formField?.option?.optionLabel ? formField.option.optionLabel : 'label']\"\r\n [nzValue]=\"item[formField?.option?.optionValue ? formField.option.optionValue : 'value']\"></nz-option>\r\n </nz-select>\r\n </div>\r\n <!-- Error Message -->\r\n <div\r\n *ngIf=\"dropdownField?.touched && dropdownField?.invalid\"\r\n [style]=\"getStyleWithoutClasses(formField?.validation?.style).style\">\r\n <p class=\"text-danger\"\r\n *ngIf=\"dropdownField?.errors?.['required']\">\r\n {{formField.label?.value ?\r\n formField.label?.value :\r\n modalItemInfo.propertySchema[getScope(formField.scope?.reference)][formField.scope?.reference.split('/').pop()]?.caption\r\n +\r\n ' ' + errorMessages.required}}</p>\r\n <p class=\"text-danger\"\r\n *ngIf=\"dropdownField?.errors?.['email']\">\r\n {{(formField.label?.value ?\r\n formField.label?.value :\r\n modalItemInfo.propertySchema[getScope(formField.scope?.reference)][formField.scope?.reference.split('/').pop()]?.caption)\r\n +\r\n ' ' + errorMessages.pattern}}</p>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- button control -->\r\n <div *ngSwitchCase=\"'default'\">\r\n <button type=\"button\"\r\n [ngStyle]=\"getStyleWithoutClasses(formField.style).style\"\r\n (click)=\"invokeFormBtnClick(formField.option, modalItemInfo.propertySchema, dynamicForm)\"\r\n class=\"btn btn-primary btn-block\">\r\n {{ getButtonCaption(formField) }}\r\n </button>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n </form>\r\n</div>\r\n", styles: [":host ::ng-deep .custom-datepicker .p-datepicker-dropdown{height:100%;border-radius:4px}:host ::ng-deep .custom-datepicker .p-datepicker-input{border-radius:4px}::ng-deep .p-autocomplete-list{background-color:#fff}:host ::ng-deep .custom-autocomplete{display:flex;width:100%}:host ::ng-deep .custom-autocomplete .p-autocomplete-input{flex:1;width:100%;min-width:0;border:none!important;outline:none!important;box-shadow:none!important;background:transparent!important}:host ::ng-deep .custom-autocomplete .p-autocomplete-dropdown{height:100%;border-radius:4px}:host ::ng-deep .custom-autocomplete .p-autocomplete-input:focus,:host ::ng-deep .custom-autocomplete .p-autocomplete-input:focus-visible,:host ::ng-deep .custom-autocomplete .p-inputtext:enabled:focus{border:none!important;outline:none!important;box-shadow:none!important}.responsive-modal-grid{width:100%;min-width:0;box-sizing:border-box}@media screen and (max-width:767px){.responsive-modal-grid{grid-template-columns:repeat(12,minmax(0,1fr))!important;gap:10px!important}.responsive-modal-field{grid-column:1 / -1!important;width:100%!important;max-width:none!important;min-width:0!important}.responsive-modal-action:nth-last-child(2){grid-column:1 / span 6!important}.responsive-modal-action:last-child{grid-column:7 / span 6!important}.responsive-modal-action{width:100%!important;max-width:none!important;min-width:0!important;justify-self:stretch!important;box-sizing:border-box!important}.responsive-modal-action button{display:block!important;width:100%!important;max-width:none!important;min-width:0!important;margin:0!important;box-sizing:border-box!important}}:host{--modal-field-focus-color: var(--p-primary-color, #10b981);--modal-field-focus-shadow: 0 0 0 2px rgba(16, 185, 129, .16)}:host ::ng-deep input:not([type=checkbox]):not(:disabled):focus,:host ::ng-deep textarea:not(:disabled):focus{border-color:var(--modal-field-focus-color)!important;outline:none!important;box-shadow:var(--modal-field-focus-shadow)!important}:host ::ng-deep .custom-autocomplete:focus-within{border-color:var(--modal-field-focus-color)!important;outline:none!important;box-shadow:var(--modal-field-focus-shadow)!important}:host ::ng-deep .custom-autocomplete:focus-within .p-autocomplete-input{border:none!important;outline:none!important;box-shadow:none!important}:host ::ng-deep select:not(:disabled):focus{border-color:var(--modal-field-focus-color)!important;outline:none!important;box-shadow:var(--modal-field-focus-shadow)!important}:host ::ng-deep .ant-select-focused:not(.ant-select-disabled) .ant-select-selector,:host ::ng-deep nz-select:not(.ant-select-disabled):focus-within .ant-select-selector{border-color:var(--modal-field-focus-color)!important;outline:none!important;box-shadow:var(--modal-field-focus-shadow)!important}:host ::ng-deep .p-select:not(.p-disabled).p-focus,:host ::ng-deep .p-select:not(.p-disabled):focus-within,:host ::ng-deep .p-dropdown:not(.p-disabled).p-focus,:host ::ng-deep .p-dropdown:not(.p-disabled):focus-within{border-color:var(--modal-field-focus-color)!important;outline:none!important;box-shadow:var(--modal-field-focus-shadow)!important}:host ::ng-deep .custom-datepicker:focus-within .p-datepicker-input{border-color:var(--modal-field-focus-color)!important;outline:none!important;box-shadow:var(--modal-field-focus-shadow)!important}:host ::ng-deep input:disabled,:host ::ng-deep textarea:disabled,:host ::ng-deep select:disabled,:host ::ng-deep .p-disabled,:host ::ng-deep .ant-select-disabled .ant-select-selector{box-shadow:none!important}\n"] }]
6475
+ ], template: "<!-- Faramarz Yousefian and Agent Toni (Claude Opus 5.5) 2026-10-13\r\n - fix: the placeholder comes from vlPlaceholder (pipes/placeholder.pipe.ts) - empty where the\r\n project defines none; it showed the text \"undefined\" -->\r\n<!-- Faramarz Yousefian and Agent Toni (Claude Opus 5) 2026-10-07\r\n - change: number, autocomplete, date and time fields take the toolkit keyboard of their\r\n attribute type (keyboardTypeFor) instead of only an explicit option.keyboardType\r\n - change: the date picker docks at the bottom on the devices (model-datepicker-panel--docked);\r\n the time picker stays attached to its field in a compact form (model-timepicker-panel);\r\n both report which picker closed (onPickerClose(picker)) -->\r\n\r\n<!-- Shuaib 2026-09-24\r\n - change: the model field switch uses renderFieldType so legacy checkbox fields render as boolean. -->\r\n\r\n<!-- Faramarz Yousefian and Agent Toni (Claude Opus 5) 2026-09-19\r\n - new: a @contract comment on the widest type coverage in the toolkit, and one on the credit\r\n card case recording that the rename reached this file first -->\r\n<!-- Loader Spinner -->\r\n<div *ngIf=\"isLoading\" class=\"loader-overlay\">\r\n <div class=\"spinner\"></div>\r\n</div>\r\n<div [style]=\"getStyleWithoutClasses(modalItemInfo?.layoutSchema?.style).style\"\r\n [class]=\"modalItemInfo?.layoutSchema?.style?.classes[0]\">\r\n <form #dynamicForm=\"ngForm\"\r\n *ngIf=\"modalItemInfo?.layoutSchema?.formSections?.length > 0\"\r\n (submit)=\"$event.preventDefault()\">\r\n <div\r\n *ngFor=\"let formSection of modalItemInfo?.layoutSchema?.formSections\">\r\n <div *ngIf=\"formSection?.label?.caption\"\r\n [class]=\"formSection?.label?.style?.classes[0]\"\r\n [style]=\"getStyleWithoutClasses(formSection?.label?.style).style\">\r\n {{formSection.label.caption}}\r\n </div>\r\n <div *ngIf=\"formSection?.formFields?.length > 0\"\r\n [class]=\"formSection?.style?.classes?.[0] || ''\"\r\n [ngStyle]=\"getSectionBodyStyle(formSection)\">\r\n <div *ngFor=\"let formField of formSection.formFields\"\r\n [ngStyle]=\"getFieldWrapperStyle(formField)\"\r\n [class]=\"formField?.style?.classes || ''\">\r\n\r\n <!-- @contract decision: the widest type coverage in the toolkit\r\n reality: every field type except the grid-only quantity renders here.\r\n When another container drops a type, this is the way out.\r\n seen: measured 2026-09-19. Note the file is model.component.html while\r\n the container is called modal in layout files - that costs a\r\n search every time -->\r\n <!-- @contract compatibility: checkbox is rendered as boolean for existing projects. -->\r\n <div [ngSwitch]=\"renderFieldType(\r\n formField?.scope?.reference &&\r\n modalItemInfo?.propertySchema?.[\r\n getScope(formField.scope.reference)\r\n ]\r\n ? modalItemInfo.propertySchema[\r\n getScope(formField.scope.reference)\r\n ]?.[\r\n formField.scope.reference.split('/').pop()\r\n ]?.type\r\n : 'default'\r\n )\">\r\n <!-- Media control -->\r\n <div\r\n *ngSwitchCase=\"'media'\"\r\n [style]=\"getStyleWithoutClasses(formField?.style).style\"\r\n [class]=\"formField.style?.classes ? formField.style?.classes[0] : ''\">\r\n\r\n <ng-container\r\n *ngTemplateOutlet=\"modelMediaContent; context: { field: formField }\">\r\n </ng-container>\r\n </div>\r\n\r\n <!-- credit card control -->\r\n <!-- @contract decision: the credit card type is spelled creditCard\r\n reality: this file was renamed on 2026-09-15, form.component.html and\r\n utility.service.ts followed on 2026-09-19. carditCard is read\r\n nowhere any more.\r\n failure: a data object still declaring carditCard renders empty. -->\r\n <div *ngSwitchCase=\"'creditCard'\"\r\n [style]=\"getStyleWithoutClasses(formField?.style).style\"\r\n [class]=\"formField.style?.classes[0]\">\r\n <div id=\"card-element\">\r\n <!-- a Stripe element will be inserted here -->\r\n </div>\r\n <!-- Used to display form errors -->\r\n <div id=\"card-errors\"\r\n class=\"displayError.textContent!=='': 'alert alert-danger mt-1'\">\r\n </div>\r\n </div>\r\n\r\n <!-- string control -->\r\n <div *ngSwitchCase=\"'string'\" class=\"form-group mb-3\">\r\n @if(formField.option && formField.option.control &&\r\n !formField.option.protected){\r\n @switch (formField.option.control) {\r\n @case ('textInput') {\r\n <div\r\n [ngStyle]=\"getFieldInnerLayoutStyle(formField)\">\r\n <vl-label [formField]=\"formField\"\r\n [modalItemInfo]=\"modalItemInfo\">\r\n </vl-label>\r\n <vl-textbox [formField]=\"formField\"\r\n [modalItemInfo]=\"modalItemInfo\">\r\n </vl-textbox>\r\n </div>\r\n <!-- Error Message -->\r\n <!-- <div *ngIf=\"inputField?.touched && inputField?.invalid\"\r\n [style]=\"getStyleWithoutClasses(formField?.validation?.style).style\">\r\n <p class=\"text-danger\" *ngIf=\"inputField?.errors?.['required']\">\r\n {{setErroMessage(formField, errorMessages, \"required\")}}</p>\r\n <p class=\"text-danger\" *ngIf=\"inputField?.errors?.['email']\">\r\n {{(formField.label?.value ?\r\n formField.label?.value :\r\n modalItemInfo.propertySchema[getScope(formField.scope?.reference)][formField.scope?.reference.split('/').pop()]?.caption)\r\n +\r\n ' ' + errorMessages.pattern}}</p>\r\n </div> -->\r\n }\r\n\r\n @case ('password') {\r\n <span>Switch not supported yet</span>\r\n\r\n }\r\n @case ('combobox') {\r\n <span>Combobox not supported yet</span>\r\n }\r\n @case('textArea'){\r\n <span>TextArea not supported yet</span>\r\n }\r\n @case ('switch') {\r\n <span>Switch not supported yet</span>\r\n }\r\n\r\n @case('radiobutton') {\r\n <span>Radiobutton not supported yet</span>\r\n }\r\n\r\n @case ('dropdown') {\r\n <span *ngIf=\"formField.option?.postfixCaption\">\r\n <select id=\"dynamic-dropdown\"\r\n [class]=\"formField.style?.classes ? formField.style?.classes[0]: ''\"\r\n #dropdownField=\"ngModel\"\r\n [style]=\"getStyleWithoutClasses(formField?.style).style\"\r\n [name]=\"formField.scope?.reference\"\r\n [(ngModel)]=\"modalItemInfo.propertySchema[getScope(formField.scope?.reference)][formField.scope?.reference.split('/').pop()].value\">\r\n <option\r\n *ngFor=\"let item of modalItemInfo.propertySchema[getScope(formField.scope?.reference)][formField.scope?.reference.split('/').pop()]?.data\"\r\n [value]=\"formField?.option?.optionValue ? formField.option.optionValue : 'value'\">\r\n {{ formField?.option?.optionLabel ?\r\n formField.option.optionLabel :\r\n 'label'}}</option>\r\n </select>\r\n <label\r\n [style]=\"getStyleWithoutClasses(formField?.label?.style).style\">{{modalItemInfo.propertySchema[getScope(formField.scope)][formField.scope?.reference.split('/').pop()]?.caption\r\n }}</label>\r\n </span>\r\n <div *ngIf=\"!formField.option?.postfixCaption\">\r\n <div\r\n [ngStyle]=\"getFieldInnerLayoutStyle(formField)\">\r\n <label\r\n [style]=\"getStyleWithoutClasses(formField?.label?.style).style\">{{modalItemInfo.propertySchema[getScope(formField.scope?.reference)][formField.scope?.reference.split('/').pop()]?.caption\r\n }}</label>\r\n\r\n <nz-select nzShowSearch nzAllowClear\r\n nzPlaceHolder=\"Select\"\r\n #dropdownField=\"ngModel\"\r\n [required]=\"formField.option.required\"\r\n [class]=\"formField.style?.classes ? formField.style?.classes[0]: ''\"\r\n [style]=\"getStyleWithoutClasses(formField?.style).style\"\r\n [name]=\"formField.scope?.reference\"\r\n [(ngModel)]=\"modalItemInfo.propertySchema[getScope(formField.scope?.reference)][formField.scope?.reference.split('/').pop()].value\">\r\n <nz-option\r\n *ngFor=\"let item of modalItemInfo.propertySchema[getScope(formField.scope?.reference)][formField.scope?.reference.split('/').pop()]?.data\"\r\n [nzLabel]=\"item[formField?.option?.optionLabel ? formField.option.optionLabel : 'label']\"\r\n [nzValue]=\"item[formField?.option?.optionValue ? formField.option.optionValue : 'value']\"></nz-option>\r\n </nz-select>\r\n </div>\r\n <!-- Error Message -->\r\n <div\r\n *ngIf=\"dropdownField?.touched && dropdownField?.invalid\"\r\n [style]=\"getStyleWithoutClasses(formField?.validation?.style).style\">\r\n <p class=\"text-danger\"\r\n *ngIf=\"dropdownField?.errors?.['required']\">\r\n {{formField.label?.value ?\r\n formField.label?.value :\r\n modalItemInfo.propertySchema[getScope(formField.scope?.reference)][formField.scope?.reference.split('/').pop()]?.caption\r\n +\r\n ' ' + errorMessages.required}}</p>\r\n <p class=\"text-danger\"\r\n *ngIf=\"dropdownField?.errors?.['email']\">\r\n {{(formField.label?.value ?\r\n formField.label?.value :\r\n modalItemInfo.propertySchema[getScope(formField.scope?.reference)][formField.scope?.reference.split('/').pop()]?.caption)\r\n +\r\n ' ' + errorMessages.pattern}}</p>\r\n </div>\r\n </div>\r\n }\r\n\r\n @case ('autocomplete') {\r\n <div\r\n [ngStyle]=\"getFieldInnerLayoutStyle(formField)\">\r\n <vl-label [formField]=\"formField\"\r\n [modalItemInfo]=\"modalItemInfo\">\r\n </vl-label>\r\n\r\n <span>\r\n <p-autocomplete\r\n #autocompleteField=\"ngModel\"\r\n [required]=\"formField.option.required\"\r\n [name]=\"formField.scope?.reference\"\r\n styleClass=\"custom-autocomplete\"\r\n [(ngModel)]=\"modalItemInfo.propertySchema[getScope(formField.scope?.reference)][formField.scope?.reference.split('/').pop()].value\"\r\n [style]=\"getStyleWithoutClasses(formField?.scope?.style).style\"\r\n [class]=\"formField?.scope?.style?.classes ? formField?.scope?.style?.classes[0] : ''\"\r\n [suggestions]=\"matchData\"\r\n [dropdown]=\"true\"\r\n [optionLabel]=\"formField?.option?.autocomplete?.response?.label ? formField.option.autocomplete.response.label : 'label'\"\r\n [placeholder]=\"modalItemInfo.propertySchema | vlPlaceholder: formField.scope?.reference\"\r\n (completeMethod)=\"autocompChangeEvent($event, formField)\"\r\n (ngModelChange)=\"autocompFocusOutEvent($event, formField)\"\r\n [vlCustomKeyboard]=\"keyboardTypeFor(formField)\">\r\n </p-autocomplete>\r\n <!-- Error Message -->\r\n <div\r\n *ngIf=\"autocompleteField?.touched && autocompleteField?.invalid\"\r\n [style]=\"getStyleWithoutClasses(formField?.validation?.style).style\">\r\n <p class=\"text-danger\"\r\n *ngIf=\"autocompleteField?.errors?.['required']\">\r\n {{setErroMessage(formField,\r\n errorMessages, \"required\")}}</p>\r\n <p class=\"text-danger\"\r\n *ngIf=\"autocompleteField?.errors?.['email']\">\r\n {{(formField.label?.value ?\r\n formField.label?.value :\r\n modalItemInfo.propertySchema[getScope(formField.scope?.reference)][formField.scope?.reference.split('/').pop()]?.caption)\r\n +\r\n ' ' +\r\n errorMessages.pattern}}</p>\r\n </div>\r\n </span>\r\n </div>\r\n }\r\n }\r\n }@else{\r\n <div *ngIf=\"!formField.option.protected\">\r\n <div\r\n [ngStyle]=\"getFieldInnerLayoutStyle(formField)\">\r\n <vl-label [formField]=\"formField\"\r\n [modalItemInfo]=\"modalItemInfo\">\r\n </vl-label>\r\n <vl-textbox [formField]=\"formField\"\r\n [modalItemInfo]=\"modalItemInfo\">\r\n </vl-textbox>\r\n </div>\r\n <!-- Error Message -->\r\n <!-- <div *ngIf=\"inputField?.touched && inputField?.invalid\"\r\n [style]=\"getStyleWithoutClasses(formField?.validation?.style).style\">\r\n <p class=\"text-danger\" *ngIf=\"inputField?.errors?.['required']\">\r\n {{setErroMessage(formField, errorMessages, \"required\")}}</p>\r\n <p class=\"text-danger\" *ngIf=\"inputField?.errors?.['email']\">\r\n {{(formField.label?.value ?\r\n formField.label?.value :\r\n modalItemInfo.propertySchema[getScope(formField.scope?.reference)][formField.scope?.reference.split('/').pop()]?.caption)\r\n +\r\n ' ' + errorMessages.pattern}}</p>\r\n </div> -->\r\n </div>\r\n }\r\n <span *ngIf=\"formField.option.protected\"\r\n [style]=\"getStyleWithoutClasses(formField?.label?.style).style\"\r\n [class]=\"formField?.label?.style.classes ? formField?.label?.style?.classes[0] : ''\">\r\n <vl-string [formField]=\"formField\"\r\n [modalItemInfo]=\"modalItemInfo\">\r\n </vl-string>\r\n </span>\r\n\r\n </div>\r\n\r\n <!-- number control -->\r\n <div *ngSwitchCase=\"'number'\" class=\"form-group mb-3\">\r\n <span *ngIf=\"formField.option.protected\"\r\n [style]=\"getStyleWithoutClasses(formField?.label?.style).style\"\r\n [class]=\"formField?.label?.style.classes ? formField?.label?.style?.classes[0] : ''\">\r\n <h5>{{\r\n modalItemInfo.propertySchema[getScope(formField.scope?.reference)][formField.scope?.reference.split('/').pop()]?.caption\r\n }} {{\r\n modalItemInfo.propertySchema[getScope(formField.scope?.reference)][formField.scope?.reference.split('/').pop()]?.value\r\n |\r\n currency:formField.option.currency :true:\r\n formField.option?.decimalPoint}}\r\n </h5>\r\n </span>\r\n <span *ngIf=\"!formField.option.protected\">\r\n <div\r\n [ngStyle]=\"getFieldInnerLayoutStyle(formField)\">\r\n <label\r\n [style]=\"getStyleWithoutClasses(formField?.label?.style).style\"\r\n [class]=\"formField?.label?.style.classes ? formField?.label?.style?.classes[0] : ''\">{{\r\n formField.label?.value\r\n ?\r\n formField.label?.value :\r\n modalItemInfo.propertySchema[getScope(formField.scope?.reference)][formField.scope?.reference.split('/').pop()]?.caption\r\n }}</label>\r\n <input type=\"number\"\r\n [class]=\"formField.style?.classes ? formField.style?.classes[0]: ''\"\r\n [vlCustomKeyboard]=\"keyboardTypeFor(formField)\"\r\n [style]=\"getStyleWithoutClasses(formField?.style).style\"\r\n [(ngModel)]=\"modalItemInfo.propertySchema[getScope(formField.scope?.reference)][formField.scope?.reference.split('/').pop()].value\"\r\n [name]=\"formField.scope?.reference\"\r\n [placeholder]=\"modalItemInfo.propertySchema | vlPlaceholder: formField.scope?.reference\" />\r\n </div>\r\n </span>\r\n </div>\r\n\r\n <!-- DateRange control -->\r\n <div *ngSwitchCase=\"'dateRange'\"\r\n class=\"form-group mb-3\">\r\n <span *ngIf=\"formField.option.protected\"\r\n [style]=\"getStyleWithoutClasses(formField?.label?.style).style\"\r\n [class]=\"formField?.label?.style.classes ? formField?.label?.style?.classes[0] : ''\">\r\n <vl-string [formField]=\"formField\"\r\n [modalItemInfo]=\"modalItemInfo\">\r\n </vl-string>\r\n </span>\r\n <div *ngIf=\"!formField.option.protected\">\r\n <div\r\n [ngStyle]=\"getFieldInnerLayoutStyle(formField)\">\r\n <label\r\n [style]=\"getStyleWithoutClasses(formField?.label?.style).style\"\r\n [class]=\"formField?.label?.style.classes ? formField?.label?.style?.classes[0] : ''\">{{\r\n formField.label?.value\r\n ?\r\n formField.label?.value :\r\n modalItemInfo.propertySchema[getScope(formField.scope?.reference)][formField.scope?.reference.split('/').pop()]?.caption\r\n }}</label>\r\n <nz-range-picker #dateRangeField=\"ngModel\"\r\n [required]=\"formField.option.required\"\r\n [name]=\"formField.scope?.reference\"\r\n [style]=\"getStyleWithoutClasses(formField?.style).style\"\r\n [(ngModel)]=\"modalItemInfo.propertySchema[getScope(formField.scope?.reference)][formField.scope?.reference.split('/').pop()].value\"></nz-range-picker>\r\n </div>\r\n <!-- Error Message -->\r\n <div\r\n *ngIf=\"dateRangeField?.touched && dateRangeField?.invalid\"\r\n [style]=\"getStyleWithoutClasses(formField?.validation?.style).style\">\r\n <p class=\"text-danger\"\r\n *ngIf=\"dateRangeField?.errors?.['required']\">\r\n {{formField.label?.value ?\r\n formField.label?.value :\r\n modalItemInfo.propertySchema[getScope(formField.scope?.reference)][formField.scope?.reference.split('/').pop()]?.caption\r\n +\r\n ' ' + errorMessages.required}}</p>\r\n <p class=\"text-danger\"\r\n *ngIf=\"dateRangeField?.errors?.['email']\">\r\n {{(formField.label?.value ?\r\n formField.label?.value :\r\n modalItemInfo.propertySchema[getScope(formField.scope?.reference)][formField.scope?.reference.split('/').pop()]?.caption)\r\n +\r\n ' ' + errorMessages.pattern}}</p>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- Date control -->\r\n <div *ngSwitchCase=\"'date'\" class=\"form-group mb-3\">\r\n <span\r\n *ngIf=\"formField.option.protected\"\r\n [style]=\"getStyleWithoutClasses(formField?.label?.style).style\"\r\n [class]=\"formField?.label?.style.classes ? formField?.label?.style?.classes[0] : ''\">\r\n <vl-string\r\n [formField]=\"formField\"\r\n [modalItemInfo]=\"modalItemInfo\">\r\n </vl-string>\r\n </span>\r\n\r\n <div *ngIf=\"!formField.option.protected\">\r\n <div\r\n [ngStyle]=\"getFieldInnerLayoutStyle(formField)\">\r\n <label\r\n [style]=\"getStyleWithoutClasses(formField?.label?.style).style\"\r\n [class]=\"formField?.label?.style.classes ? formField?.label?.style?.classes[0] : ''\">\r\n {{ getLabel(formField) }}\r\n </label>\r\n\r\n <span>\r\n <div class=\"picker-field\">\r\n <p-datepicker\r\n #datePicker\r\n #dateField=\"ngModel\"\r\n styleClass=\"custom-datepicker\"\r\n [required]=\"formField.option.required\"\r\n [name]=\"formField.scope?.reference\"\r\n [disabled]=\"formField?.option?.disabled\"\r\n [showIcon]=\"false\"\r\n [showOnFocus]=\"false\"\r\n appendTo=\"body\"\r\n [autoZIndex]=\"true\"\r\n [baseZIndex]=\"10000\"\r\n [panelStyleClass]=\"picker.datePanelClass\"\r\n [motionOptions]=\"picker.dockedMotion\"\r\n [vlCustomKeyboard]=\"keyboardTypeFor(formField)\"\r\n (pointerdown)=\"picker.onFieldPointerDown($event, datePicker)\"\r\n (onFocus)=\"picker.onFieldFocus($event)\"\r\n (onShow)=\"picker.onShown()\"\r\n (onClose)=\"picker.onClose(datePicker)\"\r\n (ngModelChange)=\"dateChangeEvent(formField, $event)\"\r\n (onInput)=\"onDateTyping($event)\"\r\n [dateFormat]=\"\r\n modalItemInfo.propertySchema[\r\n getScope(formField.scope?.reference)\r\n ][\r\n formField.scope?.reference.split('/').pop()\r\n ]?.format || 'yy-mm-dd'\r\n \"\r\n [(ngModel)]=\"\r\n modalItemInfo.propertySchema[\r\n getScope(formField.scope?.reference)\r\n ][\r\n formField.scope?.reference.split('/').pop()\r\n ].value\r\n \"\r\n [class]=\"formField?.scope?.style?.classes?.[0] || ''\"\r\n [style]=\"getStyleWithoutClasses(formField?.scope?.style).style\">\r\n </p-datepicker>\r\n\r\n <button\r\n type=\"button\"\r\n class=\"picker-field__icon\"\r\n aria-label=\"Open calendar\"\r\n [disabled]=\"formField?.option?.disabled\"\r\n (pointerdown)=\"picker.openFromIcon($event, datePicker)\"\r\n (click)=\"picker.blockIconClick($event)\">\r\n <i class=\"pi pi-calendar\"></i>\r\n </button>\r\n </div>\r\n\r\n <div\r\n *ngIf=\"dateField?.touched && dateField?.invalid\"\r\n [style]=\"getStyleWithoutClasses(formField?.validation?.style).style\">\r\n <p class=\"text-danger\"\r\n *ngIf=\"dateField?.errors?.['required']\">\r\n {{ setErroMessage(formField,\r\n errorMessages, 'required') }}\r\n </p>\r\n <p class=\"text-danger\"\r\n *ngIf=\"dateField?.errors?.['email']\">\r\n {{\r\n (formField.label?.value\r\n ? formField.label?.value\r\n : modalItemInfo.propertySchema[\r\n getScope(formField.scope?.reference)\r\n ][\r\n formField.scope?.reference.split('/').pop()\r\n ]?.caption)\r\n + ' ' + errorMessages.pattern\r\n }}\r\n </p>\r\n </div>\r\n </span>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- Time control -->\r\n <div *ngSwitchCase=\"'time'\" class=\"form-group mb-3\">\r\n <span\r\n *ngIf=\"formField.option.protected\"\r\n [style]=\"getStyleWithoutClasses(formField?.label?.style).style\"\r\n [class]=\"formField?.label?.style.classes ? formField?.label?.style?.classes[0] : ''\">\r\n <vl-string\r\n [formField]=\"formField\"\r\n [modalItemInfo]=\"modalItemInfo\">\r\n </vl-string>\r\n </span>\r\n\r\n <div *ngIf=\"!formField.option.protected\">\r\n <div\r\n [ngStyle]=\"getFieldInnerLayoutStyle(formField)\">\r\n <label\r\n [style]=\"getStyleWithoutClasses(formField?.label?.style).style\"\r\n [class]=\"formField?.label?.style.classes ? formField?.label?.style?.classes[0] : ''\">\r\n {{ getLabel(formField) }}\r\n </label>\r\n\r\n <span>\r\n <div class=\"picker-field\">\r\n <p-datepicker\r\n #timePicker\r\n #timeField=\"ngModel\"\r\n styleClass=\"custom-datepicker\"\r\n [required]=\"formField.option.required\"\r\n [name]=\"formField.scope?.reference\"\r\n [timeOnly]=\"true\"\r\n hourFormat=\"24\"\r\n [disabled]=\"formField?.option?.disabled\"\r\n [showIcon]=\"false\"\r\n [showOnFocus]=\"false\"\r\n appendTo=\"body\"\r\n [autoZIndex]=\"true\"\r\n [baseZIndex]=\"10000\"\r\n [panelStyleClass]=\"picker.timePanelClass\"\r\n [vlCustomKeyboard]=\"keyboardTypeFor(formField)\"\r\n (pointerdown)=\"picker.onFieldPointerDown($event, timePicker)\"\r\n (onFocus)=\"picker.onFieldFocus($event)\"\r\n (onShow)=\"onTimePanelShow(formField)\"\r\n (onClose)=\"picker.onClose(timePicker)\"\r\n (onInput)=\"onTimeTyping($event)\"\r\n (ngModelChange)=\"timeChangeEvent(formField, $event)\"\r\n [style]=\"getStyleWithoutClasses(formField?.scope?.style).style\"\r\n [(ngModel)]=\"\r\n modalItemInfo.propertySchema[\r\n getScope(formField.scope?.reference)\r\n ][\r\n formField.scope?.reference.split('/').pop()\r\n ].value\r\n \"\r\n [class]=\"formField?.scope?.style?.classes?.[0] || ''\">\r\n </p-datepicker>\r\n\r\n <button\r\n type=\"button\"\r\n class=\"picker-field__icon\"\r\n aria-label=\"Open time picker\"\r\n [disabled]=\"formField?.option?.disabled\"\r\n (pointerdown)=\"picker.openFromIcon($event, timePicker)\"\r\n (click)=\"picker.blockIconClick($event)\">\r\n <i class=\"pi pi-clock\"></i>\r\n </button>\r\n </div>\r\n\r\n <div\r\n *ngIf=\"timeField?.touched && timeField?.invalid\"\r\n [style]=\"getStyleWithoutClasses(formField?.validation?.style).style\">\r\n <p class=\"text-danger\"\r\n *ngIf=\"timeField?.errors?.['required']\">\r\n {{ setErroMessage(formField,\r\n errorMessages, 'required') }}\r\n </p>\r\n <p class=\"text-danger\"\r\n *ngIf=\"timeField?.errors?.['email']\">\r\n {{\r\n (formField.label?.value\r\n ? formField.label?.value\r\n : modalItemInfo.propertySchema[\r\n getScope(formField.scope?.reference)\r\n ][\r\n formField.scope?.reference.split('/').pop()\r\n ]?.caption)\r\n + ' ' + errorMessages.pattern\r\n }}\r\n </p>\r\n </div>\r\n </span>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- Autocomplete control -->\r\n <div *ngSwitchCase=\"'autocomplete'\"\r\n class=\"form-group mb-3\">\r\n <span *ngIf=\"formField.option.protected\"\r\n [style]=\"getStyleWithoutClasses(formField?.label?.style).style\"\r\n [class]=\"formField?.label?.style.classes ? formField?.label?.style?.classes[0] : ''\">\r\n <vl-string [formField]=\"formField\"\r\n [modalItemInfo]=\"modalItemInfo\">\r\n </vl-string>\r\n </span>\r\n <div *ngIf=\"!formField.option.protected\">\r\n <div\r\n [ngStyle]=\"getFieldInnerLayoutStyle(formField)\">\r\n <vl-label [formField]=\"formField\"\r\n [modalItemInfo]=\"modalItemInfo\">\r\n </vl-label>\r\n\r\n <span>\r\n <p-autocomplete\r\n #autocompleteField=\"ngModel\"\r\n [required]=\"formField.option.required\"\r\n [name]=\"formField.scope?.reference\"\r\n styleClass=\"custom-autocomplete\"\r\n [(ngModel)]=\"modalItemInfo.propertySchema[getScope(formField.scope?.reference)][formField.scope?.reference.split('/').pop()].value\"\r\n [style]=\"getStyleWithoutClasses(formField?.scope?.style).style\"\r\n [class]=\"formField?.scope?.style?.classes ? formField?.scope?.style?.classes[0] : ''\"\r\n [suggestions]=\"matchData\"\r\n [dropdown]=\"true\"\r\n [optionLabel]=\"formField?.option?.autocomplete?.response?.label ? formField.option.autocomplete.response.label : 'label'\"\r\n [placeholder]=\"modalItemInfo.propertySchema | vlPlaceholder: formField.scope?.reference\"\r\n (completeMethod)=\"autocompChangeEvent($event, formField)\"\r\n (ngModelChange)=\"autocompFocusOutEvent($event, formField)\"\r\n [vlCustomKeyboard]=\"keyboardTypeFor(formField)\">\r\n </p-autocomplete>\r\n <!-- Error Message -->\r\n <div\r\n *ngIf=\"autocompleteField?.touched && autocompleteField?.invalid\"\r\n [style]=\"getStyleWithoutClasses(formField?.validation?.style).style\">\r\n <p class=\"text-danger\"\r\n *ngIf=\"autocompleteField?.errors?.['required']\">\r\n {{setErroMessage(formField,\r\n errorMessages, \"required\")}}</p>\r\n <p class=\"text-danger\"\r\n *ngIf=\"autocompleteField?.errors?.['email']\">\r\n {{(formField.label?.value ?\r\n formField.label?.value :\r\n modalItemInfo.propertySchema[getScope(formField.scope?.reference)][formField.scope?.reference.split('/').pop()]?.caption)\r\n +\r\n ' ' +\r\n errorMessages.pattern}}</p>\r\n </div>\r\n </span>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- checkBox control -->\r\n <div *ngSwitchCase=\"'boolean'\" class=\"form-group mb-3\"\r\n [style]=\"getStyleWithoutClasses(formField?.style).style\"\r\n [class]=\"formField.style?.classes ? formField.style?.classes[0] : ''\">\r\n <span *ngIf=\"formField.option?.postfixCaption\">\r\n <label class=\"form-check-label\"><input\r\n type=\"checkbox\" class=\"form-check-input\"\r\n [(ngModel)]=\"modalItemInfo.propertySchema[getScope(formField.scope?.reference)][formField.scope?.reference.split('/').pop()].value\"\r\n [name]=\"formField.scope?.reference\"\r\n (ngModelChange)=\"invokeSetformData()\" />{{\r\n modalItemInfo.propertySchema[getScope(formField.scope?.reference)][formField.scope?.reference.split('/').pop()]?.caption\r\n }}</label>\r\n </span>\r\n <div *ngIf=\"!formField.option?.postfixCaption\"\r\n [class]=\"formField?.layout == 'horizontal' ? 'horizontal-layout' : 'row'\">\r\n <label class=\"form-check-label\">{{\r\n modalItemInfo.propertySchema[getScope(formField.scope?.reference)][formField.scope?.reference.split('/').pop()]?.caption\r\n }}\r\n <input type=\"checkbox\"\r\n class=\"form-check-input\"\r\n [(ngModel)]=\"modalItemInfo.propertySchema[getScope(formField.scope?.reference)][formField.scope?.reference.split('/').pop()].value\"\r\n [name]=\"formField.scope?.reference\" /></label>\r\n </div>\r\n </div>\r\n\r\n <!-- dropdown control -->\r\n <div *ngSwitchCase=\"'dropdown'\" class=\"form-group mb-3\"\r\n [style]=\"getStyleWithoutClasses(formField?.style).style\"\r\n [class]=\"formField.style?.classes ? formField.style?.classes[0] : ''\">\r\n <span *ngIf=\"formField.option?.postfixCaption\">\r\n <select id=\"dynamic-dropdown\"\r\n [class]=\"formField.style?.classes ? formField.style?.classes[0]: ''\"\r\n #dropdownField=\"ngModel\"\r\n [style]=\"getStyleWithoutClasses(formField?.style).style\"\r\n [name]=\"formField.scope?.reference\"\r\n [(ngModel)]=\"modalItemInfo.propertySchema[getScope(formField.scope?.reference)][formField.scope?.reference.split('/').pop()].value\">\r\n <option\r\n *ngFor=\"let item of modalItemInfo.propertySchema[getScope(formField.scope?.reference)][formField.scope?.reference.split('/').pop()]?.data\"\r\n [value]=\"formField?.option?.optionValue ? formField.option.optionValue : 'value'\">\r\n {{ formField?.option?.optionLabel ?\r\n formField.option.optionLabel :\r\n 'label'}}</option>\r\n </select>\r\n <label\r\n [style]=\"getStyleWithoutClasses(formField?.label?.style).style\">{{modalItemInfo.propertySchema[getScope(formField.scope)][formField.scope?.reference.split('/').pop()]?.caption\r\n }}</label>\r\n </span>\r\n <div *ngIf=\"!formField.option?.postfixCaption\">\r\n <div\r\n [ngStyle]=\"getFieldInnerLayoutStyle(formField)\">\r\n <label\r\n [style]=\"getStyleWithoutClasses(formField?.label?.style).style\">{{modalItemInfo.propertySchema[getScope(formField.scope?.reference)][formField.scope?.reference.split('/').pop()]?.caption\r\n }}</label>\r\n\r\n <nz-select nzShowSearch nzAllowClear\r\n nzPlaceHolder=\"Select\"\r\n #dropdownField=\"ngModel\"\r\n [required]=\"formField.option.required\"\r\n [class]=\"formField.style?.classes ? formField.style?.classes[0]: ''\"\r\n [style]=\"getStyleWithoutClasses(formField?.style).style\"\r\n [name]=\"formField.scope?.reference\"\r\n [(ngModel)]=\"modalItemInfo.propertySchema[getScope(formField.scope?.reference)][formField.scope?.reference.split('/').pop()].value\">\r\n <nz-option\r\n *ngFor=\"let item of modalItemInfo.propertySchema[getScope(formField.scope?.reference)][formField.scope?.reference.split('/').pop()]?.data\"\r\n [nzLabel]=\"item[formField?.option?.optionLabel ? formField.option.optionLabel : 'label']\"\r\n [nzValue]=\"item[formField?.option?.optionValue ? formField.option.optionValue : 'value']\"></nz-option>\r\n </nz-select>\r\n </div>\r\n <!-- Error Message -->\r\n <div\r\n *ngIf=\"dropdownField?.touched && dropdownField?.invalid\"\r\n [style]=\"getStyleWithoutClasses(formField?.validation?.style).style\">\r\n <p class=\"text-danger\"\r\n *ngIf=\"dropdownField?.errors?.['required']\">\r\n {{formField.label?.value ?\r\n formField.label?.value :\r\n modalItemInfo.propertySchema[getScope(formField.scope?.reference)][formField.scope?.reference.split('/').pop()]?.caption\r\n +\r\n ' ' + errorMessages.required}}</p>\r\n <p class=\"text-danger\"\r\n *ngIf=\"dropdownField?.errors?.['email']\">\r\n {{(formField.label?.value ?\r\n formField.label?.value :\r\n modalItemInfo.propertySchema[getScope(formField.scope?.reference)][formField.scope?.reference.split('/').pop()]?.caption)\r\n +\r\n ' ' + errorMessages.pattern}}</p>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- button control -->\r\n <div *ngSwitchCase=\"'default'\">\r\n <button type=\"button\"\r\n [ngStyle]=\"getStyleWithoutClasses(formField.style).style\"\r\n (click)=\"invokeFormBtnClick(formField.option, modalItemInfo.propertySchema, dynamicForm)\"\r\n class=\"btn btn-primary btn-block\">\r\n {{ getButtonCaption(formField) }}\r\n </button>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n </form>\r\n</div>\r\n<ng-template #modelMediaContent let-field=\"field\">\r\n <ng-container *ngIf=\"getMediaSource(field) as source\">\r\n <ng-container [ngSwitch]=\"getMediaKind(field)\">\r\n\r\n <img\r\n *ngSwitchDefault\r\n [src]=\"source\"\r\n [alt]=\"getMediaLabel(field)\"\r\n loading=\"lazy\" />\r\n\r\n <video\r\n *ngSwitchCase=\"'video'\"\r\n [src]=\"source\"\r\n [attr.aria-label]=\"getMediaLabel(field)\"\r\n controls\r\n playsinline\r\n preload=\"metadata\">\r\n Your browser does not support video playback.\r\n </video>\r\n\r\n <audio\r\n *ngSwitchCase=\"'audio'\"\r\n [src]=\"source\"\r\n [attr.aria-label]=\"getMediaLabel(field)\"\r\n controls\r\n preload=\"metadata\">\r\n Your browser does not support audio playback.\r\n </audio>\r\n\r\n <a\r\n *ngSwitchCase=\"'pdf'\"\r\n [href]=\"source\"\r\n target=\"_blank\"\r\n rel=\"noopener noreferrer\">\r\n Open PDF \u2014 {{ getMediaLabel(field) }}\r\n </a>\r\n\r\n <a\r\n *ngSwitchCase=\"'file'\"\r\n [href]=\"source\"\r\n target=\"_blank\"\r\n rel=\"noopener noreferrer\">\r\n Open file \u2014 {{ getMediaLabel(field) }}\r\n </a>\r\n\r\n </ng-container>\r\n </ng-container>\r\n</ng-template>", styles: [":host ::ng-deep .custom-datepicker .p-datepicker-dropdown{height:100%;border-radius:4px}:host ::ng-deep .custom-datepicker .p-datepicker-input{border-radius:4px}::ng-deep .p-autocomplete-list{background-color:#fff}:host ::ng-deep .custom-autocomplete{display:flex;width:100%}:host ::ng-deep .custom-autocomplete .p-autocomplete-input{flex:1;width:100%;min-width:0;border:none!important;outline:none!important;box-shadow:none!important;background:transparent!important}:host ::ng-deep .custom-autocomplete .p-autocomplete-dropdown{height:100%;border-radius:4px}:host ::ng-deep .custom-autocomplete .p-autocomplete-input:focus,:host ::ng-deep .custom-autocomplete .p-autocomplete-input:focus-visible,:host ::ng-deep .custom-autocomplete .p-inputtext:enabled:focus{border:none!important;outline:none!important;box-shadow:none!important}.responsive-modal-grid{width:100%;min-width:0;box-sizing:border-box}@media screen and (max-width:767px){.responsive-modal-grid{grid-template-columns:repeat(12,minmax(0,1fr))!important;gap:10px!important}.responsive-modal-field{grid-column:1 / -1!important;width:100%!important;max-width:none!important;min-width:0!important}.responsive-modal-action:nth-last-child(2){grid-column:1 / span 6!important}.responsive-modal-action:last-child{grid-column:7 / span 6!important}.responsive-modal-action{width:100%!important;max-width:none!important;min-width:0!important;justify-self:stretch!important;box-sizing:border-box!important}.responsive-modal-action button{display:block!important;width:100%!important;max-width:none!important;min-width:0!important;margin:0!important;box-sizing:border-box!important}}:host{--modal-field-focus-color: var(--p-primary-color, #10b981);--modal-field-focus-shadow: 0 0 0 2px rgba(16, 185, 129, .16)}:host ::ng-deep input:not([type=checkbox]):not(:disabled):focus,:host ::ng-deep textarea:not(:disabled):focus{border-color:var(--modal-field-focus-color)!important;outline:none!important;box-shadow:var(--modal-field-focus-shadow)!important}:host ::ng-deep .custom-autocomplete:focus-within{border-color:var(--modal-field-focus-color)!important;outline:none!important;box-shadow:var(--modal-field-focus-shadow)!important}:host ::ng-deep .custom-autocomplete:focus-within .p-autocomplete-input{border:none!important;outline:none!important;box-shadow:none!important}:host ::ng-deep select:not(:disabled):focus{border-color:var(--modal-field-focus-color)!important;outline:none!important;box-shadow:var(--modal-field-focus-shadow)!important}:host ::ng-deep .ant-select-focused:not(.ant-select-disabled) .ant-select-selector,:host ::ng-deep nz-select:not(.ant-select-disabled):focus-within .ant-select-selector{border-color:var(--modal-field-focus-color)!important;outline:none!important;box-shadow:var(--modal-field-focus-shadow)!important}:host ::ng-deep .p-select:not(.p-disabled).p-focus,:host ::ng-deep .p-select:not(.p-disabled):focus-within,:host ::ng-deep .p-dropdown:not(.p-disabled).p-focus,:host ::ng-deep .p-dropdown:not(.p-disabled):focus-within{border-color:var(--modal-field-focus-color)!important;outline:none!important;box-shadow:var(--modal-field-focus-shadow)!important}:host ::ng-deep .custom-datepicker:focus-within .p-datepicker-input{border-color:var(--modal-field-focus-color)!important;outline:none!important;box-shadow:var(--modal-field-focus-shadow)!important}:host ::ng-deep input:disabled,:host ::ng-deep textarea:disabled,:host ::ng-deep select:disabled,:host ::ng-deep .p-disabled,:host ::ng-deep .ant-select-disabled .ant-select-selector{box-shadow:none!important}\n"] }]
6173
6476
  }], ctorParameters: () => [{ type: i0.ChangeDetectorRef }, { type: i1$3.DynamicDialogRef }, { type: i1$3.DynamicDialogConfig }, { type: UtilityService }], propDecorators: { errorMessages: [{
6174
6477
  type: Input
6175
6478
  }], modalItemInfo: [{
@@ -6299,6 +6602,228 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.2", ngImpor
6299
6602
  args: [{ selector: 'vl-time', standalone: true, template: "<p>time works!</p>\r\n" }]
6300
6603
  }] });
6301
6604
 
6605
+ // Faramarz Yousefian and Agent Toni (Claude Opus 5.5) 2026-10-14
6606
+ // - new: one OpenID Connect flow for the devices, used by Keycloak and Okta alike. Both are OIDC with
6607
+ // PKCE; only issuer, client id and redirect differ, and the endpoints come from the issuer's
6608
+ // discovery document. Before, MobileKeycloakService and MobileOktaService each had their own
6609
+ // login, refresh and logout, and the logout behaved differently (Okta: white page, browser window)
6610
+ /** Set by signOut: the next login asks for the password instead of reusing the provider session. */
6611
+ const PROMPT_LOGIN_KEY = 'vl-oidc-prompt-login';
6612
+ /** Set by signOut when the project requires a login: the restarted app shows its loader (app.ts). */
6613
+ const RELOGIN_KEY = 'vl-relogin';
6614
+ class MobileOidcService {
6615
+ discoveries = new Map();
6616
+ /** The issuer's discovery document, fetched once per issuer. */
6617
+ discover(issuer) {
6618
+ const key = issuer.replace(/\/+$/, '');
6619
+ if (!this.discoveries.has(key)) {
6620
+ const request = stagedRequest(signal => fetch(`${key}/.well-known/openid-configuration`, { signal }))
6621
+ .then(response => {
6622
+ if (!response.ok) {
6623
+ throw new Error(`OIDC discovery failed (${response.status})`);
6624
+ }
6625
+ return response.json();
6626
+ });
6627
+ // A failed discovery must not stay cached.
6628
+ request.catch(() => this.discoveries.delete(key));
6629
+ this.discoveries.set(key, request);
6630
+ }
6631
+ return this.discoveries.get(key);
6632
+ }
6633
+ /**
6634
+ * Signs in through the system browser (authorization code + PKCE). With offlineAccess the scope
6635
+ * gets offline_access; if the provider refuses it the login is repeated without it. After a
6636
+ * logout the provider is asked for the password again (prompt=login).
6637
+ */
6638
+ async login(provider) {
6639
+ const discovery = await this.discover(provider.issuer);
6640
+ const scope = this.scopeOf(provider.scope);
6641
+ const promptLogin = this.flag(PROMPT_LOGIN_KEY);
6642
+ const authenticate = (withScope) => OAuth2Client.authenticate({
6643
+ appId: provider.clientId,
6644
+ authorizationBaseUrl: discovery.authorization_endpoint,
6645
+ accessTokenEndpoint: discovery.token_endpoint,
6646
+ redirectUrl: provider.redirectUri,
6647
+ responseType: 'code',
6648
+ scope: withScope,
6649
+ pkceEnabled: true,
6650
+ logsEnabled: false,
6651
+ ...(promptLogin ? { additionalParameters: { prompt: 'login' } } : {})
6652
+ });
6653
+ let result;
6654
+ try {
6655
+ result = await authenticate(provider.offlineAccess ? this.withOfflineAccess(scope) : scope);
6656
+ }
6657
+ catch (error) {
6658
+ const cancelled = /USER_CANCELLED/i.test(String(error?.message ?? error));
6659
+ if (!provider.offlineAccess || cancelled) {
6660
+ throw error;
6661
+ }
6662
+ console.warn('Identity provider refused offline_access, signing in without it');
6663
+ result = await authenticate(scope);
6664
+ }
6665
+ this.setFlag(PROMPT_LOGIN_KEY, false);
6666
+ const response = result?.access_token_response ?? result;
6667
+ const accessToken = response?.access_token ?? result?.access_token;
6668
+ if (!accessToken) {
6669
+ return null;
6670
+ }
6671
+ return {
6672
+ access_token: accessToken,
6673
+ refresh_token: response?.refresh_token,
6674
+ id_token: response?.id_token,
6675
+ expires_in: response?.expires_in,
6676
+ token_type: response?.token_type,
6677
+ issuer: provider.issuer
6678
+ };
6679
+ }
6680
+ /** New tokens from the refresh token (grant_type=refresh_token, public client - no secret). */
6681
+ async refresh(provider, stored) {
6682
+ if (!stored?.refresh_token || !provider?.clientId) {
6683
+ return 'refused';
6684
+ }
6685
+ try {
6686
+ const discovery = await this.discover(stored.issuer || provider.issuer);
6687
+ const response = await stagedRequest(signal => fetch(discovery.token_endpoint, {
6688
+ method: 'POST',
6689
+ headers: { 'Content-Type': 'application/x-www-form-urlencoded', Accept: 'application/json' },
6690
+ body: new URLSearchParams({
6691
+ grant_type: 'refresh_token',
6692
+ refresh_token: stored.refresh_token,
6693
+ client_id: provider.clientId
6694
+ }).toString(),
6695
+ signal
6696
+ }));
6697
+ if (!response.ok) {
6698
+ // 400 invalid_grant: expired, rotated away or revoked.
6699
+ return 'refused';
6700
+ }
6701
+ const result = await response.json();
6702
+ if (!result?.access_token) {
6703
+ return 'refused';
6704
+ }
6705
+ return {
6706
+ access_token: result.access_token,
6707
+ // With token rotation the provider sends a new refresh token each time.
6708
+ refresh_token: result.refresh_token ?? stored.refresh_token,
6709
+ id_token: result.id_token ?? stored.id_token,
6710
+ expires_in: result.expires_in,
6711
+ token_type: result.token_type,
6712
+ issuer: stored.issuer || provider.issuer
6713
+ };
6714
+ }
6715
+ catch {
6716
+ console.warn('Token refresh not reachable');
6717
+ return null;
6718
+ }
6719
+ }
6720
+ /** The user's claims from the provider's userinfo endpoint; null when the token is refused. */
6721
+ async userInfo(provider, accessToken) {
6722
+ const discovery = await this.discover(provider.issuer);
6723
+ const response = await stagedRequest(signal => fetch(discovery.userinfo_endpoint, {
6724
+ headers: { Authorization: `Bearer ${accessToken}`, Accept: 'application/json' },
6725
+ signal
6726
+ }));
6727
+ return response.ok ? response.json() : null;
6728
+ }
6729
+ /**
6730
+ * The same logout for every provider, without a browser window: the provider session is ended
6731
+ * where the provider allows it from the app (Keycloak: logout endpoint with the refresh token),
6732
+ * refresh and access token are revoked, the saved sign-in is removed and the app restarts. The
6733
+ * next login asks for the password. When the project requires a login, the restarted app shows
6734
+ * its loader until the sign-in window opens.
6735
+ */
6736
+ async signOut(provider, stored, storageKey, removeStored, options) {
6737
+ this.setFlag(PROMPT_LOGIN_KEY, true);
6738
+ if (provider?.clientId && (stored?.refresh_token || stored?.access_token)) {
6739
+ try {
6740
+ const discovery = await this.discover(stored?.issuer || provider.issuer);
6741
+ // Back-channel end of the session; providers without it (Okta) simply refuse - ignored.
6742
+ if (discovery.end_session_endpoint && stored?.refresh_token) {
6743
+ await this.post(discovery.end_session_endpoint, {
6744
+ client_id: provider.clientId,
6745
+ refresh_token: stored.refresh_token
6746
+ });
6747
+ }
6748
+ if (discovery.revocation_endpoint) {
6749
+ if (stored?.refresh_token) {
6750
+ await this.post(discovery.revocation_endpoint, {
6751
+ client_id: provider.clientId, token: stored.refresh_token, token_type_hint: 'refresh_token'
6752
+ });
6753
+ }
6754
+ if (stored?.access_token) {
6755
+ await this.post(discovery.revocation_endpoint, {
6756
+ client_id: provider.clientId, token: stored.access_token, token_type_hint: 'access_token'
6757
+ });
6758
+ }
6759
+ }
6760
+ }
6761
+ catch {
6762
+ console.warn('Identity provider not reachable, signing out locally');
6763
+ }
6764
+ }
6765
+ await removeStored(storageKey);
6766
+ this.setFlag(RELOGIN_KEY, options.loginRequired);
6767
+ window.location.reload();
6768
+ }
6769
+ /** Scope as the space separated string the OAuth2 plugin expects. */
6770
+ scopeOf(scope) {
6771
+ const value = Array.isArray(scope) ? scope.join(' ') : scope;
6772
+ return value?.trim() || 'openid profile email';
6773
+ }
6774
+ withOfflineAccess(scope) {
6775
+ const parts = scope.split(/\s+/).filter(Boolean);
6776
+ if (!parts.includes('offline_access')) {
6777
+ parts.push('offline_access');
6778
+ }
6779
+ return parts.join(' ');
6780
+ }
6781
+ async post(url, fields) {
6782
+ try {
6783
+ const response = await stagedRequest(signal => fetch(url, {
6784
+ method: 'POST',
6785
+ headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
6786
+ body: new URLSearchParams(fields).toString(),
6787
+ signal
6788
+ }));
6789
+ if (!response.ok) {
6790
+ console.warn('Logout request refused', response.status);
6791
+ }
6792
+ }
6793
+ catch {
6794
+ console.warn('Logout request not reachable');
6795
+ }
6796
+ }
6797
+ flag(key) {
6798
+ try {
6799
+ return localStorage.getItem(key) === '1';
6800
+ }
6801
+ catch {
6802
+ return false;
6803
+ }
6804
+ }
6805
+ setFlag(key, on) {
6806
+ try {
6807
+ on ? localStorage.setItem(key, '1') : localStorage.removeItem(key);
6808
+ }
6809
+ catch {
6810
+ // Storage not available - the flag is a convenience only.
6811
+ }
6812
+ }
6813
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.2", ngImport: i0, type: MobileOidcService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
6814
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.2", ngImport: i0, type: MobileOidcService, providedIn: 'root' });
6815
+ }
6816
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.2", ngImport: i0, type: MobileOidcService, decorators: [{
6817
+ type: Injectable,
6818
+ args: [{
6819
+ providedIn: 'root'
6820
+ }]
6821
+ }] });
6822
+
6823
+ // Faramarz Yousefian and Agent Toni (Claude Opus 5.5) 2026-10-14
6824
+ // - change: login, refresh and logout run through MobileOidcService - the same OpenID Connect flow
6825
+ // as Okta. The logout additionally revokes the tokens and makes the next login ask for the
6826
+ // password; the Keycloak session is still ended through the logout endpoint
6302
6827
  // Faramarz Yousefian and Agent Toni (Claude Opus 5.5) 2026-10-13
6303
6828
  // - change: the Keycloak requests (discovery, token refresh, logout) run under the waiting rule
6304
6829
  // - new: logout marks the restart (localStorage vl-relogin); the app shows its loader until the
@@ -6324,12 +6849,14 @@ class MobileKeycloakService {
6324
6849
  http;
6325
6850
  utilityService;
6326
6851
  platform;
6852
+ oidc;
6327
6853
  tokens = null;
6328
- constructor(config, http, utilityService, platform) {
6854
+ constructor(config, http, utilityService, platform, oidc) {
6329
6855
  this.config = config;
6330
6856
  this.http = http;
6331
6857
  this.utilityService = utilityService;
6332
6858
  this.platform = platform;
6859
+ this.oidc = oidc;
6333
6860
  if (Capacitor.isNativePlatform()) {
6334
6861
  App.addListener('appUrlOpen', async (url) => {
6335
6862
  // Nothing to do here; capacitor-oauth2 resolves internally.
@@ -6337,48 +6864,27 @@ class MobileKeycloakService {
6337
6864
  });
6338
6865
  }
6339
6866
  }
6867
+ /** The Keycloak realm as an OIDC provider, from login.mobile of the project. */
6868
+ provider() {
6869
+ const cfg = this.config.getKeycloakMobileConfig();
6870
+ return {
6871
+ issuer: cfg?.issuer,
6872
+ clientId: cfg?.clientId,
6873
+ redirectUri: cfg?.redirectUri,
6874
+ scope: cfg?.scope,
6875
+ // login.mobile.offlineAccess: the sign-in lasts as long as the app is used at least once per
6876
+ // "Offline Session Idle" (30 days in realm p5) instead of the 5 days of a normal refresh token
6877
+ offlineAccess: cfg?.offlineAccess === true
6878
+ };
6879
+ }
6340
6880
  async login() {
6341
6881
  if (!Capacitor.isNativePlatform())
6342
6882
  return null;
6343
6883
  const cfg = this.config.getKeycloakMobileConfig();
6344
- const discoveryUrl = `${cfg.issuer}/.well-known/openid-configuration`;
6345
- const discovery = await (await stagedRequest(signal => fetch(discoveryUrl, { signal }))).json();
6346
- const authenticate = (scope) => OAuth2Client.authenticate({
6347
- appId: cfg.clientId, // <--- Keycloak clientId goes here
6348
- authorizationBaseUrl: discovery.authorization_endpoint,
6349
- accessTokenEndpoint: discovery.token_endpoint,
6350
- responseType: 'code',
6351
- redirectUrl: cfg.redirectUri,
6352
- scope,
6353
- pkceEnabled: true,
6354
- logsEnabled: false
6355
- });
6356
- /*
6357
- * With login.mobile.offlineAccess the app asks for an offline token: the sign-in then lasts as
6358
- * long as the app is used at least once per "Offline Session Idle" (30 days in realm p5)
6359
- * instead of the 5 days of a normal refresh token. If Keycloak refuses the scope - role or
6360
- * client scope removed - the login is repeated without it rather than failing.
6361
- */
6362
- const offlineScope = this.withOfflineAccess(cfg.scope);
6363
- let result;
6364
- try {
6365
- result = await authenticate(cfg.offlineAccess ? offlineScope : cfg.scope);
6366
- }
6367
- catch (error) {
6368
- const cancelled = /USER_CANCELLED/i.test(String(error?.message ?? error));
6369
- if (!cfg.offlineAccess || cancelled) {
6370
- throw error;
6371
- }
6372
- console.warn('Keycloak refused offline_access, signing in without it');
6373
- result = await authenticate(cfg.scope);
6374
- }
6375
- this.tokens = {
6376
- access_token: result?.access_token_response?.access_token ? result?.access_token_response?.access_token : result.access_token,
6377
- refresh_token: result?.access_token_response?.refresh_token,
6378
- id_token: result?.access_token_response?.id_token,
6379
- expires_in: result?.access_token_response?.expires_at ? result?.access_token_response?.expires_at : result?.access_token_response?.expires_in,
6380
- token_type: result?.access_token_response?.token_type
6381
- };
6884
+ const tokens = await this.oidc.login(this.provider());
6885
+ if (!tokens)
6886
+ return '';
6887
+ this.tokens = { ...tokens };
6382
6888
  let keycloakLoginUser = "";
6383
6889
  if (this.tokens.access_token) {
6384
6890
  keycloakLoginUser = await this.getUserInfo(this.tokens.access_token, cfg.issuer);
@@ -6393,57 +6899,13 @@ class MobileKeycloakService {
6393
6899
  }
6394
6900
  return keycloakLoginUser;
6395
6901
  }
6396
- /** The configured scope plus offline_access, without duplicating it. */
6397
- withOfflineAccess(scope) {
6398
- const parts = (scope ?? 'openid').split(/\s+/).filter(Boolean);
6399
- if (!parts.includes('offline_access')) {
6400
- parts.push('offline_access');
6401
- }
6402
- return parts.join(' ');
6403
- }
6404
- /**
6405
- * New tokens from the refresh token (grant_type=refresh_token). Returns them in the stored token
6406
- * shape, or null when Keycloak refuses - then the caller falls back to the login.
6407
- */
6408
6902
  async refreshTokens(stored) {
6409
- const cfg = this.config.getKeycloakMobileConfig();
6410
- const issuer = stored?.issuer || cfg?.issuer;
6411
- if (!stored?.refresh_token || !issuer || !cfg?.clientId) {
6412
- return null;
6413
- }
6414
- try {
6415
- const discovery = await (await stagedRequest(signal => fetch(`${issuer}/.well-known/openid-configuration`, { signal }))).json();
6416
- const response = await stagedRequest(signal => fetch(discovery.token_endpoint, {
6417
- method: 'POST',
6418
- headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
6419
- body: new URLSearchParams({
6420
- grant_type: 'refresh_token',
6421
- refresh_token: stored.refresh_token,
6422
- client_id: cfg.clientId
6423
- }).toString(),
6424
- signal
6425
- }));
6426
- if (!response.ok) {
6427
- return null;
6428
- }
6429
- const result = await response.json();
6430
- if (!result?.access_token) {
6431
- return null;
6432
- }
6433
- this.tokens = {
6434
- access_token: result.access_token,
6435
- refresh_token: result.refresh_token ?? stored.refresh_token,
6436
- id_token: result.id_token ?? stored.id_token,
6437
- expires_in: result.expires_in,
6438
- token_type: result.token_type,
6439
- issuer
6440
- };
6441
- return this.tokens;
6442
- }
6443
- catch (error) {
6444
- console.warn('Keycloak token refresh failed');
6903
+ const result = await this.oidc.refresh(this.provider(), stored);
6904
+ if (!result || result === 'refused') {
6445
6905
  return null;
6446
6906
  }
6907
+ this.tokens = { ...result, issuer: stored?.issuer || result.issuer };
6908
+ return this.tokens;
6447
6909
  }
6448
6910
  async getUserInfo(accessToken, issuer) {
6449
6911
  try {
@@ -6472,37 +6934,12 @@ class MobileKeycloakService {
6472
6934
  */
6473
6935
  async logout() {
6474
6936
  const keycloakInfo = await this.utilityService.getLocalStorage('KeycloakInfo');
6475
- const cfg = this.config.getKeycloakMobileConfig();
6476
- const issuer = keycloakInfo?.issuer || cfg?.issuer;
6477
- const refreshToken = keycloakInfo?.refresh_token ?? keycloakInfo?.keycloakInfo?.refresh_token;
6478
- if (issuer && cfg?.clientId && refreshToken) {
6479
- try {
6480
- const response = await stagedRequest(signal => fetch(`${issuer}/protocol/openid-connect/logout`, {
6481
- method: 'POST',
6482
- headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
6483
- body: new URLSearchParams({ client_id: cfg.clientId, refresh_token: refreshToken }).toString(),
6484
- signal
6485
- }));
6486
- if (!response.ok) {
6487
- console.warn('Keycloak logout refused', response.status);
6488
- }
6489
- }
6490
- catch {
6491
- console.warn('Keycloak logout not reachable, signing out locally');
6492
- }
6493
- }
6937
+ const tokens = keycloakInfo?.keycloakInfo ?? keycloakInfo;
6494
6938
  this.tokens = null;
6495
- await this.utilityService.removeLocalStorage('KeycloakInfo');
6496
- // The restarted app shows its loader until the sign-in window opens (white screen otherwise).
6497
- try {
6498
- localStorage.setItem('vl-relogin', '1');
6499
- }
6500
- catch {
6501
- // Storage not available - the app starts without the loader.
6502
- }
6503
- window.location.reload();
6939
+ // Keycloak projects require a login: the restarted app shows its loader until the sign-in opens.
6940
+ await this.oidc.signOut(this.provider(), tokens, 'KeycloakInfo', key => this.utilityService.removeLocalStorage(key), { loginRequired: true });
6504
6941
  }
6505
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.2", ngImport: i0, type: MobileKeycloakService, deps: [{ token: ConfigService }, { token: i1$1.HttpClient }, { token: UtilityService }, { token: i1.Platform }], target: i0.ɵɵFactoryTarget.Injectable });
6942
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.2", ngImport: i0, type: MobileKeycloakService, deps: [{ token: ConfigService }, { token: i1$1.HttpClient }, { token: UtilityService }, { token: i1.Platform }, { token: MobileOidcService }], target: i0.ɵɵFactoryTarget.Injectable });
6506
6943
  static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.2", ngImport: i0, type: MobileKeycloakService, providedIn: 'root' });
6507
6944
  }
6508
6945
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.2", ngImport: i0, type: MobileKeycloakService, decorators: [{
@@ -6510,7 +6947,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.2", ngImpor
6510
6947
  args: [{
6511
6948
  providedIn: 'root'
6512
6949
  }]
6513
- }], ctorParameters: () => [{ type: ConfigService }, { type: i1$1.HttpClient }, { type: UtilityService }, { type: i1.Platform }] });
6950
+ }], ctorParameters: () => [{ type: ConfigService }, { type: i1$1.HttpClient }, { type: UtilityService }, { type: i1.Platform }, { type: MobileOidcService }] });
6514
6951
 
6515
6952
  // Faramarz Yousefian and Agent Toni (Claude Opus 5.5) 2026-10-13
6516
6953
  // - new: activeLanguage, the language file in use ("de.json"); its menu entry gets a check mark
@@ -7331,7 +7768,7 @@ class SideMenuComponent {
7331
7768
  });
7332
7769
  }
7333
7770
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.2", ngImport: i0, type: SideMenuComponent, deps: [{ token: i1$4.NzI18nService }, { token: MobileKeycloakService }, { token: Couchdb }, { token: i7.OAuthService }, { token: i1.Platform }, { token: RequestService }, { token: UtilityService }, { token: i1$3.DialogService }, { token: NotificationService }, { token: i0.Injector }], target: i0.ɵɵFactoryTarget.Component });
7334
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.2", type: SideMenuComponent, isStandalone: true, selector: "vl-side-menu", inputs: { menuItems: "menuItems", userInfo: "userInfo", settings: "settings", projects: "projects", tenantName: "tenantName", environment: "environment", projectSeleted: "projectSeleted", appVersionInfo: "appVersionInfo" }, outputs: { languageChange: "languageChange", invokeMenu: "invokeMenu", menuToggle: "menuToggle", invokeProject: "invokeProject", errorMessage: "errorMessage", deleteProject: "deleteProject", paginationType: "paginationType" }, host: { listeners: { "window:resize": "onResizeMobileMode()", "document:click": "onDocumentClick($event)" }, properties: { "class.sidemenu-mobile": "this.mobileMode" } }, viewQueries: [{ propertyName: "sideMenu", first: true, predicate: ["sideMenu"], descendants: true, static: true }], usesOnChanges: true, ngImport: i0, template: "<!-- Faramarz Yousefian and Agent Toni (Claude Opus 5.5) 2026-10-13\r\n - new: the active language has a check mark, like the active pagination type\r\n - fix: all check marks (pagination, language) stand in one column at the right edge; the\r\n pagination marks followed their caption at a fixed distance and landed elsewhere on iOS\r\n - change: the version footer has three columns - version, build (source commit) and build\r\n number (appBuildNumber), the three values build.sh and the web Docker build produce -->\r\n<!-- Shuaib 2026-09-24\r\n - change: sign-in visibility checks now include jwtToken alongside keycloak and oktaAuth. -->\r\n<!-- Faramarz Yousefian and Agent Toni (Claude Opus 5) 2026-09-19\r\n - new: a @contract comment on the option key, singular since 2026-09-16, and on the sign-in\r\n branches, which know keycloak and oktaAuth but not jwtToken -->\r\n<div class=\"left-wrap sidemenu\" [class.collapsed]=\"isCollapsed\"\r\n [ngStyle]=\"{ 'z-index': !isCollapsed && isMobile ? 999999 : 'auto' }\"\r\n #sideMenu>\r\n <!-- Move toggle button OUTSIDE menu container -->\r\n <div class=\"side-toggle-handle\" id=\"toggle-id\" (click)=\"toggleCollapsed()\"\r\n [class.collapsed]=\"isCollapsed\">\r\n <span id=\"toggle-icon\" nz-icon\r\n [nzType]=\"isCollapsed ? 'caret-right' : 'caret-left'\"></span>\r\n </div>\r\n <div class=\"side-menu\" id=\"sidemenuwrap\"\r\n [ngStyle]=\"{ width: (isMobile && isCollapsed) ? '1px' : isCollapsed ? '60px' : '' }\">\r\n <!-- user content -->\r\n <ng-container *ngIf=\"loginedUserInfo && loginedUserInfo?.name\">\r\n <div class=\"user-profile\" [class.collapsed]=\"isCollapsed\">\r\n <img class=\"avatar\" [src]=\"loginedUserInfo?.image\" alt=\"User\" />\r\n <div [class]=\"isMobile ? '' : 'details'\" *ngIf=\"!isCollapsed\">\r\n <div class=\"name\">{{ loginedUserInfo.name }}</div>\r\n <div class=\"email\">{{ loginedUserInfo?.email }}</div>\r\n <div class=\"actions\" *ngIf=\"loginedUserInfo?.actions?.length\">\r\n <button *ngFor=\"let action of loginedUserInfo?.actions\" nz-button\r\n nzType=\"link\" nzSize=\"small\"\r\n (click)=\"invokeNavigate(action)\">\r\n <span>{{ action?.label?.caption }}</span>\r\n <span nz-icon [nzType]=\"action.icon\"></span>\r\n </button>\r\n </div>\r\n </div>\r\n </div>\r\n </ng-container>\r\n <!-- @contract decision: this container reads option (singular), like every other one\r\n reality: it read options (plural) until 2026-09-16. A menu file written for the old\r\n spelling is ignored without an error.\r\n\r\n @contract decision: sign-in visibility supports keycloak, oktaAuth and jwtToken.\r\n A JWT project uses the decoded user's login state, like the other providers.\r\n seen: the login type comparisons in the lines below -->\r\n <!-- dynamic menu -->\r\n <ul nz-menu nzMode=\"inline\" nzTheme=\"dark\"\r\n [nzInlineCollapsed]=\"isCollapsed\">\r\n <ng-container *ngFor=\"let item of menuItems\">\r\n <ng-container\r\n *ngIf=\"!item.submenu && item?.option?.action != 'logout'; else submenu\">\r\n <span\r\n [class]=\"environment?.login?.type === 'oktaAuth' || environment?.login?.type === 'keycloak' || environment?.login?.type === 'jwtToken' ? item.option?.login === true ? loginedUserInfo?.name ? '' : 'hidden' : item.option?.login === false ? loginedUserInfo?.name ? 'hidden' : '' : '' : userInfo?.userId ? item.option?.login ? item.option.role ? item.option.role == userInfo.userRole ? '' : 'hidden' : '' : 'hidden' : !item.option?.login ? '' : 'hidden' \">\r\n <li (click)=\"invokeNavigate(item)\" nz-menu-item nz-tooltip\r\n nzTooltipPlacement=\"right\"\r\n [nzTooltipTitle]=\"isCollapsed && !isMobile ? item?.label?.caption : ''\">\r\n <span nz-icon [nzType]=\"item.icon\"></span>\r\n <span>{{ item?.label?.caption }}</span>\r\n </li>\r\n </span>\r\n </ng-container>\r\n <ng-template #submenu>\r\n <span\r\n [class]=\"item.option?.login === true && (environment?.login?.type === 'oktaAuth' || environment?.login?.type === 'keycloak' || environment?.login?.type === 'jwtToken') ? loginedUserInfo?.name ? '' : 'hidden' : item.option?.login === false ? loginedUserInfo?.name ? 'hidden' : '' : ''\">\r\n <li nz-submenu *ngIf=\"item?.option?.action != 'logout'\"\r\n [nzTitle]=\"item?.label?.caption\"\r\n [nzIcon]=\"item.icon\">\r\n <ul>\r\n <ng-container *ngFor=\"let child of item.submenu\">\r\n <li (click)=\"invokeNavigate(child)\" *ngIf=\"!child.submenu\"\r\n nz-menu-item nz-tooltip\r\n nzTooltipPlacement=\"right\"\r\n [nzTooltipTitle]=\"isCollapsed && !isMobile ? child?.label?.caption : ''\">\r\n <span nz-icon [nzType]=\"child?.icon\"></span>\r\n <span>{{ child?.label?.caption }}</span>\r\n </li>\r\n <ng-container *ngIf=\"child.submenu\">\r\n <li nz-submenu [nzTitle]=\"child?.label?.caption\"\r\n [nzIcon]=\"child?.icon\">\r\n <ul>\r\n <ng-container *ngFor=\"let subChild of child.submenu\">\r\n <li (click)=\"invokeNavigate(subChild)\" nz-menu-item>\r\n <ng-container\r\n *ngIf=\"subChild?.option?.setImageUrl; else antIcon\">\r\n <img *ngIf=\"isUrl(subChild?.icon)\"\r\n [src]=\"subChild?.icon\" alt=\"icon\"\r\n style=\"width: 16px; height: 16px; margin-right: 8px;\" />\r\n </ng-container>\r\n <ng-template #antIcon>\r\n <span nz-icon [nzType]=\"subChild?.icon\"></span>\r\n </ng-template>\r\n <span>{{ subChild?.label?.caption }}</span>\r\n @if(subChild?.option?.numberedPagination &&\r\n !scrollPagination){\r\n <span nz-icon\r\n nzType=\"check\" nzTheme=\"outline\"\r\n class=\"pagination-check\">\r\n </span>\r\n }\r\n @if(subChild?.option?.scrollPagination &&\r\n scrollPagination){\r\n <span nz-icon\r\n nzType=\"check\" nzTheme=\"outline\"\r\n class=\"pagination-check\">\r\n </span>\r\n }\r\n @if(subChild?.option?.changeLang &&\r\n subChild?.option?.data_url === activeLanguage){\r\n <span nz-icon nzType=\"check\" nzTheme=\"outline\"\r\n class=\"pagination-check\">\r\n </span>\r\n }\r\n </li>\r\n </ng-container>\r\n </ul>\r\n </li>\r\n </ng-container>\r\n </ng-container>\r\n </ul>\r\n </li>\r\n </span>\r\n </ng-template>\r\n </ng-container>\r\n\r\n <!-- separator -->\r\n <li *ngIf=\"settingMenu.submenu\" class=\"menu-separator\"></li>\r\n\r\n <!-- settings menu -->\r\n <ng-container *ngIf=\"!settingMenu.submenu; else settingSubmenu\"\r\n style=\"position: absolute; bottom: 0;\">\r\n <li (click)=\"invokeNavigate(settingMenu)\" nz-menu-item nz-tooltip\r\n nzTooltipPlacement=\"right\"\r\n [nzTooltipTitle]=\"isCollapsed && !isMobile ? settingMenu?.label?.caption : ''\">\r\n <span nz-icon [nzType]=\"settingMenu.icon\"></span>\r\n <span>{{ settingMenu?.label?.caption }}</span>\r\n </li>\r\n </ng-container>\r\n <ng-template #settingSubmenu>\r\n <li nz-submenu [nzTitle]=\"settingMenu?.label?.caption\"\r\n [nzIcon]=\"settingMenu.icon\">\r\n <ul>\r\n <ng-container *ngFor=\"let child of settingMenu.submenu\">\r\n <li (click)=\"invokeNavigate(child)\" *ngIf=\"!child.submenu\"\r\n nz-menu-item nz-tooltip\r\n nzTooltipPlacement=\"right\"\r\n [nzTooltipTitle]=\"isCollapsed && !isMobile ? child?.label?.caption : ''\">\r\n <span nz-icon [nzType]=\"child?.icon\"></span>\r\n <span>{{ child?.label?.caption }}</span>\r\n </li>\r\n <ng-container *ngIf=\"child.submenu\">\r\n <li nz-submenu [nzTitle]=\"child?.label?.caption\"\r\n [nzIcon]=\"child?.icon\">\r\n <ul style=\"width: 260px;\">\r\n <ng-container\r\n *ngFor=\"let subChild of child.submenu; let i = index\">\r\n <li (click)=\"invokeNavigate(subChild, child)\"\r\n nz-menu-item>\r\n <span\r\n [class]=\"child?.label?.caption === 'Languages' ? '' : 'menu-row'\">\r\n <ng-container\r\n *ngIf=\"subChild?.option?.changeProject; else antIcon\">\r\n <img [src]=\"subChild?.icon\" alt=\"icon\"\r\n style=\"width: 16px; height: 16px; margin-right: 8px;\" />\r\n </ng-container>\r\n <ng-template #antIcon>\r\n <span nz-icon [nzType]=\"subChild?.icon\"></span>\r\n </ng-template>\r\n <span>{{ subChild?.label?.caption }}</span>\r\n <!-- Delete icon (prevent click bubbling) -->\r\n <span *ngIf=\"child?.label?.caption != 'Languages'\"\r\n nz-icon nzType=\"delete\" class=\"delete-icon\"\r\n style=\"padding-left: 5%;\"\r\n (click)=\"deleteMenuItem(subChild, i, $event)\"></span>\r\n </span>\r\n </li>\r\n </ng-container>\r\n </ul>\r\n </li>\r\n </ng-container>\r\n </ng-container>\r\n </ul>\r\n </li>\r\n </ng-template>\r\n </ul>\r\n @if (!isCollapsed && appVersionInfo?.appVersion) {\r\n <div class=\"app-version-footer\">\r\n <div class=\"app-version-footer__item\">\r\n <span class=\"app-version-footer__label\">Version</span>\r\n <span class=\"app-version-footer__value\">{{ appVersionInfo.appVersion }}</span>\r\n </div>\r\n <div class=\"app-version-footer__item\">\r\n <span class=\"app-version-footer__label\">Build</span>\r\n <span class=\"app-version-footer__value\">{{ appVersionInfo.appBuild || '-' }}</span>\r\n </div>\r\n <div class=\"app-version-footer__item\">\r\n <span class=\"app-version-footer__label\">Build No.</span>\r\n <span class=\"app-version-footer__value\">{{ appVersionInfo.appBuildNumber || '-' }}</span>\r\n </div>\r\n </div>\r\n }\r\n </div>\r\n</div>\r\n", styles: [":host{position:relative;display:block;flex:0 0 auto;width:250px;height:100%;min-height:0;overflow:visible;transition:width .3s ease}.left-wrap.sidemenu{position:relative;width:250px;height:100%;min-height:0;overflow:visible;transition:width .3s ease,transform .3s ease}.side-menu{position:relative;display:flex;flex-direction:column;width:250px;height:100%;min-height:0;color:#fff;background-color:#0d1b2a;overflow:hidden;transition:width .3s ease,box-shadow .3s ease}:host:has(.left-wrap.sidemenu.collapsed){width:64px}.left-wrap.sidemenu.collapsed,.left-wrap.sidemenu.collapsed .side-menu{width:64px}.menu-separator{flex:0 0 auto;height:1px;margin:15px 12px 6px;background-color:#ffffff26;border:0;list-style:none}.user-profile{flex:0 0 auto;padding:20px 10px 16px;margin-top:40px;text-align:center;border-bottom:1px solid rgba(255,255,255,.1);overflow:hidden;transition:padding .25s ease,margin .25s ease,opacity .25s ease,max-height .25s ease}.user-profile .avatar{display:block;width:64px;height:64px;margin:0 auto 8px;object-fit:cover;border:2px solid #ffffff;border-radius:50%;transition:width .25s ease,height .25s ease,margin .25s ease}.user-profile .details{min-width:0;overflow:hidden;transition:opacity .2s ease}.user-profile .name{color:#fff;font-size:14px;font-weight:600;line-height:1.4;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.user-profile .email{margin:2px 0 8px;color:#aaa;font-size:12px;line-height:1.4;overflow-wrap:anywhere;word-break:break-word}.user-profile .actions{display:flex;align-items:center;justify-content:center;gap:6px}.user-profile .actions button{margin:0;color:#fff}.left-wrap.sidemenu.collapsed .user-profile{padding:12px 8px}.left-wrap.sidemenu.collapsed .user-profile .avatar{width:40px;height:40px;margin-bottom:0}.left-wrap.sidemenu.collapsed .user-profile .details,.left-wrap.sidemenu.collapsed .user-profile .name,.left-wrap.sidemenu.collapsed .user-profile .email,.left-wrap.sidemenu.collapsed .user-profile .actions{display:none}.side-menu ul[nz-menu]{flex:1 1 auto;width:100%;min-height:0;margin:0;padding:4px 0 8px;overflow-x:hidden;overflow-y:auto;background-color:transparent;scrollbar-width:thin;scrollbar-color:rgba(255,255,255,.28) transparent;scroll-behavior:smooth}.side-menu ul[nz-menu]::-webkit-scrollbar{width:6px}.side-menu ul[nz-menu]::-webkit-scrollbar-track{background:transparent}.side-menu ul[nz-menu]::-webkit-scrollbar-thumb{background-color:#ffffff47;border-radius:999px}.side-menu ul[nz-menu]::-webkit-scrollbar-thumb:hover{background-color:#ffffff6b}.menu-row{display:flex;align-items:center;width:100%;min-width:0}.menu-text{flex:1 1 auto;min-width:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.delete-icon{flex:0 0 auto;margin-left:auto;color:#ffffffb3;cursor:pointer;transition:color .18s ease,transform .18s ease}.delete-icon:hover{color:#ff7875;transform:scale(1.08)}.projects{position:static;flex:0 0 auto;width:100%;margin-top:auto;background-color:#0d1b2a}.side-toggle-handle{position:absolute;top:24px;right:-14px;z-index:10000;display:flex;align-items:center;justify-content:center;width:28px;height:48px;padding:0;color:#fff;background-color:#0d1b2a;border:0;border-radius:0 6px 6px 0;box-shadow:2px 0 6px #00000040;cursor:pointer;transform:translateY(-50%);transition:background-color .2s ease,box-shadow .2s ease}.side-toggle-handle:hover{background-color:#142a40;box-shadow:3px 0 9px #0000004d}.side-toggle-handle:focus-visible{outline:3px solid rgba(24,144,255,.45);outline-offset:2px}.side-toggle-handle span{color:#fff;font-size:14px;line-height:1;transition:transform .25s ease}.collapse-btn{position:absolute;top:8px;right:8px;z-index:10001}:host(:not(.sidemenu-mobile)) .left-wrap.sidemenu.collapsed:hover{transform:translate(0)}:host(:not(.sidemenu-mobile)) ::ng-deep .ant-menu.ant-menu-inline-collapsed{width:64px!important}:host(:not(.sidemenu-mobile)) ::ng-deep .ant-menu.ant-menu-inline-collapsed>.ant-menu-item,:host(:not(.sidemenu-mobile)) ::ng-deep .ant-menu.ant-menu-inline-collapsed>.ant-menu-submenu>.ant-menu-submenu-title,:host(:not(.sidemenu-mobile)) ::ng-deep .ant-menu.ant-menu-inline-collapsed>.ant-menu-item-group>.ant-menu-item-group-list>.ant-menu-item,:host(:not(.sidemenu-mobile)) ::ng-deep .ant-menu.ant-menu-inline-collapsed>.ant-menu-item-group>.ant-menu-item-group-list>.ant-menu-submenu>.ant-menu-submenu-title{display:flex!important;align-items:center!important;justify-content:center!important;width:45px!important;height:32px!important;margin-inline:0!important;padding-inline:0!important;overflow:hidden!important}:host(:not(.sidemenu-mobile)) ::ng-deep .ant-menu.ant-menu-inline-collapsed .ant-menu-title-content,:host(:not(.sidemenu-mobile)) ::ng-deep .ant-menu.ant-menu-inline-collapsed .menu-text,:host(:not(.sidemenu-mobile)) ::ng-deep .ant-menu.ant-menu-inline-collapsed .delete-icon,:host(:not(.sidemenu-mobile)) ::ng-deep .ant-menu.ant-menu-inline-collapsed .ant-menu-submenu-arrow{display:none!important;width:0!important;min-width:0!important;max-width:0!important;margin:0!important;padding:0!important;visibility:hidden!important;overflow:hidden!important;text-overflow:clip!important}:host(:not(.sidemenu-mobile)) ::ng-deep .ant-menu.ant-menu-inline-collapsed .ant-menu-item-icon,:host(:not(.sidemenu-mobile)) ::ng-deep .ant-menu.ant-menu-inline-collapsed>.ant-menu-item>.anticon,:host(:not(.sidemenu-mobile)) ::ng-deep .ant-menu.ant-menu-inline-collapsed>.ant-menu-submenu>.ant-menu-submenu-title>.anticon{display:inline-flex!important;flex:0 0 auto;align-items:center;justify-content:center;width:auto!important;min-width:18px;margin:0!important;padding:0!important;color:inherit;font-size:18px;line-height:1;visibility:visible!important}:host(:not(.sidemenu-mobile)) ::ng-deep .ant-menu.ant-menu-inline-collapsed .menu-row{display:contents}:host(.sidemenu-mobile){position:absolute;top:0;bottom:0;left:0;z-index:9999;width:250px;height:100%}:host(.sidemenu-mobile):has(.left-wrap.sidemenu.collapsed){width:0}:host(.sidemenu-mobile) .left-wrap.sidemenu{width:250px;height:100%}:host(.sidemenu-mobile) .side-menu,:host(.sidemenu-mobile) .side-menu.open{width:250px;height:100%;box-shadow:8px 0 22px #0000003d}:host(.sidemenu-mobile) .left-wrap.sidemenu.collapsed{width:250px;transform:translate(-250px)}:host(.sidemenu-mobile) .left-wrap.sidemenu.collapsed .side-menu{width:250px;box-shadow:none}:host(.sidemenu-mobile) .left-wrap.sidemenu.collapsed .side-toggle-handle{right:-28px}:host(.sidemenu-mobile) .side-toggle-handle{top:0;right:0;padding:0;transform:none!important}:host(.sidemenu-mobile) .collapse-btn{top:8px;right:8px}:host(.sidemenu-mobile) .user-profile{margin-top:40px}:host(.sidemenu-mobile) .user-profile .avatar{width:48px;height:48px}:host(.sidemenu-mobile) .left-wrap.sidemenu.collapsed .user-profile{max-height:0;padding:0;margin:0;opacity:0;overflow:hidden;border-bottom:0}@media(prefers-reduced-motion:reduce){:host,.left-wrap.sidemenu,.side-menu,.user-profile,.user-profile .avatar,.side-toggle-handle,.side-toggle-handle span{transition:none}.side-menu ul[nz-menu]{scroll-behavior:auto}}.app-version-footer{flex-shrink:0;display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:6px;padding:10px 12px;border-top:1px solid rgba(255,255,255,.15);color:#ffffffa6;font-size:11px;line-height:1.4;text-align:center}.app-version-footer__item{display:flex;flex-direction:column;min-width:0}.app-version-footer__label{font-size:10px;opacity:.7}.app-version-footer__value{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.pagination-check{position:absolute;top:50%;right:42px;transform:translateY(-50%)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i5.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i5.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i5.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "ngmodule", type: PlatformModule }, { kind: "ngmodule", type:
7771
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.2", type: SideMenuComponent, isStandalone: true, selector: "vl-side-menu", inputs: { menuItems: "menuItems", userInfo: "userInfo", settings: "settings", projects: "projects", tenantName: "tenantName", environment: "environment", projectSeleted: "projectSeleted", appVersionInfo: "appVersionInfo" }, outputs: { languageChange: "languageChange", invokeMenu: "invokeMenu", menuToggle: "menuToggle", invokeProject: "invokeProject", errorMessage: "errorMessage", deleteProject: "deleteProject", paginationType: "paginationType" }, host: { listeners: { "window:resize": "onResizeMobileMode()", "document:click": "onDocumentClick($event)" }, properties: { "class.sidemenu-mobile": "this.mobileMode" } }, viewQueries: [{ propertyName: "sideMenu", first: true, predicate: ["sideMenu"], descendants: true, static: true }], usesOnChanges: true, ngImport: i0, template: "<!-- Faramarz Yousefian and Agent Toni (Claude Opus 5.5) 2026-10-13\r\n - new: the active language has a check mark, like the active pagination type\r\n - fix: all check marks (pagination, language) stand in one column at the right edge; the\r\n pagination marks followed their caption at a fixed distance and landed elsewhere on iOS\r\n - change: the version footer has three columns - version, build (source commit) and build\r\n number (appBuildNumber), the three values build.sh and the web Docker build produce -->\r\n<!-- Shuaib 2026-09-24\r\n - change: sign-in visibility checks now include jwtToken alongside keycloak and oktaAuth. -->\r\n<!-- Faramarz Yousefian and Agent Toni (Claude Opus 5) 2026-09-19\r\n - new: a @contract comment on the option key, singular since 2026-09-16, and on the sign-in\r\n branches, which know keycloak and oktaAuth but not jwtToken -->\r\n<div class=\"left-wrap sidemenu\" [class.collapsed]=\"isCollapsed\"\r\n [ngStyle]=\"{ 'z-index': !isCollapsed && isMobile ? 999999 : 'auto' }\"\r\n #sideMenu>\r\n <!-- Move toggle button OUTSIDE menu container -->\r\n <div class=\"side-toggle-handle\" id=\"toggle-id\" (click)=\"toggleCollapsed()\"\r\n [class.collapsed]=\"isCollapsed\">\r\n <span id=\"toggle-icon\" nz-icon\r\n [nzType]=\"isCollapsed ? 'caret-right' : 'caret-left'\"></span>\r\n </div>\r\n <div class=\"side-menu\" id=\"sidemenuwrap\"\r\n [ngStyle]=\"{ width: (isMobile && isCollapsed) ? '1px' : isCollapsed ? '60px' : '' }\">\r\n <!-- user content -->\r\n <ng-container *ngIf=\"loginedUserInfo && loginedUserInfo?.name\">\r\n <div class=\"user-profile\" [class.collapsed]=\"isCollapsed\">\r\n <img class=\"avatar\" [src]=\"loginedUserInfo?.image\" alt=\"User\" />\r\n <div [class]=\"isMobile ? '' : 'details'\" *ngIf=\"!isCollapsed\">\r\n <div class=\"name\">{{ loginedUserInfo.name }}</div>\r\n <div class=\"email\">{{ loginedUserInfo?.email }}</div>\r\n <div class=\"actions\" *ngIf=\"loginedUserInfo?.actions?.length\">\r\n <button *ngFor=\"let action of loginedUserInfo?.actions\" nz-button\r\n nzType=\"link\" nzSize=\"small\"\r\n (click)=\"invokeNavigate(action)\">\r\n <span>{{ action?.label?.caption }}</span>\r\n <span nz-icon [nzType]=\"action.icon\"></span>\r\n </button>\r\n </div>\r\n </div>\r\n </div>\r\n </ng-container>\r\n <!-- @contract decision: this container reads option (singular), like every other one\r\n reality: it read options (plural) until 2026-09-16. A menu file written for the old\r\n spelling is ignored without an error.\r\n\r\n @contract decision: sign-in visibility supports keycloak, oktaAuth and jwtToken.\r\n A JWT project uses the decoded user's login state, like the other providers.\r\n seen: the login type comparisons in the lines below -->\r\n <!-- dynamic menu -->\r\n <ul nz-menu nzMode=\"inline\" nzTheme=\"dark\"\r\n [nzInlineCollapsed]=\"isCollapsed\">\r\n <ng-container *ngFor=\"let item of menuItems\">\r\n <ng-container\r\n *ngIf=\"!item.submenu && item?.option?.action != 'logout'; else submenu\">\r\n <span\r\n [class]=\"environment?.login?.type === 'oktaAuth' || environment?.login?.type === 'keycloak' || environment?.login?.type === 'jwtToken' ? item.option?.login === true ? loginedUserInfo?.name ? '' : 'hidden' : item.option?.login === false ? loginedUserInfo?.name ? 'hidden' : '' : '' : userInfo?.userId ? item.option?.login ? item.option.role ? item.option.role == userInfo.userRole ? '' : 'hidden' : '' : 'hidden' : !item.option?.login ? '' : 'hidden' \">\r\n <li (click)=\"invokeNavigate(item)\" nz-menu-item nz-tooltip\r\n nzTooltipPlacement=\"right\"\r\n [nzTooltipTitle]=\"isCollapsed && !isMobile ? item?.label?.caption : ''\">\r\n <span nz-icon [nzType]=\"item.icon\"></span>\r\n <span>{{ item?.label?.caption }}</span>\r\n </li>\r\n </span>\r\n </ng-container>\r\n <ng-template #submenu>\r\n <span\r\n [class]=\"item.option?.login === true && (environment?.login?.type === 'oktaAuth' || environment?.login?.type === 'keycloak' || environment?.login?.type === 'jwtToken') ? loginedUserInfo?.name ? '' : 'hidden' : item.option?.login === false ? loginedUserInfo?.name ? 'hidden' : '' : ''\">\r\n <li nz-submenu *ngIf=\"item?.option?.action != 'logout'\"\r\n [nzTitle]=\"item?.label?.caption\"\r\n [nzIcon]=\"item.icon\">\r\n <ul>\r\n <ng-container *ngFor=\"let child of item.submenu\">\r\n <li (click)=\"invokeNavigate(child)\" *ngIf=\"!child.submenu\"\r\n nz-menu-item nz-tooltip\r\n nzTooltipPlacement=\"right\"\r\n [nzTooltipTitle]=\"isCollapsed && !isMobile ? child?.label?.caption : ''\">\r\n <span nz-icon [nzType]=\"child?.icon\"></span>\r\n <span>{{ child?.label?.caption }}</span>\r\n </li>\r\n <ng-container *ngIf=\"child.submenu\">\r\n <li nz-submenu [nzTitle]=\"child?.label?.caption\"\r\n [nzIcon]=\"child?.icon\">\r\n <ul>\r\n <ng-container *ngFor=\"let subChild of child.submenu\">\r\n <li (click)=\"invokeNavigate(subChild)\" nz-menu-item>\r\n <ng-container\r\n *ngIf=\"subChild?.option?.setImageUrl; else antIcon\">\r\n <img *ngIf=\"isUrl(subChild?.icon)\"\r\n [src]=\"subChild?.icon\" alt=\"icon\"\r\n style=\"width: 16px; height: 16px; margin-right: 8px;\" />\r\n </ng-container>\r\n <ng-template #antIcon>\r\n <span nz-icon [nzType]=\"subChild?.icon\"></span>\r\n </ng-template>\r\n <span>{{ subChild?.label?.caption }}</span>\r\n @if(subChild?.option?.numberedPagination &&\r\n !scrollPagination){\r\n <span nz-icon\r\n nzType=\"check\" nzTheme=\"outline\"\r\n class=\"pagination-check\">\r\n </span>\r\n }\r\n @if(subChild?.option?.scrollPagination &&\r\n scrollPagination){\r\n <span nz-icon\r\n nzType=\"check\" nzTheme=\"outline\"\r\n class=\"pagination-check\">\r\n </span>\r\n }\r\n @if(subChild?.option?.changeLang &&\r\n subChild?.option?.data_url === activeLanguage){\r\n <span nz-icon nzType=\"check\" nzTheme=\"outline\"\r\n class=\"pagination-check\">\r\n </span>\r\n }\r\n </li>\r\n </ng-container>\r\n </ul>\r\n </li>\r\n </ng-container>\r\n </ng-container>\r\n </ul>\r\n </li>\r\n </span>\r\n </ng-template>\r\n </ng-container>\r\n\r\n <!-- separator -->\r\n <li *ngIf=\"settingMenu.submenu\" class=\"menu-separator\"></li>\r\n\r\n <!-- settings menu -->\r\n <ng-container *ngIf=\"!settingMenu.submenu; else settingSubmenu\"\r\n style=\"position: absolute; bottom: 0;\">\r\n <li (click)=\"invokeNavigate(settingMenu)\" nz-menu-item nz-tooltip\r\n nzTooltipPlacement=\"right\"\r\n [nzTooltipTitle]=\"isCollapsed && !isMobile ? settingMenu?.label?.caption : ''\">\r\n <span nz-icon [nzType]=\"settingMenu.icon\"></span>\r\n <span>{{ settingMenu?.label?.caption }}</span>\r\n </li>\r\n </ng-container>\r\n <ng-template #settingSubmenu>\r\n <li nz-submenu [nzTitle]=\"settingMenu?.label?.caption\"\r\n [nzIcon]=\"settingMenu.icon\">\r\n <ul>\r\n <ng-container *ngFor=\"let child of settingMenu.submenu\">\r\n <li (click)=\"invokeNavigate(child)\" *ngIf=\"!child.submenu\"\r\n nz-menu-item nz-tooltip\r\n nzTooltipPlacement=\"right\"\r\n [nzTooltipTitle]=\"isCollapsed && !isMobile ? child?.label?.caption : ''\">\r\n <span nz-icon [nzType]=\"child?.icon\"></span>\r\n <span>{{ child?.label?.caption }}</span>\r\n </li>\r\n <ng-container *ngIf=\"child.submenu\">\r\n <li nz-submenu [nzTitle]=\"child?.label?.caption\"\r\n [nzIcon]=\"child?.icon\">\r\n <ul style=\"width: 260px;\">\r\n <ng-container\r\n *ngFor=\"let subChild of child.submenu; let i = index\">\r\n <li (click)=\"invokeNavigate(subChild, child)\"\r\n nz-menu-item>\r\n <span\r\n [class]=\"child?.label?.caption === 'Languages' ? '' : 'menu-row'\">\r\n <ng-container\r\n *ngIf=\"subChild?.option?.changeProject; else antIcon\">\r\n <img [src]=\"subChild?.icon\" alt=\"icon\"\r\n style=\"width: 16px; height: 16px; margin-right: 8px;\" />\r\n </ng-container>\r\n <ng-template #antIcon>\r\n <span nz-icon [nzType]=\"subChild?.icon\"></span>\r\n </ng-template>\r\n <span>{{ subChild?.label?.caption }}</span>\r\n <!-- Delete icon (prevent click bubbling) -->\r\n <span *ngIf=\"child?.label?.caption != 'Languages'\"\r\n nz-icon nzType=\"delete\" class=\"delete-icon\"\r\n style=\"padding-left: 5%;\"\r\n (click)=\"deleteMenuItem(subChild, i, $event)\"></span>\r\n </span>\r\n </li>\r\n </ng-container>\r\n </ul>\r\n </li>\r\n </ng-container>\r\n </ng-container>\r\n </ul>\r\n </li>\r\n </ng-template>\r\n </ul>\r\n @if (!isCollapsed && appVersionInfo?.appVersion) {\r\n <div class=\"app-version-footer\">\r\n <div class=\"app-version-footer__item\">\r\n <span class=\"app-version-footer__label\">Version</span>\r\n <span class=\"app-version-footer__value\">{{ appVersionInfo.appVersion }}</span>\r\n </div>\r\n <div class=\"app-version-footer__item\">\r\n <span class=\"app-version-footer__label\">Build</span>\r\n <span class=\"app-version-footer__value\">{{ appVersionInfo.appBuild || '-' }}</span>\r\n </div>\r\n <div class=\"app-version-footer__item\">\r\n <span class=\"app-version-footer__label\">Build No.</span>\r\n <span class=\"app-version-footer__value\">{{ appVersionInfo.appBuildNumber || '-' }}</span>\r\n </div>\r\n </div>\r\n }\r\n </div>\r\n</div>\r\n", styles: [":host{position:relative;display:block;flex:0 0 auto;width:250px;height:100%;min-height:0;overflow:visible;transition:width .3s ease}.left-wrap.sidemenu{position:relative;width:250px;height:100%;min-height:0;overflow:visible;transition:width .3s ease,transform .3s ease}.side-menu{position:relative;display:flex;flex-direction:column;width:250px;height:100%;min-height:0;color:#fff;background-color:#0d1b2a;overflow:hidden;transition:width .3s ease,box-shadow .3s ease}:host:has(.left-wrap.sidemenu.collapsed){width:64px}.left-wrap.sidemenu.collapsed,.left-wrap.sidemenu.collapsed .side-menu{width:64px}.menu-separator{flex:0 0 auto;height:1px;margin:15px 12px 6px;background-color:#ffffff26;border:0;list-style:none}.user-profile{flex:0 0 auto;padding:20px 10px 16px;margin-top:40px;text-align:center;border-bottom:1px solid rgba(255,255,255,.1);overflow:hidden;transition:padding .25s ease,margin .25s ease,opacity .25s ease,max-height .25s ease}.user-profile .avatar{display:block;width:64px;height:64px;margin:0 auto 8px;object-fit:cover;border:2px solid #ffffff;border-radius:50%;transition:width .25s ease,height .25s ease,margin .25s ease}.user-profile .details{min-width:0;overflow:hidden;transition:opacity .2s ease}.user-profile .name{color:#fff;font-size:14px;font-weight:600;line-height:1.4;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.user-profile .email{margin:2px 0 8px;color:#aaa;font-size:12px;line-height:1.4;overflow-wrap:anywhere;word-break:break-word}.user-profile .actions{display:flex;align-items:center;justify-content:center;gap:6px}.user-profile .actions button{margin:0;color:#fff}.left-wrap.sidemenu.collapsed .user-profile{padding:12px 8px}.left-wrap.sidemenu.collapsed .user-profile .avatar{width:40px;height:40px;margin-bottom:0}.left-wrap.sidemenu.collapsed .user-profile .details,.left-wrap.sidemenu.collapsed .user-profile .name,.left-wrap.sidemenu.collapsed .user-profile .email,.left-wrap.sidemenu.collapsed .user-profile .actions{display:none}.side-menu ul[nz-menu]{flex:1 1 auto;width:100%;min-height:0;margin:0;padding:4px 0 8px;overflow-x:hidden;overflow-y:auto;background-color:transparent;scrollbar-width:thin;scrollbar-color:rgba(255,255,255,.28) transparent;scroll-behavior:smooth}.side-menu ul[nz-menu]::-webkit-scrollbar{width:6px}.side-menu ul[nz-menu]::-webkit-scrollbar-track{background:transparent}.side-menu ul[nz-menu]::-webkit-scrollbar-thumb{background-color:#ffffff47;border-radius:999px}.side-menu ul[nz-menu]::-webkit-scrollbar-thumb:hover{background-color:#ffffff6b}.menu-row{display:flex;align-items:center;width:100%;min-width:0}.menu-text{flex:1 1 auto;min-width:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.delete-icon{flex:0 0 auto;margin-left:auto;color:#ffffffb3;cursor:pointer;transition:color .18s ease,transform .18s ease}.delete-icon:hover{color:#ff7875;transform:scale(1.08)}.projects{position:static;flex:0 0 auto;width:100%;margin-top:auto;background-color:#0d1b2a}.side-toggle-handle{position:absolute;top:24px;right:-14px;z-index:10000;display:flex;align-items:center;justify-content:center;width:28px;height:48px;padding:0;color:#fff;background-color:#0d1b2a;border:0;border-radius:0 6px 6px 0;box-shadow:2px 0 6px #00000040;cursor:pointer;transform:translateY(-50%);transition:background-color .2s ease,box-shadow .2s ease}.side-toggle-handle:hover{background-color:#142a40;box-shadow:3px 0 9px #0000004d}.side-toggle-handle:focus-visible{outline:3px solid rgba(24,144,255,.45);outline-offset:2px}.side-toggle-handle span{color:#fff;font-size:14px;line-height:1;transition:transform .25s ease}.collapse-btn{position:absolute;top:8px;right:8px;z-index:10001}:host(:not(.sidemenu-mobile)) .left-wrap.sidemenu.collapsed:hover{transform:translate(0)}:host(:not(.sidemenu-mobile)) ::ng-deep .ant-menu.ant-menu-inline-collapsed{width:64px!important}:host(:not(.sidemenu-mobile)) ::ng-deep .ant-menu.ant-menu-inline-collapsed>.ant-menu-item,:host(:not(.sidemenu-mobile)) ::ng-deep .ant-menu.ant-menu-inline-collapsed>.ant-menu-submenu>.ant-menu-submenu-title,:host(:not(.sidemenu-mobile)) ::ng-deep .ant-menu.ant-menu-inline-collapsed>.ant-menu-item-group>.ant-menu-item-group-list>.ant-menu-item,:host(:not(.sidemenu-mobile)) ::ng-deep .ant-menu.ant-menu-inline-collapsed>.ant-menu-item-group>.ant-menu-item-group-list>.ant-menu-submenu>.ant-menu-submenu-title{display:flex!important;align-items:center!important;justify-content:center!important;width:45px!important;height:32px!important;margin-inline:0!important;padding-inline:0!important;overflow:hidden!important}:host(:not(.sidemenu-mobile)) ::ng-deep .ant-menu.ant-menu-inline-collapsed .ant-menu-title-content,:host(:not(.sidemenu-mobile)) ::ng-deep .ant-menu.ant-menu-inline-collapsed .menu-text,:host(:not(.sidemenu-mobile)) ::ng-deep .ant-menu.ant-menu-inline-collapsed .delete-icon,:host(:not(.sidemenu-mobile)) ::ng-deep .ant-menu.ant-menu-inline-collapsed .ant-menu-submenu-arrow{display:none!important;width:0!important;min-width:0!important;max-width:0!important;margin:0!important;padding:0!important;visibility:hidden!important;overflow:hidden!important;text-overflow:clip!important}:host(:not(.sidemenu-mobile)) ::ng-deep .ant-menu.ant-menu-inline-collapsed .ant-menu-item-icon,:host(:not(.sidemenu-mobile)) ::ng-deep .ant-menu.ant-menu-inline-collapsed>.ant-menu-item>.anticon,:host(:not(.sidemenu-mobile)) ::ng-deep .ant-menu.ant-menu-inline-collapsed>.ant-menu-submenu>.ant-menu-submenu-title>.anticon{display:inline-flex!important;flex:0 0 auto;align-items:center;justify-content:center;width:auto!important;min-width:18px;margin:0!important;padding:0!important;color:inherit;font-size:18px;line-height:1;visibility:visible!important}:host(:not(.sidemenu-mobile)) ::ng-deep .ant-menu.ant-menu-inline-collapsed .menu-row{display:contents}:host(.sidemenu-mobile){position:absolute;top:0;bottom:0;left:0;z-index:9999;width:250px;height:100%}:host(.sidemenu-mobile):has(.left-wrap.sidemenu.collapsed){width:0}:host(.sidemenu-mobile) .left-wrap.sidemenu{width:250px;height:100%}:host(.sidemenu-mobile) .side-menu,:host(.sidemenu-mobile) .side-menu.open{width:250px;height:100%;box-shadow:8px 0 22px #0000003d}:host(.sidemenu-mobile) .left-wrap.sidemenu.collapsed{width:250px;transform:translate(-250px)}:host(.sidemenu-mobile) .left-wrap.sidemenu.collapsed .side-menu{width:250px;box-shadow:none}:host(.sidemenu-mobile) .left-wrap.sidemenu.collapsed .side-toggle-handle{right:-28px}:host(.sidemenu-mobile) .side-toggle-handle{top:0;right:0;padding:0;transform:none!important}:host(.sidemenu-mobile) .collapse-btn{top:8px;right:8px}:host(.sidemenu-mobile) .user-profile{margin-top:40px}:host(.sidemenu-mobile) .user-profile .avatar{width:48px;height:48px}:host(.sidemenu-mobile) .left-wrap.sidemenu.collapsed .user-profile{max-height:0;padding:0;margin:0;opacity:0;overflow:hidden;border-bottom:0}@media(prefers-reduced-motion:reduce){:host,.left-wrap.sidemenu,.side-menu,.user-profile,.user-profile .avatar,.side-toggle-handle,.side-toggle-handle span{transition:none}.side-menu ul[nz-menu]{scroll-behavior:auto}}.app-version-footer{flex-shrink:0;display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:6px;padding:10px 12px;border-top:1px solid rgba(255,255,255,.15);color:#ffffffa6;font-size:11px;line-height:1.4;text-align:center}.app-version-footer__item{display:flex;flex-direction:column;min-width:0}.app-version-footer__label{font-size:10px;opacity:.7}.app-version-footer__value{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.pagination-check{position:absolute;top:50%;right:42px;transform:translateY(-50%)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i9.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i9.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i9.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "ngmodule", type: PlatformModule }, { kind: "ngmodule", type:
7335
7772
  // NG-ZORRO
7336
7773
  NzMenuModule }, { kind: "directive", type: i11$1.NzMenuDirective, selector: "[nz-menu]", inputs: ["nzInlineIndent", "nzTheme", "nzMode", "nzInlineCollapsed", "nzSelectable"], outputs: ["nzClick"], exportAs: ["nzMenu"] }, { kind: "component", type: i11$1.NzMenuItemComponent, selector: "[nz-menu-item]", inputs: ["nzPaddingLeft", "nzDisabled", "nzSelected", "nzDanger", "nzMatchRouterExact", "nzMatchRouter"], exportAs: ["nzMenuItem"] }, { kind: "component", type: i11$1.NzSubMenuComponent, selector: "[nz-submenu]", inputs: ["nzMenuClassName", "nzPaddingLeft", "nzTitle", "nzIcon", "nzTriggerSubMenuAction", "nzOpen", "nzDisabled", "nzPlacement"], outputs: ["nzOpenChange"], exportAs: ["nzSubmenu"] }, { kind: "ngmodule", type: NzIconModule }, { kind: "directive", type: i11.NzIconDirective, selector: "nz-icon,[nz-icon]", inputs: ["nzSpin", "nzRotate", "nzType", "nzTheme", "nzTwotoneColor", "nzIconfont"], exportAs: ["nzIcon"] }, { kind: "ngmodule", type: NzTooltipModule }, { kind: "directive", type: i13$1.NzTooltipDirective, selector: "[nz-tooltip]", inputs: ["nzTooltipTitle", "nzTooltipTitleContext", "nz-tooltip", "nzTooltipTrigger", "nzTooltipPlacement", "nzTooltipOrigin", "nzTooltipVisible", "nzTooltipMouseEnterDelay", "nzTooltipMouseLeaveDelay", "nzTooltipOverlayClassName", "nzTooltipOverlayStyle", "nzTooltipArrowPointAtCenter", "cdkConnectedOverlayPush", "nzTooltipColor"], outputs: ["nzTooltipVisibleChange"], exportAs: ["nzTooltip"] }, { kind: "ngmodule", type: NzButtonModule }, { kind: "component", type: i13.NzButtonComponent, selector: "button[nz-button], a[nz-button]", inputs: ["nzBlock", "nzGhost", "nzSearch", "nzLoading", "nzDanger", "disabled", "tabIndex", "nzType", "nzShape", "nzSize"], exportAs: ["nzButton"] }, { kind: "directive", type: i14.ɵNzTransitionPatchDirective, selector: "[nz-button], [nz-icon], nz-icon, [nz-menu-item], [nz-submenu], nz-select-top-control, nz-select-placeholder, nz-input-group", inputs: ["hidden"] }, { kind: "ngmodule", type:
7337
7774
  // PrimeNG
@@ -7538,6 +7975,69 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.2", ngImpor
7538
7975
  }]
7539
7976
  }], ctorParameters: () => [{ type: i1.Platform }] });
7540
7977
 
7978
+ // Faramarz Yousefian and Agent Toni (Claude Opus 5.5) 2026-10-14
7979
+ // - change: login, refresh and logout run through MobileOidcService - the same OpenID Connect flow
7980
+ // as Keycloak; the endpoints come from the issuer's discovery document instead of login.mobile.
7981
+ // The logout follows login.required: a project with an optional login (luv2shop) restarts on its
7982
+ // start page, signed out
7983
+ // Faramarz Yousefian and Agent Toni (Claude Opus 5.5) 2026-10-13
7984
+ // - new: Okta sign-in on the devices with a refresh token. The login asks for offline_access, the
7985
+ // tokens (access, refresh, id) are kept with the user, an expired access token is renewed with
7986
+ // the refresh token (grant_type=refresh_token, public client with PKCE - no secret) and the
7987
+ // logout revokes the refresh token. Before, only the access token was kept: after its lifetime
7988
+ // (1 hour in luv2shop) the backend calls failed until the user signed in again
7989
+ // - new: signOut ends the sign-in without a browser window: refresh and access token are revoked
7990
+ // and the next login asks Okta for the password again (prompt=login). The logout page in the
7991
+ // in-app browser stayed white after its redirect to the app scheme and did not close
7992
+ class MobileOktaService {
7993
+ utilityService;
7994
+ oidc;
7995
+ constructor(utilityService, oidc) {
7996
+ this.utilityService = utilityService;
7997
+ this.oidc = oidc;
7998
+ }
7999
+ /**
8000
+ * The Okta authorization server as an OIDC provider, from login.mobile of the project. The issuer
8001
+ * is login.mobile.issuer, else login.web.issuer, else derived from the authorize URL
8002
+ * (https://…/oauth2/default/v1/authorize → https://…/oauth2/default).
8003
+ */
8004
+ provider(environment) {
8005
+ const mobile = environment?.login?.mobile ?? {};
8006
+ const issuer = mobile.issuer
8007
+ || environment?.login?.web?.issuer
8008
+ || String(mobile.authorizationBaseUrl ?? '').replace(/\/v1\/authorize.*$/, '');
8009
+ return {
8010
+ issuer,
8011
+ clientId: mobile.clientId,
8012
+ redirectUri: mobile.redirectUrl,
8013
+ scope: mobile.scope,
8014
+ // Always: the refresh token keeps the sign-in beyond the access token's lifetime.
8015
+ offlineAccess: true
8016
+ };
8017
+ }
8018
+ login(environment) {
8019
+ return this.oidc.login(this.provider(environment));
8020
+ }
8021
+ refreshTokens(environment, stored) {
8022
+ return this.oidc.refresh(this.provider(environment), stored);
8023
+ }
8024
+ /**
8025
+ * Logout with the shared flow. login.required decides where the restarted app goes: true → the
8026
+ * loader until the sign-in opens, otherwise (default for Okta) the start page, signed out.
8027
+ */
8028
+ signOut(environment, stored) {
8029
+ return this.oidc.signOut(this.provider(environment), stored, 'loginedUser', key => this.utilityService.removeLocalStorage(key), { loginRequired: environment?.login?.required === true });
8030
+ }
8031
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.2", ngImport: i0, type: MobileOktaService, deps: [{ token: UtilityService }, { token: MobileOidcService }], target: i0.ɵɵFactoryTarget.Injectable });
8032
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.2", ngImport: i0, type: MobileOktaService, providedIn: 'root' });
8033
+ }
8034
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.2", ngImport: i0, type: MobileOktaService, decorators: [{
8035
+ type: Injectable,
8036
+ args: [{
8037
+ providedIn: 'root'
8038
+ }]
8039
+ }], ctorParameters: () => [{ type: UtilityService }, { type: MobileOidcService }] });
8040
+
7541
8041
  // Faramarz Yousefian and Agent Toni (Claude Opus 5) 2026-10-07
7542
8042
  // - new: letter layouts per language and a symbol page for the custom keyboards. The keyboard had
7543
8043
  // one hard-wired QWERTY without umlauts or punctuation, so German text such as a comment could
@@ -7719,9 +8219,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.2", ngImpor
7719
8219
  args: [{ selector: 'vl-custom-keyboard', standalone: true, template: "<!-- Faramarz Yousefian and Agent Toni (Claude Opus 5.5) 2026-10-13\r\n - change: the space key has no label (it said \"Space\" in every language); a label per language\r\n would have to be maintained for each new project language -->\r\n<!-- Faramarz Yousefian and Agent Toni (Claude Opus 5) 2026-10-07\r\n - new: a ?123 / ABC key switches string keyboards between letters and the symbol page -->\r\n@if (keyboard.activeSession(); as session) {\r\n<section class=\"custom-keyboard\" data-vl-custom-keyboard [class.custom-keyboard--numeric]=\"\r\n session.type === 'numeric' ||\r\n session.type === 'date' ||\r\n session.type === 'time'\" [class.custom-keyboard--opening]=\"keyboard.interactionBlocked()\"\r\n [attr.aria-label]=\"session.type + ' keyboard'\" (pointerdown)=\"$event.preventDefault()\">\r\n\r\n @for (row of rows; track $index) {\r\n <div class=\"custom-keyboard__row\">\r\n @for (key of row; track key) {\r\n <button type=\"button\" class=\"custom-keyboard__key\" (click)=\"enterKey(key)\">\r\n {{ key }}\r\n </button>\r\n }\r\n </div>\r\n }\r\n\r\n <!-- One mobile-style action row for every keyboard type -->\r\n <div class=\"custom-keyboard__actions\" [class.custom-keyboard__actions--compact]=\"\r\n session.type !== 'alpha' &&\r\n session.type !== 'string'\r\n \" [class.custom-keyboard__actions--symbols]=\"hasSymbolPage\">\r\n\r\n @if (\r\n session.type === 'alpha' ||\r\n session.type === 'string'\r\n ) {\r\n <button type=\"button\" class=\"custom-keyboard__action-button custom-keyboard__shift\" [class.active]=\"uppercase()\"\r\n [disabled]=\"symbols()\" aria-label=\"Change letter case\" title=\"Shift\" (click)=\"toggleCase()\">\r\n <i class=\"pi pi-arrow-up\"></i>\r\n </button>\r\n\r\n @if (hasSymbolPage) {\r\n <button type=\"button\" class=\"custom-keyboard__action-button custom-keyboard__page\"\r\n [attr.aria-label]=\"symbols() ? 'Letters' : 'Digits and symbols'\" (click)=\"toggleSymbols()\">\r\n {{ symbols() ? 'ABC' : '?123' }}\r\n </button>\r\n }\r\n\r\n <button type=\"button\" class=\"custom-keyboard__action-button custom-keyboard__space\" aria-label=\"Space\" (click)=\"enterSpace()\">\r\n </button>\r\n }\r\n\r\n <button type=\"button\" class=\"custom-keyboard__action-button custom-keyboard__delete\"\r\n aria-label=\"Delete previous character\" title=\"Delete\" (click)=\"keyboard.backspace()\">\r\n <i class=\"pi pi-delete-left\"></i>\r\n </button>\r\n\r\n <button type=\"button\" class=\"custom-keyboard__action-button custom-keyboard__done\" aria-label=\"Done\"\r\n title=\"Done\" (click)=\"keyboard.close()\">\r\n <i class=\"pi pi-check\"></i>\r\n </button>\r\n </div>\r\n</section>\r\n}\r\n", styles: [":host{display:contents}.custom-keyboard{position:fixed;right:0;bottom:0;left:0;z-index:200000;display:block;width:100%;max-height:min(52dvh,390px);padding:8px 6px calc(8px + env(safe-area-inset-bottom,0px));background:var(--vl-keyboard-background, var(--vl-page-background, #ffffff));box-shadow:0 -6px 20px #0f172a38;box-sizing:border-box;overflow-x:hidden;overflow-y:auto;user-select:none;-webkit-user-select:none;touch-action:manipulation;-webkit-overflow-scrolling:touch}.custom-keyboard__row{display:flex;justify-content:center;gap:4px;width:100%;margin-bottom:6px}.custom-keyboard__key{display:flex;flex:1 1 0;width:auto;max-width:52px;min-width:0;height:42px;align-items:center;justify-content:center;padding:0;color:#111827;font-size:16px;font-weight:700;line-height:1;background:#fff;border:1px solid #d1d5db;border-radius:5px;box-shadow:0 1px 2px #0f172a47;cursor:pointer;appearance:none;-webkit-appearance:none;touch-action:manipulation;transition:transform 80ms ease,background-color 80ms ease}.custom-keyboard__key:active{background:#e6f4ff;transform:scale(.96)}.custom-keyboard--numeric .custom-keyboard__key{max-width:92px;height:46px;font-size:18px}.custom-keyboard__actions{display:grid;grid-template-columns:46px minmax(90px,1fr) 46px 54px;gap:6px;width:100%;margin-top:4px;padding:0 4px}.custom-keyboard__actions--compact{grid-template-columns:minmax(52px,1fr) minmax(52px,1fr)}.custom-keyboard__actions--symbols{grid-template-columns:46px 54px minmax(70px,1fr) 46px 54px}.custom-keyboard__action-button{display:flex;width:100%;min-width:0;height:42px;align-items:center;justify-content:center;padding:0 8px;color:#172033;font-size:15px;font-weight:700;line-height:1;border:0;border-radius:6px;box-shadow:0 1px 2px #0f172a40;cursor:pointer;appearance:none;-webkit-appearance:none;touch-action:manipulation;transition:transform 80ms ease,background-color 80ms ease}.custom-keyboard__action-button i{font-size:17px;line-height:1;pointer-events:none}.custom-keyboard__action-button:active{transform:scale(.96)}.custom-keyboard__shift{color:#172033;background:#aeb6c2}.custom-keyboard__shift.active{color:#fff;background:#64748b}.custom-keyboard__space{color:#172033;background:#fff}.custom-keyboard__delete{color:#172033;background:#aeb6c2}.custom-keyboard__done{color:#fff;background:#1890ff}.custom-keyboard__page{color:#172033;font-size:14px;background:#aeb6c2}.custom-keyboard__shift:disabled{opacity:.45}.custom-keyboard__key:focus-visible,.custom-keyboard__action-button:focus-visible{outline:3px solid rgba(24,144,255,.35);outline-offset:1px}@media(max-height:650px){.custom-keyboard{max-height:58dvh;padding-top:6px}.custom-keyboard__row{gap:3px;margin-bottom:4px}.custom-keyboard__key{height:35px;font-size:14px}.custom-keyboard--numeric .custom-keyboard__key{height:38px;font-size:16px}.custom-keyboard__action-button{height:36px}}@media(max-width:360px){.custom-keyboard{padding-right:4px;padding-left:4px}.custom-keyboard__row{gap:3px}.custom-keyboard__key{font-size:14px}.custom-keyboard__actions{grid-template-columns:42px minmax(70px,1fr) 42px 48px;gap:4px;padding-right:2px;padding-left:2px}.custom-keyboard__actions--compact{grid-template-columns:minmax(48px,1fr) minmax(48px,1fr)}.custom-keyboard__actions--symbols{grid-template-columns:40px 48px minmax(56px,1fr) 40px 46px}}.custom-keyboard--opening .custom-keyboard__key,.custom-keyboard--opening .custom-keyboard__action-button{pointer-events:none}.custom-keyboard--opening{cursor:default}::ng-deep .picker-field{position:relative}::ng-deep .picker-field__icon{position:absolute;right:0;top:0;height:100%;width:2.5rem;border:0;background:transparent;cursor:pointer}::ng-deep .picker-field--active input{border-color:var(--modal-field-focus-color, var(--p-primary-color, #10b981))!important;outline:none!important;box-shadow:var(--modal-field-focus-shadow, 0 0 0 2px rgba(16, 185, 129, .16))!important}::ng-deep .p-datepicker-panel.model-datepicker-panel--docked,::ng-deep .model-datepicker-panel--docked{position:fixed!important;background:var(--vl-keyboard-background, var(--vl-page-background, #ffffff))!important;inset:auto 0 0!important;width:100%!important;min-width:100%!important;max-width:100%!important;max-height:min(52dvh,420px)!important;margin:0!important;padding-bottom:env(safe-area-inset-bottom,0px)!important;overflow-y:auto!important;transform:none!important;border-radius:12px 12px 0 0!important;box-shadow:0 -6px 20px #0f172a38!important;box-sizing:border-box!important}::ng-deep .model-timepicker-panel.p-datepicker-panel:not(.model-datepicker-panel--docked){width:auto!important;min-width:0!important;padding:4px 8px!important;border-radius:8px!important}::ng-deep .model-timepicker-panel .p-datepicker-time-picker{gap:4px!important;padding:0!important;border:0!important}::ng-deep .model-timepicker-panel .p-datepicker-hour-picker,::ng-deep .model-timepicker-panel .p-datepicker-minute-picker{gap:0!important}::ng-deep .model-timepicker-panel .p-datepicker-hour-picker span,::ng-deep .model-timepicker-panel .p-datepicker-minute-picker span,::ng-deep .model-timepicker-panel .p-datepicker-separator{font-size:1rem!important;line-height:1.2!important}::ng-deep .model-timepicker-panel .p-datepicker-increment-button,::ng-deep .model-timepicker-panel .p-datepicker-decrement-button{width:2rem!important;height:1.75rem!important}::ng-deep body.vl-side-dock .model-datepicker-panel--docked{inset:0 0 0 auto!important;width:var(--vl-side-dock-width, 50vw)!important;min-width:0!important;max-width:var(--vl-side-dock-width, 50vw)!important;height:100dvh!important;max-height:100dvh!important;min-height:0!important;padding-top:env(safe-area-inset-top,0px)!important;padding-right:env(safe-area-inset-right,0px)!important;border-left:1px solid #e5e7eb!important;box-shadow:-6px 0 20px #0f172a2e!important}.custom-keyboard__key{height:clamp(26px,5.2dvh,42px)}.custom-keyboard--numeric .custom-keyboard__key{height:clamp(28px,5.6dvh,46px)}.custom-keyboard__action-button{height:clamp(28px,5.2dvh,42px)}.custom-keyboard__row{margin-bottom:clamp(3px,.8dvh,6px)}::ng-deep body.vl-side-dock .custom-keyboard{inset:0 0 0 auto;width:var(--vl-side-dock-width, 50vw);max-height:none;height:100dvh;display:flex;flex-direction:column;justify-content:flex-start;padding-top:env(safe-area-inset-top,0px);padding-right:max(6px,env(safe-area-inset-right,0px));box-shadow:-6px 0 20px #0f172a2e}.custom-keyboard,::ng-deep .model-datepicker-panel--docked{border-top-left-radius:var(--p-dialog-border-radius, 12px)!important;border-top-right-radius:var(--p-dialog-border-radius, 12px)!important;overflow:hidden}::ng-deep .model-datepicker-panel--docked .p-datepicker-header{padding-top:clamp(2px,.6dvh,8px)!important;padding-bottom:clamp(2px,.6dvh,8px)!important}::ng-deep .model-datepicker-panel--docked .p-datepicker-day-cell,::ng-deep .model-datepicker-panel--docked .p-datepicker-weekday-cell{padding:1px!important}::ng-deep .model-datepicker-panel--docked .p-datepicker-day{width:var(--vl-day-size, clamp(28px, 4.4dvh, 40px))!important;height:var(--vl-day-size, clamp(28px, 4.4dvh, 40px))!important}::ng-deep body.vl-side-dock .model-datepicker-panel--docked,::ng-deep body.vl-side-dock .custom-keyboard{top:var(--vl-side-dock-top, max(8px, env(safe-area-inset-top, 0px)))!important;bottom:var(--vl-side-dock-bottom, max(8px, env(safe-area-inset-bottom, 0px)))!important;right:max(8px,env(safe-area-inset-right,0px))!important;left:auto!important;width:calc(var(--vl-side-dock-width, 50vw) - max(8px,env(safe-area-inset-right,0px)))!important;max-width:none!important;height:auto!important;max-height:none!important;padding-top:6px!important;padding-right:6px!important;border-radius:var(--p-dialog-border-radius, 12px)!important;overflow:hidden!important;box-shadow:var(--p-dialog-shadow, 0 20px 25px -5px rgba(0, 0, 0, .1), 0 8px 10px -6px rgba(0, 0, 0, .1))!important}::ng-deep body.vl-custom-keyboard-open .custom-keyboard,::ng-deep body.vl-custom-keyboard-open .model-datepicker-panel--docked{left:var(--vl-dock-left, 0px)!important;right:var(--vl-dock-right, 0px)!important;width:auto!important;min-width:0!important;max-width:none!important;bottom:var(--vl-dock-bottom-gap)!important;padding-bottom:8px!important;border-radius:var(--p-dialog-border-radius, 12px)!important;box-shadow:var(--p-dialog-shadow, 0 20px 25px -5px rgba(0, 0, 0, .1), 0 8px 10px -6px rgba(0, 0, 0, .1))!important}::ng-deep body{--vl-dock-bottom-gap: max(8px, env(safe-area-inset-bottom, 0px))}\n"] }]
7720
8220
  }], ctorParameters: () => [] });
7721
8221
 
8222
+ // Faramarz Yousefian and Agent Toni (Claude Opus 5.5) 2026-10-14
8223
+ // - new: exports MobileOidcService (one OpenID Connect flow for Keycloak and Okta on the devices)
7722
8224
  // Faramarz Yousefian and Agent Toni (Claude Opus 5.5) 2026-10-13
7723
8225
  // - new: exports native-platform (isNativeMobile/isNativePhone), PlaceholderPipe,
7724
8226
  // RequestTimeoutService and RemoteListService
8227
+ // - new: exports MobileOktaService (Okta sign-in on the devices with refresh token)
7725
8228
  /*
7726
8229
  * Public API Surface of view-toolkit
7727
8230
  */
@@ -7730,5 +8233,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.2", ngImpor
7730
8233
  * Generated bundle index. Do not edit.
7731
8234
  */
7732
8235
 
7733
- export { AppVersionResetService, CardComponent, ConfigService, Couchdb, CustomKeyboardComponent, CustomKeyboardDirective, CustomKeyboardService, FormComponent, GridComponent, HeaderMenuComponent, LogsComponent, MobileKeycloakService, ModelComponent, NetworkLogService, NotificationService, PaginationComponent, PlaceholderPipe, REQUEST_STAGES, RemoteListService, RequestService, RequestTimeoutError, RequestTimeoutService, SIDE_DOCK_CLASS, SideMenuComponent, UtilityService, ViewToolkitModule, isNativeMobile, isNativePhone, normalizeCustomKeyboardType, resolveCustomKeyboardType, resolvePlaceholder, sideDockWidth, stagedRequest };
8236
+ 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 };
7734
8237
  //# sourceMappingURL=yomotech-view-toolkit.mjs.map