UNPKG

ddata-ui-input

Version:

DData UI Input module, components, models & services

823 lines (807 loc) 150 kB
import { faCog, faCheckSquare, faSquare, faCalendar, faSearch } from '@fortawesome/free-solid-svg-icons'; import { BaseModel, DdataCoreModule, ValidatorService, ProxyFactoryService, Paginate, SpinnerService } from 'ddata-core'; import * as i0 from '@angular/core'; import { Pipe, EventEmitter, Input, Output, ChangeDetectionStrategy, Component, ViewChild, HostListener, ViewContainerRef, signal, NgModule } from '@angular/core'; import * as i1 from '@angular/common'; import { CommonModule } from '@angular/common'; import * as i2 from '@fortawesome/angular-fontawesome'; import { FontAwesomeModule } from '@fortawesome/angular-fontawesome'; import * as i2$1 from '@angular/forms'; import { FormsModule } from '@angular/forms'; import * as i4 from 'ngx-color-picker'; import { ColorPickerComponent, ColorPickerDirective } from 'ngx-color-picker'; import * as moment from 'moment'; import * as i3 from '@ng-bootstrap/ng-bootstrap'; import { NgbDatepickerModule } from '@ng-bootstrap/ng-bootstrap'; import { BehaviorSubject, fromEvent, Subscription } from 'rxjs'; import { debounceTime, distinctUntilChanged, takeUntil, tap, switchMap, map, finalize, take } from 'rxjs/operators'; import * as i1$1 from '@angular/router'; import * as i2$2 from 'ddata-ui-common'; import { DdataUiCommonModule } from 'ddata-ui-common'; import * as i3$1 from 'ngx-material-timepicker'; import { NgxMaterialTimepickerModule } from 'ngx-material-timepicker'; class DialogContentItem { constructor(component, data) { this.component = component; this.data = data; } } class DialogContentWithOptions { constructor(component, options) { this.component = component; this.options = options; } } // tslint:disable: variable-name class SearchModelFunctions extends BaseModel { constructor() { super(...arguments); this.icons = { cog: faCog }; } init(data) { const searchData = !!data ? data : {}; this.initAsNumberWithDefaults(['id'], searchData); this.initAsStringWithDefaults(['name', 'description', 'type', 'found_model_name'], searchData); this.icon = this.setIcon(this.type); this.url = this.setUrl(this.type); return this; } setUrl(type) { return type.replace(new RegExp(/_/, 'g'), '/'); } setIcon(type) { if (!type) { return this.icons.cog; } return this.icons[type] ?? this.icons.cog; } } class SearchAbstract extends SearchModelFunctions { constructor() { super(...arguments); // tslint:disable: variable-name this.api_endpoint = '/search'; this.model_name = 'Search'; } init(data) { const searchData = !!data ? data : {}; super.init(searchData); this.initAsStringWithDefaults(['searchText'], searchData); return this; } prepareToSave() { return { term: !!this.searchText ? this.searchText : '' }; } } class SearchResultAbstract extends SearchModelFunctions { init(data) { super.init(data); return this; } } class DescriptionPipe { transform(value) { const transformValue = !!value ? value : ''; let result = ''; const parts = transformValue.split('|'); parts.forEach((part) => { let processedPart = part.replace(new RegExp(/^tel:(.*?)$/), '<a href="tel:$1" class="mr-3">$1</a>'); processedPart = processedPart.replace(new RegExp(/^email:(.*?)$/), '<a href="mailto:$1" class="mr-3">$1</a>'); processedPart = processedPart.replace(new RegExp(/^url:(.*?)$/), '<a href="$1" class="mr-3" target="_blank">$1</a>'); processedPart = processedPart.replace(new RegExp(/^description:(.*?)$/), '<span class="description">$1</span>'); result += `${processedPart} `; }); return result; } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: DescriptionPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe }); } static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "20.0.6", ngImport: i0, type: DescriptionPipe, isStandalone: false, name: "description" }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: DescriptionPipe, decorators: [{ type: Pipe, args: [{ name: 'description', standalone: false }] }] }); class InputHelperService { constructor() { this.validatorService = DdataCoreModule.InjectorInstance.get(ValidatorService); } validateField(model, field) { // handle missing validation rule if (!model.validationRules[field]) { console.error(`Missing validation rule:${field} from model: ${model.constructor.name}`); return false; } const isValid = this.validatorService.validate(model[field], model.validationRules[field]); // if not valid & validation error is not set if (!isValid && !model.validationErrors.includes(field)) { model.validationErrors.push(field); return false; } // it's valid & validation error set - need remove if (model.validationErrors.includes(field)) { model.validationErrors.splice(model.validationErrors.indexOf(field), 1); } return true; } getTitle(model, field) { if (!model || !model.fields[field] || !model.fields[field].title) { console.error(`The model not contains the '${field}' field's title. You need to set in your model the fields.${field}.title field.`); return ''; } return model.fields[field].title; } getLabel(model, field) { if (!model || !model.fields[field] || !model.fields[field].label) { console.error(`The model not contains the '${field}' field's label. You need to set in your model the fields.${field}.label field.`); return ''; } return model.fields[field].label; } getPlaceholder(model, field) { if (!model || !model.fields[field] || !model.fields[field].placeholder) { console.error(`The model not contains the '${field}' field's placeholder. You need to set in your model the fields.${field}.placeholder field.`); return ''; } return model.fields[field].title; } getPrepend(model, field) { if (!model || !model.fields[field] || !model.fields[field].prepend) { return ''; } return model.fields[field].prepend; } getAppend(model, field) { if (!model || !model.fields[field] || !model.fields[field].append) { return ''; } return model.fields[field].append; } isRequired(model, field) { try { // Check if model and validationRules exist if (!model || !model.validationRules || !model.validationRules[field]) { return false; } const rules = model.validationRules[field]; // According to ValidationRuleInterface, rules should be Array<Rule> if (Array.isArray(rules)) { return rules.includes('required'); } // Fallback: Handle object format for compatibility (though this shouldn't be the standard) if (typeof rules === 'object' && rules !== null) { // Object format: { required: true } return Boolean(rules.required); } // String format: 'required' if (typeof rules === 'string') { return rules === 'required'; } // Boolean format: true (means required) if (typeof rules === 'boolean') { return rules; } return false; } catch { return false; } } randChars() { let result = ''; const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; const charactersLength = characters.length; for (let i = 0; i < 50; i++) { result += characters.charAt(Math.floor(Math.random() * charactersLength)); } return result; } } class DdataInputCheckboxComponent { set model(value) { let actualValue = value; if (!actualValue) { actualValue = new BaseModel(); } this._model = actualValue; if (!!this._model.fields) { if (!!this._model.fields[this._field]) { this._label = this._model.fields[this._field].label ?? ''; } } } get model() { return this._model; } set field(fieldValue) { let actualValue = fieldValue; if (actualValue === 'undefined') { actualValue = 'isValid'; } this._field = actualValue; } get field() { return this._field; } constructor() { // Input properties this.disabled = false; this.showLabel = true; this.showLabelAfter = true; this.labelClass = 'col pl-2 col-form-label'; this.wrapperClass = 'd-flex'; this.iconOn = faCheckSquare; this.iconOff = faSquare; // Output properties this.changed = new EventEmitter(); // tslint:disable: variable-name this._model = new BaseModel(); this._field = 'isValid'; this._label = ''; this.iterable = 0; } ngOnInit() { this.iterable = Math.floor(Math.random() * 100); } clicked() { if (!this.disabled) { this.model[this._field] = !this.model[this._field]; this.changed.emit(this.model[this._field]); } } getIcon() { return !!this.model[this._field] ? this.iconOn : this.iconOff; } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: DdataInputCheckboxComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); } static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.0.6", type: DdataInputCheckboxComponent, isStandalone: false, selector: "dd-input-checkbox", inputs: { disabled: "disabled", showLabel: "showLabel", showLabelAfter: "showLabelAfter", labelClass: "labelClass", wrapperClass: "wrapperClass", iconOn: "iconOn", iconOff: "iconOff", model: "model", field: "field" }, outputs: { changed: "changed" }, ngImport: i0, template: "<div [class]=\"wrapperClass\">\n <label\n *ngIf=\"showLabel && !showLabelAfter\"\n [class]=\"labelClass\"\n [class.disabled]=\"disabled\"\n [for]=\"_field + iterable\"\n >\n {{ _label }}:\n </label>\n\n <button\n type=\"button\"\n class=\"btn btn-light\"\n (click)=\"clicked()\"\n [disabled]=\"disabled\"\n [id]=\"_field + iterable\"\n [name]=\"_field + iterable\"\n [title]=\"_label\"\n >\n <fa-icon [icon]=\"getIcon()\"></fa-icon>\n </button>\n\n <label\n *ngIf=\"showLabel && showLabelAfter\"\n [class]=\"labelClass\"\n [class.disabled]=\"disabled\"\n [for]=\"_field + iterable\"\n >\n {{ _label }}\n </label>\n</div>\n", styles: [".disabled{opacity:.3}\n"], dependencies: [{ kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: i2.FaIconComponent, selector: "fa-icon", inputs: ["icon", "title", "animation", "mask", "flip", "size", "pull", "border", "inverse", "symbol", "rotate", "fixedWidth", "transform", "a11yRole"], outputs: ["iconChange", "titleChange", "animationChange", "maskChange", "flipChange", "sizeChange", "pullChange", "borderChange", "inverseChange", "symbolChange", "rotateChange", "fixedWidthChange", "transformChange", "a11yRoleChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: DdataInputCheckboxComponent, decorators: [{ type: Component, args: [{ selector: 'dd-input-checkbox', changeDetection: ChangeDetectionStrategy.OnPush, standalone: false, template: "<div [class]=\"wrapperClass\">\n <label\n *ngIf=\"showLabel && !showLabelAfter\"\n [class]=\"labelClass\"\n [class.disabled]=\"disabled\"\n [for]=\"_field + iterable\"\n >\n {{ _label }}:\n </label>\n\n <button\n type=\"button\"\n class=\"btn btn-light\"\n (click)=\"clicked()\"\n [disabled]=\"disabled\"\n [id]=\"_field + iterable\"\n [name]=\"_field + iterable\"\n [title]=\"_label\"\n >\n <fa-icon [icon]=\"getIcon()\"></fa-icon>\n </button>\n\n <label\n *ngIf=\"showLabel && showLabelAfter\"\n [class]=\"labelClass\"\n [class.disabled]=\"disabled\"\n [for]=\"_field + iterable\"\n >\n {{ _label }}\n </label>\n</div>\n", styles: [".disabled{opacity:.3}\n"] }] }], ctorParameters: () => [], propDecorators: { disabled: [{ type: Input }], showLabel: [{ type: Input }], showLabelAfter: [{ type: Input }], labelClass: [{ type: Input }], wrapperClass: [{ type: Input }], iconOn: [{ type: Input }], iconOff: [{ type: Input }], changed: [{ type: Output }], model: [{ type: Input }], field: [{ type: Input }] } }); class DdataInputColorComponent { set model(value) { let modelValue = value; if (!modelValue) { modelValue = new BaseModel(); } this._model = modelValue; if (!!this._model && !!this._model.fields[this._field]) { this._title = this.helperService.getTitle(this._model, this._field); this._placeholder = this.helperService.getPlaceholder(this._model, this._field); this._prepend = this.helperService.getPrepend(this._model, this._field); this._append = this.helperService.getAppend(this._model, this._field); this._label = this.helperService.getLabel(this._model, this._field); } if (!!this._model && !!this._model.validationRules[this._field]) { this._isRequired = this.helperService.isRequired(this._model, this._field); } } get model() { return this._model; } set field(value) { let fieldValue = value; if (fieldValue === 'undefined') { fieldValue = 'isValid'; } this._field = fieldValue; } set append(value) { let appendValue = value; if (appendValue === 'undefined') { appendValue = ''; } this._append = appendValue; } set prepend(value) { let prependValue = value; if (prependValue === 'undefined') { prependValue = ''; } this._prepend = prependValue; } set labelText(value) { let labelValue = value; if (labelValue === 'undefined') { labelValue = ''; } this._label = labelValue; } constructor(helperService) { this.helperService = helperService; this.disabled = false; this.type = 'text'; this.inputClass = 'form-control'; this.labelClass = 'col-12 col-md-3 px-0 col-form-label'; this.inputBlockClass = 'col-12 d-flex px-0'; this.inputBlockExtraClass = 'col-md-9'; this.showLabel = true; this.autoFocus = false; this.wrapperClass = 'd-flex flex-wrap'; this.changed = new EventEmitter(); // tslint:disable: variable-name this._field = ''; this._title = ''; this._label = ''; this._placeholder = ''; this._prepend = ''; this._append = ''; this._isRequired = false; this._model = new BaseModel(); this.random = this.helperService.randChars(); this.toggle = false; this.validatorService = DdataCoreModule.InjectorInstance.get(ValidatorService); } ngOnInit() { if (this.autoFocus) { this.inputBox.nativeElement.focus(); } } validateField() { const isValid = this.helperService.validateField(this._model, this._field); if (isValid) { this.changed.emit(this._model); } } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: DdataInputColorComponent, deps: [{ token: InputHelperService }], target: i0.ɵɵFactoryTarget.Component }); } static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.0.6", type: DdataInputColorComponent, isStandalone: false, selector: "dd-input-color", inputs: { disabled: "disabled", type: "type", inputClass: "inputClass", labelClass: "labelClass", inputBlockClass: "inputBlockClass", inputBlockExtraClass: "inputBlockExtraClass", showLabel: "showLabel", autoFocus: "autoFocus", wrapperClass: "wrapperClass", model: "model", field: "field", append: "append", prepend: "prepend", labelText: "labelText" }, outputs: { changed: "changed" }, viewQueries: [{ propertyName: "inputBox", first: true, predicate: ["inputBox"], descendants: true }], ngImport: i0, template: "<div [class]=\"wrapperClass\">\n <label [class]=\"labelClass\" [for]=\"_field + '_' + random\" *ngIf=\"showLabel\">\n {{ _label }}:\n <span *ngIf=\"_isRequired\"> *</span>\n </label>\n\n <div [class]=\"inputBlockClass\" [ngClass]=\"showLabel ? inputBlockExtraClass : ''\">\n <div\n class=\"input-color-container\"\n [style.background]=\"model[_field]\"\n (click)=\"toggle = !toggle\"\n ></div>\n\n <div class=\"input-group-prepend\" *ngIf=\"_prepend !== ''\">\n <div class=\"input-group-text\">{{ _prepend }}</div>\n </div>\n\n <input\n [class.invalid]=\"model.validationErrors.includes(_field)\"\n [class]=\"inputClass\"\n [(ngModel)]=\"model[_field]\"\n [id]=\"_field + '_' + random\"\n [attr.name]=\"_field + '_' + random\"\n [placeholder]=\"_placeholder\"\n [title]=\"_title\"\n [disabled]=\"disabled\"\n [type]=\"type\"\n [(colorPicker)]=\"model[_field]\"\n [(cpToggle)]=\"toggle\"\n cpPosition=\"bottom\"\n cpOutputFormat=\"hex\"\n cpAlphaChannel=\"disabled\"\n cpFallbackColor=\"#c0c0c0\"\n (keyup)=\"validateField()\"\n #inputBox\n />\n\n <div class=\"input-group-append\" *ngIf=\"_append !== ''\">\n <div class=\"input-group-text\">{{ _append }}</div>\n </div>\n </div>\n</div>\n", styles: [".input-color-container{width:40px}\n"], dependencies: [{ kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i2$1.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$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: i4.ColorPickerDirective, selector: "[colorPicker]", inputs: ["colorPicker", "cpWidth", "cpHeight", "cpToggle", "cpDisabled", "cpIgnoredElements", "cpFallbackColor", "cpColorMode", "cpCmykEnabled", "cpOutputFormat", "cpAlphaChannel", "cpDisableInput", "cpDialogDisplay", "cpSaveClickOutside", "cpCloseClickOutside", "cpUseRootViewContainer", "cpPosition", "cpPositionOffset", "cpPositionRelativeToArrow", "cpOKButton", "cpOKButtonText", "cpOKButtonClass", "cpCancelButton", "cpCancelButtonText", "cpCancelButtonClass", "cpEyeDropper", "cpPresetLabel", "cpPresetColors", "cpPresetColorsClass", "cpMaxPresetColorsLength", "cpPresetEmptyMessage", "cpPresetEmptyMessageClass", "cpAddColorButton", "cpAddColorButtonText", "cpAddColorButtonClass", "cpRemoveColorButtonClass", "cpArrowPosition", "cpExtraTemplate"], outputs: ["cpInputChange", "cpToggleChange", "cpSliderChange", "cpSliderDragEnd", "cpSliderDragStart", "colorPickerOpen", "colorPickerClose", "colorPickerCancel", "colorPickerSelect", "colorPickerChange", "cpCmykColorChange", "cpPresetColorsChange"], exportAs: ["ngxColorPicker"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: DdataInputColorComponent, decorators: [{ type: Component, args: [{ selector: 'dd-input-color', standalone: false, changeDetection: ChangeDetectionStrategy.OnPush, template: "<div [class]=\"wrapperClass\">\n <label [class]=\"labelClass\" [for]=\"_field + '_' + random\" *ngIf=\"showLabel\">\n {{ _label }}:\n <span *ngIf=\"_isRequired\"> *</span>\n </label>\n\n <div [class]=\"inputBlockClass\" [ngClass]=\"showLabel ? inputBlockExtraClass : ''\">\n <div\n class=\"input-color-container\"\n [style.background]=\"model[_field]\"\n (click)=\"toggle = !toggle\"\n ></div>\n\n <div class=\"input-group-prepend\" *ngIf=\"_prepend !== ''\">\n <div class=\"input-group-text\">{{ _prepend }}</div>\n </div>\n\n <input\n [class.invalid]=\"model.validationErrors.includes(_field)\"\n [class]=\"inputClass\"\n [(ngModel)]=\"model[_field]\"\n [id]=\"_field + '_' + random\"\n [attr.name]=\"_field + '_' + random\"\n [placeholder]=\"_placeholder\"\n [title]=\"_title\"\n [disabled]=\"disabled\"\n [type]=\"type\"\n [(colorPicker)]=\"model[_field]\"\n [(cpToggle)]=\"toggle\"\n cpPosition=\"bottom\"\n cpOutputFormat=\"hex\"\n cpAlphaChannel=\"disabled\"\n cpFallbackColor=\"#c0c0c0\"\n (keyup)=\"validateField()\"\n #inputBox\n />\n\n <div class=\"input-group-append\" *ngIf=\"_append !== ''\">\n <div class=\"input-group-text\">{{ _append }}</div>\n </div>\n </div>\n</div>\n", styles: [".input-color-container{width:40px}\n"] }] }], ctorParameters: () => [{ type: InputHelperService }], propDecorators: { disabled: [{ type: Input }], type: [{ type: Input }], inputClass: [{ type: Input }], labelClass: [{ type: Input }], inputBlockClass: [{ type: Input }], inputBlockExtraClass: [{ type: Input }], showLabel: [{ type: Input }], autoFocus: [{ type: Input }], wrapperClass: [{ type: Input }], changed: [{ type: Output }], inputBox: [{ type: ViewChild, args: ['inputBox'] }], model: [{ type: Input }], field: [{ type: Input }], append: [{ type: Input }], prepend: [{ type: Input }], labelText: [{ type: Input }] } }); class DdataInputDateComponent { set moment(value) { let momentValue = value; if (!momentValue) { momentValue = moment; } this._moment = momentValue; } set model(value) { let modelValue = value; if (!modelValue) { modelValue = new BaseModel(); } this._model = modelValue; if (!!this._model && !!this._model.fields[this._field]) { this._title = this.helperService.getTitle(this._model, this._field); this._placeholder = this.helperService.getPlaceholder(this._model, this._field); this._prepend = this.helperService.getPrepend(this._model, this._field); this._append = this.helperService.getAppend(this._model, this._field); this._label = this.helperService.getLabel(this._model, this._field); } if (!!this._model && !!this._model.validationRules[this._field]) { this._isRequired = this.helperService.isRequired(this._model, this._field); } } get model() { return this._model; } set field(value) { let fieldValue = value; if (fieldValue === 'undefined') { fieldValue = 'isValid'; } this._field = fieldValue; } set append(value) { let appendValue = value; if (appendValue === 'undefined') { appendValue = ''; } this._append = appendValue; } set prepend(value) { let prependValue = value; if (prependValue === 'undefined') { prependValue = ''; } this._prepend = prependValue; } set labelText(value) { let labelValue = value; if (labelValue === 'undefined') { labelValue = ''; } this._label = labelValue; } constructor(changeDetector) { this.changeDetector = changeDetector; this.disabled = false; this.inputClass = 'form-control'; this.labelClass = 'col-12 col-md-3 px-0 col-form-label'; this.inputBlockClass = 'col-12 d-flex px-0'; this.inputBlockExtraClass = 'col-md-9'; this.showLabel = true; this.autoFocus = false; this.isViewOnly = false; this.viewOnlyClass = 'form-control border-0 bg-light'; this.buttonClass = 'input-group-prepend btn btn-light mb-0'; this.wrapperClass = 'd-flex flex-wrap'; this.format = 'YYYY-MM-DD'; this.separator = '-'; this.labelApply = 'OK'; this.labelCancel = 'Cancel'; this.position = 'center'; this.direction = 'down'; this.showIcon = true; this.autoApply = true; this.singleDatePicker = true; this.changed = new EventEmitter(); this.helperService = DdataCoreModule.InjectorInstance.get(InputHelperService); // tslint:disable: variable-name this._field = ''; this._title = ''; this._label = ''; this._placeholder = ''; this._prepend = ''; this._append = ''; this._isRequired = false; this._model = new BaseModel(); this._moment = moment; this.icon = { calendar: faCalendar }; this.random = this.helperService.randChars(); this.selectedValue = !!this.model[this._field] ? this.model[this._field] : ''; } ngOnInit() { if (!!this.model[this._field]) { this.selectedValue = this.model[this._field]; } if (this.autoFocus) { this.inputBox.nativeElement.focus(); } } change(value) { this.selectedValue = `${value.year}-${value.month.toString().padStart(2, '0')}-${value.day .toString() .padStart(2, '0')}`; this.model[this._field] = this.selectedValue; const isValid = this.helperService.validateField(this._model, this._field); if (isValid) { this.changed.emit(this._model); } } typeChange(event) { this._model[this._field] = event.target.value; } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: DdataInputDateComponent, deps: [{ token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component }); } static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.0.6", type: DdataInputDateComponent, isStandalone: false, selector: "dd-input-date", inputs: { disabled: "disabled", inputClass: "inputClass", labelClass: "labelClass", inputBlockClass: "inputBlockClass", inputBlockExtraClass: "inputBlockExtraClass", showLabel: "showLabel", autoFocus: "autoFocus", isViewOnly: "isViewOnly", viewOnlyClass: "viewOnlyClass", buttonClass: "buttonClass", wrapperClass: "wrapperClass", format: "format", separator: "separator", labelApply: "labelApply", labelCancel: "labelCancel", position: "position", direction: "direction", showIcon: "showIcon", autoApply: "autoApply", singleDatePicker: "singleDatePicker", moment: "moment", model: "model", field: "field", append: "append", prepend: "prepend", labelText: "labelText" }, outputs: { changed: "changed" }, viewQueries: [{ propertyName: "inputBox", first: true, predicate: ["inputBox"], descendants: true }], ngImport: i0, template: "<div [class]=\"wrapperClass\">\n <label [class]=\"labelClass\" [for]=\"_field + '_' + random\" *ngIf=\"showLabel\">\n {{ _label }}:\n <span *ngIf=\"_is_required\"> *</span>\n </label>\n\n <div [class]=\"inputBlockClass\" [ngClass]=\"showLabel ? inputBlockExtraClass : ''\">\n <div class=\"input-group-prepend\" *ngIf=\"_prepend !== ''\">\n <div class=\"input-group-text\">{{ _prepend }}</div>\n </div>\n\n <ng-container *ngIf=\"!isViewOnly\">\n <input\n [class.invalid]=\"model.validationErrors.includes(_field)\"\n [class]=\"inputClass\"\n [disabled]=\"disabled\"\n [id]=\"_field + '_' + random\"\n [name]=\"_field + '_' + random\"\n [placeholder]=\"_placeholder\"\n [title]=\"_title\"\n [value]=\"model[_field]\"\n (dateSelect)=\"change($event)\"\n type=\"text\"\n ngbDatepicker\n #d=\"ngbDatepicker\"\n (click)=\"d.toggle()\"\n (change)=\"typeChange($event)\"\n />\n </ng-container>\n\n <ng-container *ngIf=\"isViewOnly\">\n <div [class]=\"viewOnlyClass\">{{ model[_field] }}</div>\n </ng-container>\n\n <label [class]=\"buttonClass\" *ngIf=\"!disabled && showIcon\" [for]=\"_field + '_' + random\">\n <fa-icon [icon]=\"icon.calendar\"></fa-icon>\n </label>\n\n <div class=\"input-group-append\" *ngIf=\"_append !== ''\">\n <div class=\"input-group-text\">{{ _append }}</div>\n </div>\n </div>\n</div>\n", styles: [":host{position:relative;flex:1 1 auto}\n"], dependencies: [{ kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: i2.FaIconComponent, selector: "fa-icon", inputs: ["icon", "title", "animation", "mask", "flip", "size", "pull", "border", "inverse", "symbol", "rotate", "fixedWidth", "transform", "a11yRole"], outputs: ["iconChange", "titleChange", "animationChange", "maskChange", "flipChange", "sizeChange", "pullChange", "borderChange", "inverseChange", "symbolChange", "rotateChange", "fixedWidthChange", "transformChange", "a11yRoleChange"] }, { kind: "directive", type: i3.NgbInputDatepicker, selector: "input[ngbDatepicker]", inputs: ["autoClose", "contentTemplate", "datepickerClass", "dayTemplate", "dayTemplateData", "displayMonths", "firstDayOfWeek", "footerTemplate", "markDisabled", "minDate", "maxDate", "navigation", "outsideDays", "placement", "popperOptions", "restoreFocus", "showWeekNumbers", "startDate", "container", "positionTarget", "weekdays", "disabled"], outputs: ["dateSelect", "navigate", "closed"], exportAs: ["ngbDatepicker"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: DdataInputDateComponent, decorators: [{ type: Component, args: [{ selector: 'dd-input-date', standalone: false, changeDetection: ChangeDetectionStrategy.OnPush, template: "<div [class]=\"wrapperClass\">\n <label [class]=\"labelClass\" [for]=\"_field + '_' + random\" *ngIf=\"showLabel\">\n {{ _label }}:\n <span *ngIf=\"_is_required\"> *</span>\n </label>\n\n <div [class]=\"inputBlockClass\" [ngClass]=\"showLabel ? inputBlockExtraClass : ''\">\n <div class=\"input-group-prepend\" *ngIf=\"_prepend !== ''\">\n <div class=\"input-group-text\">{{ _prepend }}</div>\n </div>\n\n <ng-container *ngIf=\"!isViewOnly\">\n <input\n [class.invalid]=\"model.validationErrors.includes(_field)\"\n [class]=\"inputClass\"\n [disabled]=\"disabled\"\n [id]=\"_field + '_' + random\"\n [name]=\"_field + '_' + random\"\n [placeholder]=\"_placeholder\"\n [title]=\"_title\"\n [value]=\"model[_field]\"\n (dateSelect)=\"change($event)\"\n type=\"text\"\n ngbDatepicker\n #d=\"ngbDatepicker\"\n (click)=\"d.toggle()\"\n (change)=\"typeChange($event)\"\n />\n </ng-container>\n\n <ng-container *ngIf=\"isViewOnly\">\n <div [class]=\"viewOnlyClass\">{{ model[_field] }}</div>\n </ng-container>\n\n <label [class]=\"buttonClass\" *ngIf=\"!disabled && showIcon\" [for]=\"_field + '_' + random\">\n <fa-icon [icon]=\"icon.calendar\"></fa-icon>\n </label>\n\n <div class=\"input-group-append\" *ngIf=\"_append !== ''\">\n <div class=\"input-group-text\">{{ _append }}</div>\n </div>\n </div>\n</div>\n", styles: [":host{position:relative;flex:1 1 auto}\n"] }] }], ctorParameters: () => [{ type: i0.ChangeDetectorRef }], propDecorators: { disabled: [{ type: Input }], inputClass: [{ type: Input }], labelClass: [{ type: Input }], inputBlockClass: [{ type: Input }], inputBlockExtraClass: [{ type: Input }], showLabel: [{ type: Input }], autoFocus: [{ type: Input }], isViewOnly: [{ type: Input }], viewOnlyClass: [{ type: Input }], buttonClass: [{ type: Input }], wrapperClass: [{ type: Input }], format: [{ type: Input }], separator: [{ type: Input }], labelApply: [{ type: Input }], labelCancel: [{ type: Input }], position: [{ type: Input }], direction: [{ type: Input }], showIcon: [{ type: Input }], autoApply: [{ type: Input }], singleDatePicker: [{ type: Input }], changed: [{ type: Output }], inputBox: [{ type: ViewChild, args: ['inputBox'] }], moment: [{ type: Input }], model: [{ type: Input }], field: [{ type: Input }], append: [{ type: Input }], prepend: [{ type: Input }], labelText: [{ type: Input }] } }); class DdataInputComponent { set model(value) { // prevent undefined if (!value) { console.error('The input-box component get undefined model'); return; } this._model = value; if (!this._model.fields) { console.error(`Your ${this._model.model_name}'s 'fields' field is`, this._model.fields); return; } if (!this._model.fields[this._field]) { console.error(`The ${this._model.model_name}'s ${this._field} field is `, this._model.fields[this._field]); return; } if (!!this._model && !!this._model.fields[this._field]) { this._title = this.helperService.getTitle(this._model, this._field); this._placeholder = this.helperService.getPlaceholder(this._model, this._field); this._prepend = this.helperService.getPrepend(this._model, this._field); this._append = this.helperService.getAppend(this._model, this._field); this._label = this.helperService.getLabel(this._model, this._field); } if (!!this._model && !!this._model.validationRules[this._field]) { this._isRequired = this.helperService.isRequired(this._model, this._field); } } get model() { return this._model; } set field(fieldValue) { let actualValue = fieldValue; if (actualValue === 'undefined') { actualValue = 'isValid'; } this._field = actualValue; } set append(appendValue) { let actualValue = appendValue; if (actualValue === 'undefined') { actualValue = ''; } this._append = actualValue; } set prepend(prependValue) { let actualValue = prependValue; if (actualValue === 'undefined') { actualValue = ''; } this._prepend = actualValue; } set labelText(labelValue) { let actualValue = labelValue; if (actualValue === 'undefined') { actualValue = ''; } this._label = actualValue; } constructor() { // Input properties this.disabled = false; this.isViewOnly = false; this.type = 'text'; this.inputClass = 'form-control'; this.labelClass = 'col-12 col-md-3 px-0 col-form-label'; this.inputBlockClass = 'col-12 d-flex px-0'; this.inputBlockExtraClass = 'col-md-9'; this.viewOnlyClass = 'form-control border-0 bg-light'; this.wrapperClass = 'd-flex flex-wrap'; this.showLabel = true; this.autoFocus = false; this.enableCharacterCounter = false; this.enableWordCounter = false; this.maxLength = 255; this.maxWords = 7; this.wordCounterWarningMessage = ''; // Output properties this.changed = new EventEmitter(); this.maxLengthReached = new EventEmitter(); // Private properties this.helperService = DdataCoreModule.InjectorInstance.get(InputHelperService); // tslint:disable: variable-name this._field = ''; this._title = ''; this._label = ''; this._placeholder = ''; this._prepend = ''; this._append = ''; this._max = ''; this._isRequired = false; this._model = new BaseModel(); this.random = this.helperService.randChars(); this.displayWordCounterWarning = false; } ngAfterViewInit() { if (this.autoFocus) { this.inputBox.nativeElement.focus(); } } validateField() { const isValid = this.helperService.validateField(this._model, this._field); if (isValid) { this.changed.emit(this._model); } } setWordCounterWarning(value) { this.displayWordCounterWarning = value; } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: DdataInputComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); } static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.0.6", type: DdataInputComponent, isStandalone: false, selector: "dd-input", inputs: { disabled: "disabled", isViewOnly: "isViewOnly", type: "type", inputClass: "inputClass", labelClass: "labelClass", inputBlockClass: "inputBlockClass", inputBlockExtraClass: "inputBlockExtraClass", viewOnlyClass: "viewOnlyClass", wrapperClass: "wrapperClass", showLabel: "showLabel", autoFocus: "autoFocus", enableCharacterCounter: "enableCharacterCounter", enableWordCounter: "enableWordCounter", maxLength: "maxLength", maxWords: "maxWords", wordCounterWarningMessage: "wordCounterWarningMessage", model: "model", field: "field", append: "append", prepend: "prepend", labelText: "labelText" }, outputs: { changed: "changed", maxLengthReached: "maxLengthReached" }, viewQueries: [{ propertyName: "inputBox", first: true, predicate: ["inputBox"], descendants: true }], ngImport: i0, template: "<div [class]=\"wrapperClass\">\n <label [class]=\"labelClass\" [for]=\"_field + '_' + random\" *ngIf=\"showLabel\">\n {{ _label }}:\n <span *ngIf=\"_isRequired\"> *</span>\n </label>\n <div [class]=\"inputBlockClass\" [ngClass]=\"showLabel ? inputBlockExtraClass : ''\">\n <div class=\"input-group-prepend\" *ngIf=\"_prepend !== ''\">\n <div class=\"input-group-text\">{{ _prepend }}</div>\n </div>\n\n <ng-container *ngIf=\"!isViewOnly\">\n <input\n [class.invalid]=\"model.validationErrors.includes(_field)\"\n [class]=\"inputClass\"\n [(ngModel)]=\"model[_field]\"\n [id]=\"_field + '_' + random\"\n [attr.name]=\"_field + '_' + random\"\n [placeholder]=\"_placeholder\"\n [title]=\"_title\"\n [disabled]=\"disabled\"\n [type]=\"type\"\n [autocomplete]=\"random\"\n (keyup)=\"validateField()\"\n #inputBox\n />\n <ng-container *ngIf=\"enableCharacterCounter\">\n <dd-character-counter\n [currentLength]=\"model[_field]?.length || 0\"\n [maxLength]=\"maxLength\"\n ></dd-character-counter>\n </ng-container>\n <ng-container *ngIf=\"enableWordCounter\">\n <dd-word-counter\n [currentLength]=\"model[_field]\"\n [maxLength]=\"maxWords\"\n (maxLentghReached)=\"showWordCounterWarning = $event\"\n ></dd-word-counter>\n </ng-container>\n </ng-container>\n\n <ng-container *ngIf=\"isViewOnly\">\n <div\n [id]=\"_field + '_' + random\"\n [class]=\"viewOnlyClass\"\n [attr.name]=\"_field + '_' + random\"\n [title]=\"_title\"\n >\n {{ model[_field] }}\n </div>\n </ng-container>\n <div class=\"input-group-append\" *ngIf=\"_append !== ''\">\n <div class=\"input-group-text\">{{ _append }}</div>\n </div>\n </div>\n <div *ngIf=\"displayWordCounterWarning && wordCounterWarningMessage !== ''\" class=\"d-flex pb-2\">\n <div class=\"col-12 col-md-7 offset-md-3 bg-warning p-2 rounded\">\n {{ wordCounterWarningMessage }}\n </div>\n </div>\n</div>\n", styles: [".autocomplete-list-container{position:absolute;display:inline-block;top:100%;width:100%;transition:all .2s}.autocomplete-spinner-place{top:calc(100% + 40px);transition:all .2s}.autocomplete-list{position:absolute;border:1px solid #d4d4d4;border-bottom:none;border-top:none;z-index:99;top:100%;left:0;right:0;box-shadow:0 5px 10px #0000004d}.autocomplete-list-item{padding:10px;cursor:pointer;background-color:#fff;border-bottom:1px solid #d4d4d4}.autocomplete-list-item:hover{background-color:#e9e9e9}.active{background-color:#1e90ff!important;color:#fff}\n"], dependencies: [{ kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i2$1.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$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: DdataInputComponent, decorators: [{ type: Component, args: [{ selector: 'dd-input', changeDetection: ChangeDetectionStrategy.OnPush, standalone: false, template: "<div [class]=\"wrapperClass\">\n <label [class]=\"labelClass\" [for]=\"_field + '_' + random\" *ngIf=\"showLabel\">\n {{ _label }}:\n <span *ngIf=\"_isRequired\"> *</span>\n </label>\n <div [class]=\"inputBlockClass\" [ngClass]=\"showLabel ? inputBlockExtraClass : ''\">\n <div class=\"input-group-prepend\" *ngIf=\"_prepend !== ''\">\n <div class=\"input-group-text\">{{ _prepend }}</div>\n </div>\n\n <ng-container *ngIf=\"!isViewOnly\">\n <input\n [class.invalid]=\"model.validationErrors.includes(_field)\"\n [class]=\"inputClass\"\n [(ngModel)]=\"model[_field]\"\n [id]=\"_field + '_' + random\"\n [attr.name]=\"_field + '_' + random\"\n [placeholder]=\"_placeholder\"\n [title]=\"_title\"\n [disabled]=\"disabled\"\n [type]=\"type\"\n [autocomplete]=\"random\"\n (keyup)=\"validateField()\"\n #inputBox\n />\n <ng-container *ngIf=\"enableCharacterCounter\">\n <dd-character-counter\n [currentLength]=\"model[_field]?.length || 0\"\n [maxLength]=\"maxLength\"\n ></dd-character-counter>\n </ng-container>\n <ng-container *ngIf=\"enableWordCounter\">\n <dd-word-counter\n [currentLength]=\"model[_field]\"\n [maxLength]=\"maxWords\"\n (maxLentghReached)=\"showWordCounterWarning = $event\"\n ></dd-word-counter>\n </ng-container>\n </ng-container>\n\n <ng-container *ngIf=\"isViewOnly\">\n <div\n [id]=\"_field + '_' + random\"\n [class]=\"viewOnlyClass\"\n [attr.name]=\"_field + '_' + random\"\n [title]=\"_title\"\n >\n {{ model[_field] }}\n </div>\n </ng-container>\n <div class=\"input-group-append\" *ngIf=\"_append !== ''\">\n <div class=\"input-group-text\">{{ _append }}</div>\n </div>\n </div>\n <div *ngIf=\"displayWordCounterWarning && wordCounterWarningMessage !== ''\" class=\"d-flex pb-2\">\n <div class=\"col-12 col-md-7 offset-md-3 bg-warning p-2 rounded\">\n {{ wordCounterWarningMessage }}\n </div>\n </div>\n</div>\n", styles: [".autocomplete-list-container{position:absolute;display:inline-block;top:100%;width:100%;transition:all .2s}.autocomplete-spinner-place{top:calc(100% + 40px);transition:all .2s}.autocomplete-list{position:absolute;border:1px solid #d4d4d4;border-bottom:none;border-top:none;z-index:99;top:100%;left:0;right:0;box-shadow:0 5px 10px #0000004d}.autocomplete-list-item{padding:10px;cursor:pointer;background-color:#fff;border-bottom:1px solid #d4d4d4}.autocomplete-list-item:hover{background-color:#e9e9e9}.active{background-color:#1e90ff!important;color:#fff}\n"] }] }], ctorParameters: () => [], propDecorators: { disabled: [{ type: Input }], isViewOnly: [{ type: Input }], type: [{ type: Input }], inputClass: [{ type: Input }], labelClass: [{ type: Input }], inputBlockClass: [{ type: Input }], inputBlockExtraClass: [{ type: Input }], viewOnlyClass: [{ type: Input }], wrapperClass: [{ type: Input }], showLabel: [{ type: Input }], autoFocus: [{ type: Input }], enableCharacterCounter: [{ type: Input }], enableWordCounter: [{ type: Input }], maxLength: [{ type: Input }], maxWords: [{ type: Input }], wordCounterWarningMessage: [{ type: Input }], changed: [{ type: Output }], maxLengthReached: [{ type: Output }], inputBox: [{ type: ViewChild, args: ['inputBox'] }], model: [{ type: Input }], field: [{ type: Input }], append: [{ type: Input }], prepend: [{ type: Input }], labelText: [{ type: Input }] } }); class Search extends SearchAbstract { } class BaseSearch extends Search { } class SearchResult extends SearchResultAbstract { } class BaseSearchResult extends SearchResult { } class DdataInputSearchComponent { constructor(elementRef, router) { this.elementRef = elementRef; this.router = router; this.model = new BaseSearch().init(); this.pageNumber = 0; this.service = new ProxyFactoryService().get(BaseSearch); this.icon = { search: faSearch }; this.isActive = new BehaviorSubject(false); this.models = []; this.paginate = new Paginate(BaseSearchResult); this.spinner = DdataCoreModule.InjectorInstance.get(SpinnerService); } clickout(event) { if (!this.elementRef.nativeElement.contains(event.target)) { // click out of component this.close(); } } ngOnDestroy() { this.isActive.next(false); } close() { this.models = []; this.isActive.next(false); } search() { // don't run if search string is empty, but reset models & close previous connection if (this.model.searchText === '') { this.isActive.next(false); this.models = []; return; } // close previous connection this.isActive.next(false); return fromEvent(this.searchInput.nativeElement, 'keyup').pipe( // run after 500 ms of last keyup debounceTime(500), // run only if value is changed distinctUntilChanged(), // run only if search