@fovestta2/web-angular 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +24 -0
- package/esm2022/fovestta2-web-angular.mjs +5 -0
- package/esm2022/lib/fv-checkbox/fv-checkbox.component.mjs +40 -0
- package/esm2022/lib/fv-controls.module.mjs +83 -0
- package/esm2022/lib/fv-date-field/fv-date-field.component.mjs +125 -0
- package/esm2022/lib/fv-dropdown/fv-dropdown.component.mjs +121 -0
- package/esm2022/lib/fv-entry-field/fv-entry-field.component.mjs +106 -0
- package/esm2022/lib/fv-file-selector/fv-file-selector.component.mjs +139 -0
- package/esm2022/lib/fv-image-selector/fv-image-selector.component.mjs +156 -0
- package/esm2022/lib/fv-month-year-field/fv-month-year-field.component.mjs +120 -0
- package/esm2022/lib/fv-number-field/fv-number-field.component.mjs +108 -0
- package/esm2022/lib/fv-radio-group/fv-radio-group.component.mjs +47 -0
- package/esm2022/lib/fv-rich-text-editor/fv-rich-text-editor.component.mjs +163 -0
- package/esm2022/public-api.mjs +15 -0
- package/fesm2022/fovestta2-web-angular.mjs +1149 -0
- package/fesm2022/fovestta2-web-angular.mjs.map +1 -0
- package/index.d.ts +5 -0
- package/lib/fv-checkbox/fv-checkbox.component.d.ts +14 -0
- package/lib/fv-controls.module.d.ts +18 -0
- package/lib/fv-date-field/fv-date-field.component.d.ts +29 -0
- package/lib/fv-dropdown/fv-dropdown.component.d.ts +34 -0
- package/lib/fv-entry-field/fv-entry-field.component.d.ts +27 -0
- package/lib/fv-file-selector/fv-file-selector.component.d.ts +36 -0
- package/lib/fv-image-selector/fv-image-selector.component.d.ts +39 -0
- package/lib/fv-month-year-field/fv-month-year-field.component.d.ts +29 -0
- package/lib/fv-number-field/fv-number-field.component.d.ts +29 -0
- package/lib/fv-radio-group/fv-radio-group.component.d.ts +22 -0
- package/lib/fv-rich-text-editor/fv-rich-text-editor.component.d.ts +36 -0
- package/package.json +28 -0
- package/public-api.d.ts +11 -0
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import { Component, Input, Output, EventEmitter, ViewChild, } from '@angular/core';
|
|
2
|
+
import { CommonModule } from '@angular/common';
|
|
3
|
+
import { ReactiveFormsModule } from '@angular/forms';
|
|
4
|
+
import { Validator } from '@fovestta2/validation-engine';
|
|
5
|
+
import * as i0 from "@angular/core";
|
|
6
|
+
import * as i1 from "@angular/common";
|
|
7
|
+
export class FvFileSelectorComponent {
|
|
8
|
+
label = '';
|
|
9
|
+
placeholder = 'Select a file';
|
|
10
|
+
schema;
|
|
11
|
+
control;
|
|
12
|
+
disabled = false;
|
|
13
|
+
accept = '*/*'; // MIME types, e.g., 'application/pdf,image/*'
|
|
14
|
+
maxSize; // Maximum file size in bytes
|
|
15
|
+
valueChange = new EventEmitter();
|
|
16
|
+
blur = new EventEmitter();
|
|
17
|
+
fileInput;
|
|
18
|
+
errorMessage = null;
|
|
19
|
+
selectedFile = null;
|
|
20
|
+
subscription;
|
|
21
|
+
ngOnInit() {
|
|
22
|
+
if (!this.control) {
|
|
23
|
+
console.error('FvFileSelector: control is required');
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
if (!this.schema) {
|
|
27
|
+
console.warn('FvFileSelector: schema is not provided, validation will be skipped');
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
// Subscribe to value changes
|
|
31
|
+
this.subscription = this.control.valueChanges.subscribe((value) => {
|
|
32
|
+
this.validateValue(value);
|
|
33
|
+
this.valueChange.emit(value);
|
|
34
|
+
});
|
|
35
|
+
// Validate initial value
|
|
36
|
+
if (this.control.value) {
|
|
37
|
+
this.selectedFile = this.control.value;
|
|
38
|
+
this.validateValue(this.control.value);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
ngOnDestroy() {
|
|
42
|
+
this.subscription?.unsubscribe();
|
|
43
|
+
}
|
|
44
|
+
validateValue(value) {
|
|
45
|
+
if (!this.schema)
|
|
46
|
+
return;
|
|
47
|
+
const result = Validator.validate(value, this.schema);
|
|
48
|
+
this.errorMessage = result.errorKey;
|
|
49
|
+
if (!result.isValid && result.errorKey) {
|
|
50
|
+
this.control.setErrors({ [result.errorKey]: true });
|
|
51
|
+
}
|
|
52
|
+
else {
|
|
53
|
+
this.control.setErrors(null);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
onFileSelected(event) {
|
|
57
|
+
const input = event.target;
|
|
58
|
+
if (input.files && input.files.length > 0) {
|
|
59
|
+
const file = input.files[0];
|
|
60
|
+
// Check file size if maxSize is specified
|
|
61
|
+
if (this.maxSize && file.size > this.maxSize) {
|
|
62
|
+
alert(`File size exceeds the maximum allowed size of ${this.formatFileSize(this.maxSize)}`);
|
|
63
|
+
// Reset the input
|
|
64
|
+
input.value = '';
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
const fileInfo = {
|
|
68
|
+
file: file,
|
|
69
|
+
name: file.name,
|
|
70
|
+
size: file.size,
|
|
71
|
+
type: file.type,
|
|
72
|
+
};
|
|
73
|
+
this.selectedFile = fileInfo;
|
|
74
|
+
this.control.setValue(fileInfo);
|
|
75
|
+
this.blur.emit();
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
openFileDialog() {
|
|
79
|
+
if (!this.disabled) {
|
|
80
|
+
this.fileInput.nativeElement.click();
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
removeFile() {
|
|
84
|
+
this.selectedFile = null;
|
|
85
|
+
this.control.setValue(null);
|
|
86
|
+
if (this.fileInput) {
|
|
87
|
+
this.fileInput.nativeElement.value = '';
|
|
88
|
+
}
|
|
89
|
+
this.blur.emit();
|
|
90
|
+
}
|
|
91
|
+
formatFileSize(bytes) {
|
|
92
|
+
if (bytes === 0)
|
|
93
|
+
return '0 Bytes';
|
|
94
|
+
const k = 1024;
|
|
95
|
+
const sizes = ['Bytes', 'KB', 'MB', 'GB'];
|
|
96
|
+
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
|
97
|
+
return Math.round((bytes / Math.pow(k, i)) * 100) / 100 + ' ' + sizes[i];
|
|
98
|
+
}
|
|
99
|
+
isRequired() {
|
|
100
|
+
return (this.schema?.rules?.some((r) => r.name === 'required' && r.params?.['enabled']) || false);
|
|
101
|
+
}
|
|
102
|
+
getErrorMessage() {
|
|
103
|
+
if (!this.errorMessage)
|
|
104
|
+
return '';
|
|
105
|
+
const errorMessages = {
|
|
106
|
+
ERR_REQUIRED: 'This field is required',
|
|
107
|
+
ERR_INVALID_FILE: 'Invalid file',
|
|
108
|
+
};
|
|
109
|
+
return errorMessages[this.errorMessage] || this.errorMessage;
|
|
110
|
+
}
|
|
111
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: FvFileSelectorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
112
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.14", type: FvFileSelectorComponent, isStandalone: true, selector: "fv-file-selector", inputs: { label: "label", placeholder: "placeholder", schema: "schema", control: "control", disabled: "disabled", accept: "accept", maxSize: "maxSize" }, outputs: { valueChange: "valueChange", blur: "blur" }, viewQueries: [{ propertyName: "fileInput", first: true, predicate: ["fileInput"], descendants: true }], ngImport: i0, template: "<div class=\"fv-file-selector-container\">\r\n <label *ngIf=\"label\" class=\"fv-file-selector-label\">\r\n {{ label }}\r\n <span *ngIf=\"isRequired()\" class=\"required-asterisk\">*</span>\r\n </label>\r\n\r\n <input #fileInput type=\"file\" [accept]=\"accept\" (change)=\"onFileSelected($event)\" style=\"display: none\" />\r\n\r\n <button type=\"button\" class=\"fv-file-selector-button\" [class.fv-file-selector-button-error]=\"errorMessage\"\r\n [class.fv-file-selector-button-disabled]=\"disabled\" (click)=\"openFileDialog()\" [disabled]=\"disabled\">\r\n {{ placeholder }}\r\n </button>\r\n\r\n <div *ngIf=\"selectedFile\" class=\"fv-file-info\">\r\n <div class=\"fv-file-details\">\r\n <div class=\"fv-file-name\">\uD83D\uDCC4 {{ selectedFile.name }}</div>\r\n <div class=\"fv-file-size\">{{ formatFileSize(selectedFile.size) }}</div>\r\n </div>\r\n <button type=\"button\" class=\"fv-file-remove\" (click)=\"removeFile()\" [disabled]=\"disabled\">\r\n \u2715\r\n </button>\r\n </div>\r\n\r\n <div *ngIf=\"errorMessage\" class=\"fv-file-selector-error-message\">\r\n \u26A0 {{ getErrorMessage() }}\r\n </div>\r\n</div>", styles: [".fv-file-selector-container{display:flex;flex-direction:column;margin-bottom:16px;width:100%}.fv-file-selector-label{font-size:14px;font-weight:500;color:#333;margin-bottom:6px;display:block}.required-asterisk{color:#dc3545;font-weight:700}.fv-file-selector-button{padding:10px;border:1px solid #007bff;border-radius:4px;background-color:#007bff;color:#fff;font-size:14px;font-weight:500;cursor:pointer;transition:background-color .2s,border-color .2s;text-align:center}.fv-file-selector-button:hover:not(:disabled){background-color:#0056b3;border-color:#0056b3}.fv-file-selector-button-error{border-color:#dc3545;background-color:#dc3545}.fv-file-selector-button-error:hover:not(:disabled){background-color:#c82333;border-color:#c82333}.fv-file-selector-button-disabled{background-color:#ccc;border-color:#ccc;opacity:.6;cursor:not-allowed}.fv-file-info{display:flex;align-items:center;margin-top:8px;padding:10px;background-color:#f8f9fa;border:1px solid #dee2e6;border-radius:4px}.fv-file-details{flex:1}.fv-file-name{font-size:14px;color:#333;margin-bottom:4px;word-break:break-all}.fv-file-size{font-size:12px;color:#6c757d}.fv-file-remove{padding:4px 8px;margin-left:8px;background:none;border:none;font-size:18px;color:#dc3545;font-weight:700;cursor:pointer;transition:color .2s}.fv-file-remove:hover:not(:disabled){color:#c82333}.fv-file-remove:disabled{opacity:.5;cursor:not-allowed}.fv-file-selector-error-message{margin-top:4px;font-size:12px;color:#dc3545}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: ReactiveFormsModule }] });
|
|
113
|
+
}
|
|
114
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: FvFileSelectorComponent, decorators: [{
|
|
115
|
+
type: Component,
|
|
116
|
+
args: [{ standalone: true, imports: [CommonModule, ReactiveFormsModule], selector: 'fv-file-selector', template: "<div class=\"fv-file-selector-container\">\r\n <label *ngIf=\"label\" class=\"fv-file-selector-label\">\r\n {{ label }}\r\n <span *ngIf=\"isRequired()\" class=\"required-asterisk\">*</span>\r\n </label>\r\n\r\n <input #fileInput type=\"file\" [accept]=\"accept\" (change)=\"onFileSelected($event)\" style=\"display: none\" />\r\n\r\n <button type=\"button\" class=\"fv-file-selector-button\" [class.fv-file-selector-button-error]=\"errorMessage\"\r\n [class.fv-file-selector-button-disabled]=\"disabled\" (click)=\"openFileDialog()\" [disabled]=\"disabled\">\r\n {{ placeholder }}\r\n </button>\r\n\r\n <div *ngIf=\"selectedFile\" class=\"fv-file-info\">\r\n <div class=\"fv-file-details\">\r\n <div class=\"fv-file-name\">\uD83D\uDCC4 {{ selectedFile.name }}</div>\r\n <div class=\"fv-file-size\">{{ formatFileSize(selectedFile.size) }}</div>\r\n </div>\r\n <button type=\"button\" class=\"fv-file-remove\" (click)=\"removeFile()\" [disabled]=\"disabled\">\r\n \u2715\r\n </button>\r\n </div>\r\n\r\n <div *ngIf=\"errorMessage\" class=\"fv-file-selector-error-message\">\r\n \u26A0 {{ getErrorMessage() }}\r\n </div>\r\n</div>", styles: [".fv-file-selector-container{display:flex;flex-direction:column;margin-bottom:16px;width:100%}.fv-file-selector-label{font-size:14px;font-weight:500;color:#333;margin-bottom:6px;display:block}.required-asterisk{color:#dc3545;font-weight:700}.fv-file-selector-button{padding:10px;border:1px solid #007bff;border-radius:4px;background-color:#007bff;color:#fff;font-size:14px;font-weight:500;cursor:pointer;transition:background-color .2s,border-color .2s;text-align:center}.fv-file-selector-button:hover:not(:disabled){background-color:#0056b3;border-color:#0056b3}.fv-file-selector-button-error{border-color:#dc3545;background-color:#dc3545}.fv-file-selector-button-error:hover:not(:disabled){background-color:#c82333;border-color:#c82333}.fv-file-selector-button-disabled{background-color:#ccc;border-color:#ccc;opacity:.6;cursor:not-allowed}.fv-file-info{display:flex;align-items:center;margin-top:8px;padding:10px;background-color:#f8f9fa;border:1px solid #dee2e6;border-radius:4px}.fv-file-details{flex:1}.fv-file-name{font-size:14px;color:#333;margin-bottom:4px;word-break:break-all}.fv-file-size{font-size:12px;color:#6c757d}.fv-file-remove{padding:4px 8px;margin-left:8px;background:none;border:none;font-size:18px;color:#dc3545;font-weight:700;cursor:pointer;transition:color .2s}.fv-file-remove:hover:not(:disabled){color:#c82333}.fv-file-remove:disabled{opacity:.5;cursor:not-allowed}.fv-file-selector-error-message{margin-top:4px;font-size:12px;color:#dc3545}\n"] }]
|
|
117
|
+
}], propDecorators: { label: [{
|
|
118
|
+
type: Input
|
|
119
|
+
}], placeholder: [{
|
|
120
|
+
type: Input
|
|
121
|
+
}], schema: [{
|
|
122
|
+
type: Input
|
|
123
|
+
}], control: [{
|
|
124
|
+
type: Input
|
|
125
|
+
}], disabled: [{
|
|
126
|
+
type: Input
|
|
127
|
+
}], accept: [{
|
|
128
|
+
type: Input
|
|
129
|
+
}], maxSize: [{
|
|
130
|
+
type: Input
|
|
131
|
+
}], valueChange: [{
|
|
132
|
+
type: Output
|
|
133
|
+
}], blur: [{
|
|
134
|
+
type: Output
|
|
135
|
+
}], fileInput: [{
|
|
136
|
+
type: ViewChild,
|
|
137
|
+
args: ['fileInput']
|
|
138
|
+
}] } });
|
|
139
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZnYtZmlsZS1zZWxlY3Rvci5jb21wb25lbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi9wcm9qZWN0cy9mdi1jb250cm9scy9zcmMvbGliL2Z2LWZpbGUtc2VsZWN0b3IvZnYtZmlsZS1zZWxlY3Rvci5jb21wb25lbnQudHMiLCIuLi8uLi8uLi8uLi8uLi9wcm9qZWN0cy9mdi1jb250cm9scy9zcmMvbGliL2Z2LWZpbGUtc2VsZWN0b3IvZnYtZmlsZS1zZWxlY3Rvci5jb21wb25lbnQuaHRtbCJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQ0gsU0FBUyxFQUNULEtBQUssRUFDTCxNQUFNLEVBQ04sWUFBWSxFQUdaLFNBQVMsR0FFWixNQUFNLGVBQWUsQ0FBQztBQUN2QixPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0saUJBQWlCLENBQUM7QUFDL0MsT0FBTyxFQUFlLG1CQUFtQixFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFFbEUsT0FBTyxFQUFFLFNBQVMsRUFBb0IsTUFBTSw4QkFBOEIsQ0FBQzs7O0FBZ0IzRSxNQUFNLE9BQU8sdUJBQXVCO0lBQ3ZCLEtBQUssR0FBVyxFQUFFLENBQUM7SUFDbkIsV0FBVyxHQUFXLGVBQWUsQ0FBQztJQUN0QyxNQUFNLENBQW9CO0lBQzFCLE9BQU8sQ0FBZTtJQUN0QixRQUFRLEdBQVksS0FBSyxDQUFDO0lBQzFCLE1BQU0sR0FBVyxLQUFLLENBQUMsQ0FBQyw4Q0FBOEM7SUFDdEUsT0FBTyxDQUFVLENBQUMsNkJBQTZCO0lBRTlDLFdBQVcsR0FBRyxJQUFJLFlBQVksRUFBbUIsQ0FBQztJQUNsRCxJQUFJLEdBQUcsSUFBSSxZQUFZLEVBQVEsQ0FBQztJQUVsQixTQUFTLENBQWdDO0lBRWpFLFlBQVksR0FBa0IsSUFBSSxDQUFDO0lBQ25DLFlBQVksR0FBb0IsSUFBSSxDQUFDO0lBQzdCLFlBQVksQ0FBZ0I7SUFFcEMsUUFBUTtRQUNKLElBQUksQ0FBQyxJQUFJLENB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QyxDQUFDLEVBQUUsRUFBRSxDQUFDLENBQUMsQ0FBQyxJQUFJLEtBQUssVUFBVSxJQUFJLENBQUMsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxTQUFTLENBQUMsQ0FDeEQsSUFBSSxLQUFLLENBQ2IsQ0FBQztJQUNOLENBQUM7SUFFRCxlQUFlO1FBQ1gsSUFBSSxDQUFDLElBQUksQ0FBQyxZQUFZO1lBQUUsT0FBTyxFQUFFLENBQUM7UUFFbEMsTUFBTSxhQUFhLEdBQTJCO1lBQzFDLFlBQVksRUFBRSx3QkFBd0I7WUFDdEMsZ0JBQWdCLEVBQUUsY0FBYztTQUNuQyxDQUFDO1FBRUYsT0FBTyxhQUFhLENBQUMsSUFBSSxDQUFDLFlBQVksQ0FBQyxJQUFJLElBQUksQ0FBQyxZQUFZLENBQUM7SUFDakUsQ0FBQzt3R0FuSVEsdUJBQXVCOzRGQUF2Qix1QkFBdUIscVlDN0JwQyxvdUNBMEJNLHUvQ0RGUSxZQUFZLGtJQUFFLG1CQUFtQjs7NEZBS2xDLHVCQUF1QjtrQkFQbkMsU0FBUztpQ0FDTSxJQUFJLFdBQ1AsQ0FBQyxZQUFZLEVBQUUsbUJBQW1CLENBQUMsWUFDbEMsa0JBQWtCOzhCQUtuQixLQUFLO3NCQUFiLEtBQUs7Z0JBQ0csV0FBVztzQkFBbkIsS0FBSztnQkFDRyxNQUFNO3NCQUFkLEtBQUs7Z0JBQ0csT0FBTztzQkFBZixLQUFLO2dCQUNHLFFBQVE7c0JBQWhCLEtBQUs7Z0JBQ0csTUFBTTtzQkFBZCxLQUFLO2dCQUNHLE9BQU87c0JBQWYsS0FBSztnQkFFSSxXQUFXO3NCQUFwQixNQUFNO2dCQUNHLElBQUk7c0JBQWIsTUFBTTtnQkFFaUIsU0FBUztzQkFBaEMsU0FBUzt1QkFBQyxXQUFXIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHtcclxuICAgIENvbXBvbmVudCxcclxuICAgIElucHV0LFxyXG4gICAgT3V0cHV0LFxyXG4gICAgRXZlbnRFbWl0dGVyLFxyXG4gICAgT25Jbml0LFxyXG4gICAgT25EZXN0cm95LFxyXG4gICAgVmlld0NoaWxkLFxyXG4gICAgRWxlbWVudFJlZixcclxufSBmcm9tICdAYW5ndWxhci9jb3JlJztcclxuaW1wb3J0IHsgQ29tbW9uTW9kdWxlIH0gZnJvbSAnQGFuZ3VsYXIvY29tbW9uJztcclxuaW1wb3J0IHsgRm9ybUNvbnRyb2wsIFJlYWN0aXZlRm9ybXNNb2R1bGUgfSBmcm9tICdAYW5ndWxhci9mb3Jtcyc7XHJcbmltcG9ydCB7IFN1YnNjcmlwdGlvbiB9IGZyb20gJ3J4anMnO1xyXG5pbXBvcnQgeyBWYWxpZGF0b3IsIFZhbGlkYXRpb25TY2hlbWEgfSBmcm9tICdAZm92ZXN0dGEyL3ZhbGlkYXRpb24tZW5naW5lJztcclxuXHJcbmV4cG9ydCBpbnRlcmZhY2UgRmlsZUluZm8ge1xyXG4gICAgZmlsZTogRmlsZTtcclxuICAgIG5hbWU6IHN0cmluZztcclxuICAgIHNpemU6IG51bWJlcjtcclxuICAgIHR5cGU6IHN0cmluZztcclxufVxyXG5cclxuQENvbXBvbmVudCh7XHJcbiAgICBzdGFuZGFsb25lOiB0cnVlLFxyXG4gICAgaW1wb3J0czogW0NvbW1vbk1vZHVsZSwgUmVhY3RpdmVGb3Jtc01vZHVsZV0sXHJcbiAgICBzZWxlY3RvcjogJ2Z2LWZpbGUtc2VsZWN0b3InLFxyXG4gICAgdGVtcGxhdGVVcmw6ICcuL2Z2LWZpbGUtc2VsZWN0b3IuY29tcG9uZW50Lmh0bWwnLFxyXG4gICAgc3R5bGVVcmw6ICcuL2Z2LWZpbGUtc2VsZWN0b3IuY29tcG9uZW50LmNzcycsXHJcbn0pXHJcbmV4cG9ydCBjbGFzcyBGdkZpbGVTZWxlY3RvckNvbXBvbmVudCBpbXBsZW1lbnRzIE9uSW5pdCwgT25EZXN0cm95IHtcclxuICAgIEBJbnB1dCgpIGxhYmVsOiBzdHJpbmcgPSAnJztcclxuICAgIEBJbnB1dCgpIHBsYWNlaG9sZGVyOiBzdHJpbmcgPSAnU2VsZWN0IGEgZmlsZSc7XHJcbiAgICBASW5wdXQoKSBzY2hlbWEhOiBWYWxpZGF0aW9uU2NoZW1hO1xyXG4gICAgQElucHV0KCkgY29udHJvbCE6IEZvcm1Db250cm9sO1xyXG4gICAgQElucHV0KCkgZGlzYWJsZWQ6IGJvb2xlYW4gPSBmYWxzZTtcclxuICAgIEBJbnB1dCgpIGFjY2VwdDogc3RyaW5nID0gJyovKic7IC8vIE1JTUUgdHlwZXMsIGUuZy4sICdhcHBsaWNhdGlvbi9wZGYsaW1hZ2UvKidcclxuICAgIEBJbnB1dCgpIG1heFNpemU/OiBudW1iZXI7IC8vIE1heGltdW0gZmlsZSBzaXplIGluIGJ5dGVzXHJcblxyXG4gICAgQE91dHB1dCgpIHZhbHVlQ2hhbmdlID0gbmV3IEV2ZW50RW1pdHRlcjxGaWxlSW5mbyB8IG51bGw+KCk7XHJcbiAgICBAT3V0cHV0KCkgYmx1ciA9IG5ldyBFdmVudEVtaXR0ZXI8dm9pZD4oKTtcclxuXHJcbiAgICBAVmlld0NoaWxkKCdmaWxlSW5wdXQnKSBmaWxlSW5wdXQhOiBFbGVtZW50UmVmPEhUTUxJbnB1dEVsZW1lbnQ+O1xyXG5cclxuICAgIGVycm9yTWVzc2FnZTogc3RyaW5nIHwgbnVsbCA9IG51bGw7XHJcbiAgICBzZWxlY3RlZEZpbGU6IEZpbGVJbmZvIHwgbnVsbCA9IG51bGw7XHJcbiAgICBwcml2YXRlIHN1YnNjcmlwdGlvbj86IFN1YnNjcmlwdGlvbjtcclxuXHJcbiAgICBuZ09uSW5pdCgpOiB2b2lkIHtcclxuICAgICAgICBpZiAoIXRoaXMuY29udHJvbCkge1xyXG4gICAgICAgICAgICBjb25zb2xlLmVycm9yKCdGdkZpbGVTZWxlY3RvcjogY29udHJvbCBpcyByZXF1aXJlZCcpO1xyXG4gICAgICAgICAgICByZXR1cm47XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICBpZiAoIXRoaXMuc2NoZW1hKSB7XHJcbiAgICAgICAgICAgIGNvbnNvbGUud2FybihcclxuICAgICAgICAgICAgICAgICdGdkZpbGVTZWxlY3Rvcjogc2NoZW1hIGlzIG5vdCBwcm92aWRlZCwgdmFsaWRhdGlvbiB3aWxsIGJlIHNraXBwZWQnXHJcbiAgICAgICAgICAgICk7XHJcbiAgICAgICAgICAgIHJldHVybjtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIC8vIFN1YnNjcmliZSB0byB2YWx1ZSBjaGFuZ2VzXHJcbiAgICAgICAgdGhpcy5zdWJzY3JpcHRpb24gPSB0aGlzLmNvbnRyb2wudmFsdWVDaGFuZ2VzLnN1YnNjcmliZSgodmFsdWUpID0+IHtcclxuICAgICAgICAgICAgdGhpcy52YWxpZGF0ZVZhbHVlKHZhbHVlKTtcclxuICAgICAgICAgICAgdGhpcy52YWx1ZUNoYW5nZS5lbWl0KHZhbHVlKTtcclxuICAgICAgICB9KTtcclxuXHJcbiAgICAgICAgLy8gVmFsaWRhdGUgaW5pdGlhbCB2YWx1ZVxyXG4gICAgICAgIGlmICh0aGlzLmNvbnRyb2wudmFsdWUpIHtcclxuICAgICAgICAgICAgdGhpcy5zZWxlY3RlZEZpbGUgPSB0aGlzLmNvbnRyb2wudmFsdWU7XHJcbiAgICAgICAgICAgIHRoaXMudmFsaWRhdGVWYWx1ZSh0aGlzLmNvbnRyb2wudmFsdWUpO1xyXG4gICAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICBuZ09uRGVzdHJveSgpOiB2b2lkIHtcclxuICAgICAgICB0aGlzLnN1YnNjcmlwdGlvbj8udW5zdWJzY3JpYmUoKTtcclxuICAgIH1cclxuXHJcbiAgICBwcml2YXRlIHZhbGlkYXRlVmFsdWUodmFsdWU6IGFueSk6IHZvaWQge1xyXG4gICAgICAgIGlmICghdGhpcy5zY2hlbWEpIHJldHVybjtcclxuXHJcbiAgICAgICAgY29uc3QgcmVzdWx0ID0gVmFsaWRhdG9yLnZhbGlkYXRlKHZhbHVlLCB0aGlzLnNjaGVtYSk7XHJcbiAgICAgICAgdGhpcy5lcnJvck1lc3NhZ2UgPSByZXN1bHQuZXJyb3JLZXk7XHJcblxyXG4gICAgICAgIGlmICghcmVzdWx0LmlzVmFsaWQgJiYgcmVzdWx0LmVycm9yS2V5KSB7XHJcbiAgICAgICAgICAgIHRoaXMuY29udHJvbC5zZXRFcnJvcnMoeyBbcmVzdWx0LmVycm9yS2V5XTogdHJ1ZSB9KTtcclxuICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgICB0aGlzLmNvbnRyb2wuc2V0RXJyb3JzKG51bGwpO1xyXG4gICAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICBvbkZpbGVTZWxlY3RlZChldmVudDogRXZlbnQpOiB2b2lkIHtcclxuICAgICAgICBjb25zdCBpbnB1dCA9IGV2ZW50LnRhcmdldCBhcyBIVE1MSW5wdXRFbGVtZW50O1xyXG4gICAgICAgIGlmIChpbnB1dC5maWxlcyAmJiBpbnB1dC5maWxlcy5sZW5ndGggPiAwKSB7XHJcbiAgICAgICAgICAgIGNvbnN0IGZpbGUgPSBpbnB1dC5maWxlc1swXTtcclxuXHJcbiAgICAgICAgICAgIC8vIENoZWNrIGZpbGUgc2l6ZSBpZiBtYXhTaXplIGlzIHNwZWNpZmllZFxyXG4gICAgICAgICAgICBpZiAodGhpcy5tYXhTaXplICYmIGZpbGUuc2l6ZSA+IHRoaXMubWF4U2l6ZSkge1xyXG4gICAgICAgICAgICAgICAgYWxlcnQoXHJcbiAgICAgICAgICAgICAgICAgICAgYEZpbGUgc2l6ZSBleGNlZWRzIHRoZSBtYXhpbXVtIGFsbG93ZWQgc2l6ZSBvZiAke3RoaXMuZm9ybWF0RmlsZVNpemUoXHJcbiAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMubWF4U2l6ZVxyXG4gICAgICAgICAgICAgICAgICAgICl9YFxyXG4gICAgICAgICAgICAgICAgKTtcclxuICAgICAgICAgICAgICAgIC8vIFJlc2V0IHRoZSBpbnB1dFxyXG4gICAgICAgICAgICAgICAgaW5wdXQudmFsdWUgPSAnJztcclxuICAgICAgICAgICAgICAgIHJldHVybjtcclxuICAgICAgICAgICAgfVxyXG5cclxuICAgICAgICAgICAgY29uc3QgZmlsZUluZm86IEZpbGVJbmZvID0ge1xyXG4gICAgICAgICAgICAgICAgZmlsZTogZmlsZSxcclxuICAgICAgICAgICAgICAgIG5hbWU6IGZpbGUubmFtZSxcclxuICAgICAgICAgICAgICAgIHNpemU6IGZpbGUuc2l6ZSxcclxuICAgICAgICAgICAgICAgIHR5cGU6IGZpbGUudHlwZSxcclxuICAgICAgICAgICAgfTtcclxuXHJcbiAgICAgICAgICAgIHRoaXMuc2VsZWN0ZWRGaWxlID0gZmlsZUluZm87XHJcbiAgICAgICAgICAgIHRoaXMuY29udHJvbC5zZXRWYWx1ZShmaWxlSW5mbyk7XHJcbiAgICAgICAgICAgIHRoaXMuYmx1ci5lbWl0KCk7XHJcbiAgICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIG9wZW5GaWxlRGlhbG9nKCk6IHZvaWQge1xyXG4gICAgICAgIGlmICghdGhpcy5kaXNhYmxlZCkge1xyXG4gICAgICAgICAgICB0aGlzLmZpbGVJbnB1dC5uYXRpdmVFbGVtZW50LmNsaWNrKCk7XHJcbiAgICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIHJlbW92ZUZpbGUoKTogdm9pZCB7XHJcbiAgICAgICAgdGhpcy5zZWxlY3RlZEZpbGUgPSBudWxsO1xyXG4gICAgICAgIHRoaXMuY29udHJvbC5zZXRWYWx1ZShudWxsKTtcclxuICAgICAgICBpZiAodGhpcy5maWxlSW5wdXQpIHtcclxuICAgICAgICAgICAgdGhpcy5maWxlSW5wdXQubmF0aXZlRWxlbWVudC52YWx1ZSA9ICcnO1xyXG4gICAgICAgIH1cclxuICAgICAgICB0aGlzLmJsdXIuZW1pdCgpO1xyXG4gICAgfVxyXG5cclxuICAgIGZvcm1hdEZpbGVTaXplKGJ5dGVzOiBudW1iZXIpOiBzdHJpbmcge1xyXG4gICAgICAgIGlmIChieXRlcyA9PT0gMCkgcmV0dXJuICcwIEJ5dGVzJztcclxuICAgICAgICBjb25zdCBrID0gMTAyNDtcclxuICAgICAgICBjb25zdCBzaXplcyA9IFsnQnl0ZXMnLCAnS0InLCAnTUInLCAnR0InXTtcclxuICAgICAgICBjb25zdCBpID0gTWF0aC5mbG9vcihNYXRoLmxvZyhieXRlcykgLyBNYXRoLmxvZyhrKSk7XHJcbiAgICAgICAgcmV0dXJuIE1hdGgucm91bmQoKGJ5dGVzIC8gTWF0aC5wb3coaywgaSkpICogMTAwKSAvIDEwMCArICcgJyArIHNpemVzW2ldO1xyXG4gICAgfVxyXG5cclxuICAgIGlzUmVxdWlyZWQoKTogYm9vbGVhbiB7XHJcbiAgICAgICAgcmV0dXJuIChcclxuICAgICAgICAgICAgdGhpcy5zY2hlbWE/LnJ1bGVzPy5zb21lKFxyXG4gICAgICAgICAgICAgICAgKHIpID0+IHIubmFtZSA9PT0gJ3JlcXVpcmVkJyAmJiByLnBhcmFtcz8uWydlbmFibGVkJ11cclxuICAgICAgICAgICAgKSB8fCBmYWxzZVxyXG4gICAgICAgICk7XHJcbiAgICB9XHJcblxyXG4gICAgZ2V0RXJyb3JNZXNzYWdlKCk6IHN0cmluZyB7XHJcbiAgICAgICAgaWYgKCF0aGlzLmVycm9yTWVzc2FnZSkgcmV0dXJuICcnO1xyXG5cclxuICAgICAgICBjb25zdCBlcnJvck1lc3NhZ2VzOiBSZWNvcmQ8c3RyaW5nLCBzdHJpbmc+ID0ge1xyXG4gICAgICAgICAgICBFUlJfUkVRVUlSRUQ6ICdUaGlzIGZpZWxkIGlzIHJlcXVpcmVkJyxcclxuICAgICAgICAgICAgRVJSX0lOVkFMSURfRklMRTogJ0ludmFsaWQgZmlsZScsXHJcbiAgICAgICAgfTtcclxuXHJcbiAgICAgICAgcmV0dXJuIGVycm9yTWVzc2FnZXNbdGhpcy5lcnJvck1lc3NhZ2VdIHx8IHRoaXMuZXJyb3JNZXNzYWdlO1xyXG4gICAgfVxyXG59XHJcbiIsIjxkaXYgY2xhc3M9XCJmdi1maWxlLXNlbGVjdG9yLWNvbnRhaW5lclwiPlxyXG4gICAgPGxhYmVsICpuZ0lmPVwibGFiZWxcIiBjbGFzcz1cImZ2LWZpbGUtc2VsZWN0b3ItbGFiZWxcIj5cclxuICAgICAgICB7eyBsYWJlbCB9fVxyXG4gICAgICAgIDxzcGFuICpuZ0lmPVwiaXNSZXF1aXJlZCgpXCIgY2xhc3M9XCJyZXF1aXJlZC1hc3Rlcmlza1wiPio8L3NwYW4+XHJcbiAgICA8L2xhYmVsPlxyXG5cclxuICAgIDxpbnB1dCAjZmlsZUlucHV0IHR5cGU9XCJmaWxlXCIgW2FjY2VwdF09XCJhY2NlcHRcIiAoY2hhbmdlKT1cIm9uRmlsZVNlbGVjdGVkKCRldmVudClcIiBzdHlsZT1cImRpc3BsYXk6IG5vbmVcIiAvPlxyXG5cclxuICAgIDxidXR0b24gdHlwZT1cImJ1dHRvblwiIGNsYXNzPVwiZnYtZmlsZS1zZWxlY3Rvci1idXR0b25cIiBbY2xhc3MuZnYtZmlsZS1zZWxlY3Rvci1idXR0b24tZXJyb3JdPVwiZXJyb3JNZXNzYWdlXCJcclxuICAgICAgICBbY2xhc3MuZnYtZmlsZS1zZWxlY3Rvci1idXR0b24tZGlzYWJsZWRdPVwiZGlzYWJsZWRcIiAoY2xpY2spPVwib3BlbkZpbGVEaWFsb2coKVwiIFtkaXNhYmxlZF09XCJkaXNhYmxlZFwiPlxyXG4gICAgICAgIHt7IHBsYWNlaG9sZGVyIH19XHJcbiAgICA8L2J1dHRvbj5cclxuXHJcbiAgICA8ZGl2ICpuZ0lmPVwic2VsZWN0ZWRGaWxlXCIgY2xhc3M9XCJmdi1maWxlLWluZm9cIj5cclxuICAgICAgICA8ZGl2IGNsYXNzPVwiZnYtZmlsZS1kZXRhaWxzXCI+XHJcbiAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJmdi1maWxlLW5hbWVcIj7wn5OEIHt7IHNlbGVjdGVkRmlsZS5uYW1lIH19PC9kaXY+XHJcbiAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJmdi1maWxlLXNpemVcIj57eyBmb3JtYXRGaWxlU2l6ZShzZWxlY3RlZEZpbGUuc2l6ZSkgfX08L2Rpdj5cclxuICAgICAgICA8L2Rpdj5cclxuICAgICAgICA8YnV0dG9uIHR5cGU9XCJidXR0b25cIiBjbGFzcz1cImZ2LWZpbGUtcmVtb3ZlXCIgKGNsaWNrKT1cInJlbW92ZUZpbGUoKVwiIFtkaXNhYmxlZF09XCJkaXNhYmxlZFwiPlxyXG4gICAgICAgICAgICDinJVcclxuICAgICAgICA8L2J1dHRvbj5cclxuICAgIDwvZGl2PlxyXG5cclxuICAgIDxkaXYgKm5nSWY9XCJlcnJvck1lc3NhZ2VcIiBjbGFzcz1cImZ2LWZpbGUtc2VsZWN0b3ItZXJyb3ItbWVzc2FnZVwiPlxyXG4gICAgICAgIOKaoCB7eyBnZXRFcnJvck1lc3NhZ2UoKSB9fVxyXG4gICAgPC9kaXY+XHJcbjwvZGl2PiJdfQ==
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
import { Component, Input, Output, EventEmitter, ViewChild, } from '@angular/core';
|
|
2
|
+
import { CommonModule } from '@angular/common';
|
|
3
|
+
import { ReactiveFormsModule } from '@angular/forms';
|
|
4
|
+
import { Validator } from '@fovestta2/validation-engine';
|
|
5
|
+
import * as i0 from "@angular/core";
|
|
6
|
+
import * as i1 from "@angular/platform-browser";
|
|
7
|
+
import * as i2 from "@angular/common";
|
|
8
|
+
export class FvImageSelectorComponent {
|
|
9
|
+
sanitizer;
|
|
10
|
+
label = '';
|
|
11
|
+
placeholder = 'Select an image';
|
|
12
|
+
schema;
|
|
13
|
+
control;
|
|
14
|
+
disabled = false;
|
|
15
|
+
maxSize; // Maximum file size in bytes
|
|
16
|
+
valueChange = new EventEmitter();
|
|
17
|
+
blur = new EventEmitter();
|
|
18
|
+
imageInput;
|
|
19
|
+
errorMessage = null;
|
|
20
|
+
selectedImage = null;
|
|
21
|
+
subscription;
|
|
22
|
+
constructor(sanitizer) {
|
|
23
|
+
this.sanitizer = sanitizer;
|
|
24
|
+
}
|
|
25
|
+
ngOnInit() {
|
|
26
|
+
if (!this.control) {
|
|
27
|
+
console.error('FvImageSelector: control is required');
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
if (!this.schema) {
|
|
31
|
+
console.warn('FvImageSelector: schema is not provided, validation will be skipped');
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
// Subscribe to value changes
|
|
35
|
+
this.subscription = this.control.valueChanges.subscribe((value) => {
|
|
36
|
+
this.validateValue(value);
|
|
37
|
+
this.valueChange.emit(value);
|
|
38
|
+
});
|
|
39
|
+
// Validate initial value
|
|
40
|
+
if (this.control.value) {
|
|
41
|
+
this.selectedImage = this.control.value;
|
|
42
|
+
this.validateValue(this.control.value);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
ngOnDestroy() {
|
|
46
|
+
this.subscription?.unsubscribe();
|
|
47
|
+
}
|
|
48
|
+
validateValue(value) {
|
|
49
|
+
if (!this.schema)
|
|
50
|
+
return;
|
|
51
|
+
const result = Validator.validate(value, this.schema);
|
|
52
|
+
this.errorMessage = result.errorKey;
|
|
53
|
+
if (!result.isValid && result.errorKey) {
|
|
54
|
+
this.control.setErrors({ [result.errorKey]: true });
|
|
55
|
+
}
|
|
56
|
+
else {
|
|
57
|
+
this.control.setErrors(null);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
onImageSelected(event) {
|
|
61
|
+
const input = event.target;
|
|
62
|
+
if (input.files && input.files.length > 0) {
|
|
63
|
+
const file = input.files[0];
|
|
64
|
+
// Validate that it's an image
|
|
65
|
+
if (!file.type.startsWith('image/')) {
|
|
66
|
+
alert('Please select an image file');
|
|
67
|
+
input.value = '';
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
// Check file size if maxSize is specified
|
|
71
|
+
if (this.maxSize && file.size > this.maxSize) {
|
|
72
|
+
alert(`Image size exceeds the maximum allowed size of ${this.formatFileSize(this.maxSize)}`);
|
|
73
|
+
input.value = '';
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
// Create object URL and get image dimensions
|
|
77
|
+
const reader = new FileReader();
|
|
78
|
+
reader.onload = (e) => {
|
|
79
|
+
const img = new Image();
|
|
80
|
+
img.onload = () => {
|
|
81
|
+
const imageInfo = {
|
|
82
|
+
file: file,
|
|
83
|
+
url: this.sanitizer.bypassSecurityTrustUrl(e.target.result),
|
|
84
|
+
width: img.width,
|
|
85
|
+
height: img.height,
|
|
86
|
+
size: file.size,
|
|
87
|
+
};
|
|
88
|
+
this.selectedImage = imageInfo;
|
|
89
|
+
this.control.setValue(imageInfo);
|
|
90
|
+
this.blur.emit();
|
|
91
|
+
};
|
|
92
|
+
img.src = e.target.result;
|
|
93
|
+
};
|
|
94
|
+
reader.readAsDataURL(file);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
openImageDialog() {
|
|
98
|
+
if (!this.disabled) {
|
|
99
|
+
this.imageInput.nativeElement.click();
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
removeImage() {
|
|
103
|
+
this.selectedImage = null;
|
|
104
|
+
this.control.setValue(null);
|
|
105
|
+
if (this.imageInput) {
|
|
106
|
+
this.imageInput.nativeElement.value = '';
|
|
107
|
+
}
|
|
108
|
+
this.blur.emit();
|
|
109
|
+
}
|
|
110
|
+
formatFileSize(bytes) {
|
|
111
|
+
if (bytes === 0)
|
|
112
|
+
return '0 Bytes';
|
|
113
|
+
const k = 1024;
|
|
114
|
+
const sizes = ['Bytes', 'KB', 'MB', 'GB'];
|
|
115
|
+
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
|
116
|
+
return Math.round((bytes / Math.pow(k, i)) * 100) / 100 + ' ' + sizes[i];
|
|
117
|
+
}
|
|
118
|
+
isRequired() {
|
|
119
|
+
return (this.schema?.rules?.some((r) => r.name === 'required' && r.params?.['enabled']) || false);
|
|
120
|
+
}
|
|
121
|
+
getErrorMessage() {
|
|
122
|
+
if (!this.errorMessage)
|
|
123
|
+
return '';
|
|
124
|
+
const errorMessages = {
|
|
125
|
+
ERR_REQUIRED: 'This field is required',
|
|
126
|
+
ERR_INVALID_IMAGE: 'Invalid image',
|
|
127
|
+
};
|
|
128
|
+
return errorMessages[this.errorMessage] || this.errorMessage;
|
|
129
|
+
}
|
|
130
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: FvImageSelectorComponent, deps: [{ token: i1.DomSanitizer }], target: i0.ɵɵFactoryTarget.Component });
|
|
131
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.14", type: FvImageSelectorComponent, isStandalone: true, selector: "fv-image-selector", inputs: { label: "label", placeholder: "placeholder", schema: "schema", control: "control", disabled: "disabled", maxSize: "maxSize" }, outputs: { valueChange: "valueChange", blur: "blur" }, viewQueries: [{ propertyName: "imageInput", first: true, predicate: ["imageInput"], descendants: true }], ngImport: i0, template: "<div class=\"fv-image-selector-container\">\r\n <label *ngIf=\"label\" class=\"fv-image-selector-label\">\r\n {{ label }}\r\n <span *ngIf=\"isRequired()\" class=\"required-asterisk\">*</span>\r\n </label>\r\n\r\n <input #imageInput type=\"file\" accept=\"image/*\" (change)=\"onImageSelected($event)\" style=\"display: none\" />\r\n\r\n <div *ngIf=\"!selectedImage; else previewTemplate\">\r\n <button type=\"button\" class=\"fv-image-selector-button\" [class.fv-image-selector-button-error]=\"errorMessage\"\r\n [class.fv-image-selector-button-disabled]=\"disabled\" (click)=\"openImageDialog()\" [disabled]=\"disabled\">\r\n \uD83D\uDCF7 {{ placeholder }}\r\n </button>\r\n </div>\r\n\r\n <ng-template #previewTemplate>\r\n <div class=\"fv-image-preview-container\">\r\n <img [src]=\"selectedImage!.url\" class=\"fv-image-preview\" alt=\"Selected image\" />\r\n <div class=\"fv-image-actions\">\r\n <button type=\"button\" class=\"fv-image-change-button\" (click)=\"openImageDialog()\" [disabled]=\"disabled\">\r\n Change\r\n </button>\r\n <button type=\"button\" class=\"fv-image-remove-button\" (click)=\"removeImage()\" [disabled]=\"disabled\">\r\n Remove\r\n </button>\r\n </div>\r\n <div class=\"fv-image-info\">\r\n {{ selectedImage!.width }} \u00D7 {{ selectedImage!.height }} \u2022\r\n {{ formatFileSize(selectedImage!.size) }}\r\n </div>\r\n </div>\r\n </ng-template>\r\n\r\n <div *ngIf=\"errorMessage\" class=\"fv-image-selector-error-message\">\r\n \u26A0 {{ getErrorMessage() }}\r\n </div>\r\n</div>", styles: [".fv-image-selector-container{display:flex;flex-direction:column;margin-bottom:16px;width:100%}.fv-image-selector-label{font-size:14px;font-weight:500;color:#333;margin-bottom:6px;display:block}.required-asterisk{color:#dc3545;font-weight:700}.fv-image-selector-button{padding:40px;border:2px dashed #007bff;border-radius:8px;background-color:#f8f9fa;color:#007bff;font-size:14px;font-weight:500;cursor:pointer;transition:background-color .2s,border-color .2s;width:100%;text-align:center}.fv-image-selector-button:hover:not(:disabled){background-color:#e7f3ff}.fv-image-selector-button-error{border-color:#dc3545;color:#dc3545}.fv-image-selector-button-disabled{border-color:#ccc;background-color:#f5f5f5;color:#ccc;opacity:.6;cursor:not-allowed}.fv-image-preview-container{display:flex;flex-direction:column;align-items:center}.fv-image-preview{width:100%;max-width:600px;height:200px;object-fit:cover;border-radius:8px;background-color:#f0f0f0;margin-bottom:8px}.fv-image-actions{display:flex;gap:8px;margin-bottom:4px}.fv-image-change-button{padding:8px 16px;background-color:#007bff;color:#fff;border:none;border-radius:4px;font-size:14px;font-weight:500;cursor:pointer;transition:background-color .2s}.fv-image-change-button:hover:not(:disabled){background-color:#0056b3}.fv-image-change-button:disabled{opacity:.6;cursor:not-allowed}.fv-image-remove-button{padding:8px 16px;background-color:#dc3545;color:#fff;border:none;border-radius:4px;font-size:14px;font-weight:500;cursor:pointer;transition:background-color .2s}.fv-image-remove-button:hover:not(:disabled){background-color:#c82333}.fv-image-remove-button:disabled{opacity:.6;cursor:not-allowed}.fv-image-info{font-size:12px;color:#6c757d;text-align:center}.fv-image-selector-error-message{margin-top:4px;font-size:12px;color:#dc3545}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: ReactiveFormsModule }] });
|
|
132
|
+
}
|
|
133
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: FvImageSelectorComponent, decorators: [{
|
|
134
|
+
type: Component,
|
|
135
|
+
args: [{ standalone: true, imports: [CommonModule, ReactiveFormsModule], selector: 'fv-image-selector', template: "<div class=\"fv-image-selector-container\">\r\n <label *ngIf=\"label\" class=\"fv-image-selector-label\">\r\n {{ label }}\r\n <span *ngIf=\"isRequired()\" class=\"required-asterisk\">*</span>\r\n </label>\r\n\r\n <input #imageInput type=\"file\" accept=\"image/*\" (change)=\"onImageSelected($event)\" style=\"display: none\" />\r\n\r\n <div *ngIf=\"!selectedImage; else previewTemplate\">\r\n <button type=\"button\" class=\"fv-image-selector-button\" [class.fv-image-selector-button-error]=\"errorMessage\"\r\n [class.fv-image-selector-button-disabled]=\"disabled\" (click)=\"openImageDialog()\" [disabled]=\"disabled\">\r\n \uD83D\uDCF7 {{ placeholder }}\r\n </button>\r\n </div>\r\n\r\n <ng-template #previewTemplate>\r\n <div class=\"fv-image-preview-container\">\r\n <img [src]=\"selectedImage!.url\" class=\"fv-image-preview\" alt=\"Selected image\" />\r\n <div class=\"fv-image-actions\">\r\n <button type=\"button\" class=\"fv-image-change-button\" (click)=\"openImageDialog()\" [disabled]=\"disabled\">\r\n Change\r\n </button>\r\n <button type=\"button\" class=\"fv-image-remove-button\" (click)=\"removeImage()\" [disabled]=\"disabled\">\r\n Remove\r\n </button>\r\n </div>\r\n <div class=\"fv-image-info\">\r\n {{ selectedImage!.width }} \u00D7 {{ selectedImage!.height }} \u2022\r\n {{ formatFileSize(selectedImage!.size) }}\r\n </div>\r\n </div>\r\n </ng-template>\r\n\r\n <div *ngIf=\"errorMessage\" class=\"fv-image-selector-error-message\">\r\n \u26A0 {{ getErrorMessage() }}\r\n </div>\r\n</div>", styles: [".fv-image-selector-container{display:flex;flex-direction:column;margin-bottom:16px;width:100%}.fv-image-selector-label{font-size:14px;font-weight:500;color:#333;margin-bottom:6px;display:block}.required-asterisk{color:#dc3545;font-weight:700}.fv-image-selector-button{padding:40px;border:2px dashed #007bff;border-radius:8px;background-color:#f8f9fa;color:#007bff;font-size:14px;font-weight:500;cursor:pointer;transition:background-color .2s,border-color .2s;width:100%;text-align:center}.fv-image-selector-button:hover:not(:disabled){background-color:#e7f3ff}.fv-image-selector-button-error{border-color:#dc3545;color:#dc3545}.fv-image-selector-button-disabled{border-color:#ccc;background-color:#f5f5f5;color:#ccc;opacity:.6;cursor:not-allowed}.fv-image-preview-container{display:flex;flex-direction:column;align-items:center}.fv-image-preview{width:100%;max-width:600px;height:200px;object-fit:cover;border-radius:8px;background-color:#f0f0f0;margin-bottom:8px}.fv-image-actions{display:flex;gap:8px;margin-bottom:4px}.fv-image-change-button{padding:8px 16px;background-color:#007bff;color:#fff;border:none;border-radius:4px;font-size:14px;font-weight:500;cursor:pointer;transition:background-color .2s}.fv-image-change-button:hover:not(:disabled){background-color:#0056b3}.fv-image-change-button:disabled{opacity:.6;cursor:not-allowed}.fv-image-remove-button{padding:8px 16px;background-color:#dc3545;color:#fff;border:none;border-radius:4px;font-size:14px;font-weight:500;cursor:pointer;transition:background-color .2s}.fv-image-remove-button:hover:not(:disabled){background-color:#c82333}.fv-image-remove-button:disabled{opacity:.6;cursor:not-allowed}.fv-image-info{font-size:12px;color:#6c757d;text-align:center}.fv-image-selector-error-message{margin-top:4px;font-size:12px;color:#dc3545}\n"] }]
|
|
136
|
+
}], ctorParameters: () => [{ type: i1.DomSanitizer }], propDecorators: { label: [{
|
|
137
|
+
type: Input
|
|
138
|
+
}], placeholder: [{
|
|
139
|
+
type: Input
|
|
140
|
+
}], schema: [{
|
|
141
|
+
type: Input
|
|
142
|
+
}], control: [{
|
|
143
|
+
type: Input
|
|
144
|
+
}], disabled: [{
|
|
145
|
+
type: Input
|
|
146
|
+
}], maxSize: [{
|
|
147
|
+
type: Input
|
|
148
|
+
}], valueChange: [{
|
|
149
|
+
type: Output
|
|
150
|
+
}], blur: [{
|
|
151
|
+
type: Output
|
|
152
|
+
}], imageInput: [{
|
|
153
|
+
type: ViewChild,
|
|
154
|
+
args: ['imageInput']
|
|
155
|
+
}] } });
|
|
156
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZnYtaW1hZ2Utc2VsZWN0b3IuY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vcHJvamVjdHMvZnYtY29udHJvbHMvc3JjL2xpYi9mdi1pbWFnZS1zZWxlY3Rvci9mdi1pbWFnZS1zZWxlY3Rvci5jb21wb25lbnQudHMiLCIuLi8uLi8uLi8uLi8uLi9wcm9qZWN0cy9mdi1jb250cm9scy9zcmMvbGliL2Z2LWltYWdlLXNlbGVjdG9yL2Z2LWltYWdlLXNlbGVjdG9yLmNvbXBvbmVudC5odG1sIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFDSCxTQUFTLEVBQ1QsS0FBSyxFQUNMLE1BQU0sRUFDTixZQUFZLEVBR1osU0FBUyxHQUVaLE1BQU0sZUFBZSxDQUFDO0FBQ3ZCLE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQztBQUMvQyxPQUFPLEVBQWUsbUJBQW1CLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUVsRSxPQUFPLEVBQUUsU0FBUyxFQUFvQixNQUFNLDhCQUE4QixDQUFDOzs7O0FBa0IzRSxNQUFNLE9BQU8sd0JBQXdCO0lBaUJiO0lBaEJYLEtBQUssR0FBVyxFQUFFLENBQUM7SUFDbkIsV0FBVyxHQUFXLGlCQUFpQixDQUFDO0lBQ3hDLE1BQU0sQ0FBb0I7SUFDMUIsT0FBTyxDQUFlO0lBQ3RCLFFBQVEsR0FBWSxLQUFLLENBQUM7SUFDMUIsT0FBTyxDQUFVLENBQUMsNkJBQTZCO0lBRTlDLFdBQVcsR0FBRyxJQUFJLFlBQVksRUFBb0IsQ0FBQztJQUNuRCxJQUFJLEdBQUcsSUFBSSxZQUFZLEVBQVEsQ0FBQztJQUVqQixVQUFVLENBQWdDO0lBRW5FLFlBQVksR0FBa0IsSUFBSSxDQUFDO0lBQ25DLGFBQWEsR0FBcUIsSUFBSSxDQUFDO0lBQy9CLFlBQVksQ0FBZ0I7SUFFcEMsWUFBb0IsU0FBdUI7UUFBdkIsY0FBUyxHQUFULFNBQVMsQ0FBYztJQUFJLENBQUM7SUFF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WSxDQUFDO0lBQ2pFLENBQUM7d0dBcEpRLHdCQUF3Qjs0RkFBeEIsd0JBQXdCLHNYQy9CckMscXdEQW9DTSwrekREVlEsWUFBWSxrSUFBRSxtQkFBbUI7OzRGQUtsQyx3QkFBd0I7a0JBUHBDLFNBQVM7aUNBQ00sSUFBSSxXQUNQLENBQUMsWUFBWSxFQUFFLG1CQUFtQixDQUFDLFlBQ2xDLG1CQUFtQjtpRkFLcEIsS0FBSztzQkFBYixLQUFLO2dCQUNHLFdBQVc7c0JBQW5CLEtBQUs7Z0JBQ0csTUFBTTtzQkFBZCxLQUFLO2dCQUNHLE9BQU87c0JBQWYsS0FBSztnQkFDRyxRQUFRO3NCQUFoQixLQUFLO2dCQUNHLE9BQU87c0JBQWYsS0FBSztnQkFFSSxXQUFXO3NCQUFwQixNQUFNO2dCQUNHLElBQUk7c0JBQWIsTUFBTTtnQkFFa0IsVUFBVTtzQkFBbEMsU0FBUzt1QkFBQyxZQUFZIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHtcclxuICAgIENvbXBvbmVudCxcclxuICAgIElucHV0LFxyXG4gICAgT3V0cHV0LFxyXG4gICAgRXZlbnRFbWl0dGVyLFxyXG4gICAgT25Jbml0LFxyXG4gICAgT25EZXN0cm95LFxyXG4gICAgVmlld0NoaWxkLFxyXG4gICAgRWxlbWVudFJlZixcclxufSBmcm9tICdAYW5ndWxhci9jb3JlJztcclxuaW1wb3J0IHsgQ29tbW9uTW9kdWxlIH0gZnJvbSAnQGFuZ3VsYXIvY29tbW9uJztcclxuaW1wb3J0IHsgRm9ybUNvbnRyb2wsIFJlYWN0aXZlRm9ybXNNb2R1bGUgfSBmcm9tICdAYW5ndWxhci9mb3Jtcyc7XHJcbmltcG9ydCB7IFN1YnNjcmlwdGlvbiB9IGZyb20gJ3J4anMnO1xyXG5pbXBvcnQgeyBWYWxpZGF0b3IsIFZhbGlkYXRpb25TY2hlbWEgfSBmcm9tICdAZm92ZXN0dGEyL3ZhbGlkYXRpb24tZW5naW5lJztcclxuaW1wb3J0IHsgRG9tU2FuaXRpemVyLCBTYWZlVXJsIH0gZnJvbSAnQGFuZ3VsYXIvcGxhdGZvcm0tYnJvd3Nlcic7XHJcblxyXG5leHBvcnQgaW50ZXJmYWNlIEltYWdlSW5mbyB7XHJcbiAgICBmaWxlOiBGaWxlO1xyXG4gICAgdXJsOiBTYWZlVXJsO1xyXG4gICAgd2lkdGg6IG51bWJlcjtcclxuICAgIGhlaWdodDogbnVtYmVyO1xyXG4gICAgc2l6ZTogbnVtYmVyO1xyXG59XHJcblxyXG5AQ29tcG9uZW50KHtcclxuICAgIHN0YW5kYWxvbmU6IHRydWUsXHJcbiAgICBpbXBvcnRzOiBbQ29tbW9uTW9kdWxlLCBSZWFjdGl2ZUZvcm1zTW9kdWxlXSxcclxuICAgIHNlbGVjdG9yOiAnZnYtaW1hZ2Utc2VsZWN0b3InLFxyXG4gICAgdGVtcGxhdGVVcmw6ICcuL2Z2LWltYWdlLXNlbGVjdG9yLmNvbXBvbmVudC5odG1sJyxcclxuICAgIHN0eWxlVXJsOiAnLi9mdi1pbWFnZS1zZWxlY3Rvci5jb21wb25lbnQuY3NzJyxcclxufSlcclxuZXhwb3J0IGNsYXNzIEZ2SW1hZ2VTZWxlY3RvckNvbXBvbmVudCBpbXBsZW1lbnRzIE9uSW5pdCwgT25EZXN0cm95IHtcclxuICAgIEBJbnB1dCgpIGxhYmVsOiBzdHJpbmcgPSAnJztcclxuICAgIEBJbnB1dCgpIHBsYWNlaG9sZGVyOiBzdHJpbmcgPSAnU2VsZWN0IGFuIGltYWdlJztcclxuICAgIEBJbnB1dCgpIHNjaGVtYSE6IFZhbGlkYXRpb25TY2hlbWE7XHJcbiAgICBASW5wdXQoKSBjb250cm9sITogRm9ybUNvbnRyb2w7XHJcbiAgICBASW5wdXQoKSBkaXNhYmxlZDogYm9vbGVhbiA9IGZhbHNlO1xyXG4gICAgQElucHV0KCkgbWF4U2l6ZT86IG51bWJlcjsgLy8gTWF4aW11bSBmaWxlIHNpemUgaW4gYnl0ZXNcclxuXHJcbiAgICBAT3V0cHV0KCkgdmFsdWVDaGFuZ2UgPSBuZXcgRXZlbnRFbWl0dGVyPEltYWdlSW5mbyB8IG51bGw+KCk7XHJcbiAgICBAT3V0cHV0KCkgYmx1ciA9IG5ldyBFdmVudEVtaXR0ZXI8dm9pZD4oKTtcclxuXHJcbiAgICBAVmlld0NoaWxkKCdpbWFnZUlucHV0JykgaW1hZ2VJbnB1dCE6IEVsZW1lbnRSZWY8SFRNTElucHV0RWxlbWVudD47XHJcblxyXG4gICAgZXJyb3JNZXNzYWdlOiBzdHJpbmcgfCBudWxsID0gbnVsbDtcclxuICAgIHNlbGVjdGVkSW1hZ2U6IEltYWdlSW5mbyB8IG51bGwgPSBudWxsO1xyXG4gICAgcHJpdmF0ZSBzdWJzY3JpcHRpb24/OiBTdWJzY3JpcHRpb247XHJcblxyXG4gICAgY29uc3RydWN0b3IocHJpdmF0ZSBzYW5pdGl6ZXI6IERvbVNhbml0aXplcikgeyB9XHJcblxyXG4gICAgbmdPbkluaXQoKTogdm9pZCB7XHJcbiAgICAgICAgaWYgKCF0aGlzLmNvbnRyb2wpIHtcclxuICAgICAgICAgICAgY29uc29sZS5lcnJvcignRnZJbWFnZVNlbGVjdG9yOiBjb250cm9sIGlzIHJlcXVpcmVkJyk7XHJcbiAgICAgICAgICAgIHJldHVybjtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIGlmICghdGhpcy5zY2hlbWEpIHtcclxuICAgICAgICAgICAgY29uc29sZS53YXJuKFxyXG4gICAgICAgICAgICAgICAgJ0Z2SW1hZ2VTZWxlY3Rvcjogc2NoZW1hIGlzIG5vdCBwcm92aWRlZCwgdmFsaWRhdGlvbiB3aWxsIGJlIHNraXBwZWQnXHJcbiAgICAgICAgICAgICk7XHJcbiAgICAgICAgICAgIHJldHVybjtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIC8vIFN1YnNjcmliZSB0byB2YWx1ZSBjaGFuZ2VzXHJcbiAgICAgICAgdGhpcy5zdWJzY3JpcHRpb24gPSB0aGlzLmNvbnRyb2wudmFsdWVDaGFuZ2VzLnN1YnNjcmliZSgodmFsdWUpID0+IHtcclxuICAgICAgICAgICAgdGhpcy52YWxpZGF0ZVZhbHVlKHZhbHVlKTtcclxuICAgICAgICAgICAgdGhpcy52YWx1ZUNoYW5nZS5lbWl0KHZhbHVlKTtcclxuICAgICAgICB9KTtcclxuXHJcbiAgICAgICAgLy8gVmFsaWRhdGUgaW5pdGlhbCB2YWx1ZVxyXG4gICAgICAgIGlmICh0aGlzLmNvbnRyb2wudmFsdWUpIHtcclxuICAgICAgICAgICAgdGhpcy5zZWxlY3RlZEltYWdlID0gdGhpcy5jb250cm9sLnZhbHVlO1xyXG4gICAgICAgICAgICB0aGlzLnZhbGlkYXRlVmFsdWUodGhpcy5jb250cm9sLnZhbHVlKTtcclxuICAgICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgbmdPbkRlc3Ryb3koKTogdm9pZCB7XHJcbiAgICAgICAgdGhpcy5zdWJzY3JpcHRpb24/LnVuc3Vic2NyaWJlKCk7XHJcbiAgICB9XHJcblxyXG4gICAgcHJpdmF0ZSB2YWxpZGF0ZVZhbHVlKHZhbHVlOiBhbnkpOiB2b2lkIHtcclxuICAgICAgICBpZiAoIXRoaXMuc2NoZW1hKSByZXR1cm47XHJcblxyXG4gICAgICAgIGNvbnN0IHJlc3VsdCA9IFZhbGlkYXRvci52YWxpZGF0ZSh2YWx1ZSwgdGhpcy5zY2hlbWEpO1xyXG4gICAgICAgIHRoaXMuZXJyb3JNZXNzYWdlID0gcmVzdWx0LmVycm9yS2V5O1xyXG5cclxuICAgICAgICBpZiAoIXJlc3VsdC5pc1ZhbGlkICYmIHJlc3VsdC5lcnJvcktleSkge1xyXG4gICAgICAgICAgICB0aGlzLmNvbnRyb2wuc2V0RXJyb3JzKHsgW3Jlc3VsdC5lcnJvcktleV06IHRydWUgfSk7XHJcbiAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgICAgdGhpcy5jb250cm9sLnNldEVycm9ycyhudWxsKTtcclxuICAgICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgb25JbWFnZVNlbGVjdGVkKGV2ZW50OiBFdmVudCk6IHZvaWQge1xyXG4gICAgICAgIGNvbnN0IGlucHV0ID0gZXZlbnQudGFyZ2V0IGFzIEhUTUxJbnB1dEVsZW1lbnQ7XHJcbiAgICAgICAgaWYgKGlucHV0LmZpbGVzICYmIGlucHV0LmZpbGVzLmxlbmd0aCA+IDApIHtcclxuICAgICAgICAgICAgY29uc3QgZmlsZSA9IGlucHV0LmZpbGVzWzBdO1xyXG5cclxuICAgICAgICAgICAgLy8gVmFsaWRhdGUgdGhhdCBpdCdzIGFuIGltYWdlXHJcbiAgICAgICAgICAgIGlmICghZmlsZS50eXBlLnN0YXJ0c1dpdGgoJ2ltYWdlLycpKSB7XHJcbiAgICAgICAgICAgICAgICBhbGVydCgnUGxlYXNlIHNlbGVjdCBhbiBpbWFnZSBmaWxlJyk7XHJcbiAgICAgICAgICAgICAgICBpbnB1dC52YWx1ZSA9ICcnO1xyXG4gICAgICAgICAgICAgICAgcmV0dXJuO1xyXG4gICAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgICAvLyBDaGVjayBmaWxlIHNpemUgaWYgbWF4U2l6ZSBpcyBzcGVjaWZpZWRcclxuICAgICAgICAgICAgaWYgKHRoaXMubWF4U2l6ZSAmJiBmaWxlLnNpemUgPiB0aGlzLm1heFNpemUpIHtcclxuICAgICAgICAgICAgICAgIGFsZXJ0KFxyXG4gICAgICAgICAgICAgICAgICAgIGBJbWFnZSBzaXplIGV4Y2VlZHMgdGhlIG1heGltdW0gYWxsb3dlZCBzaXplIG9mICR7dGhpcy5mb3JtYXRGaWxlU2l6ZShcclxuICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5tYXhTaXplXHJcbiAgICAgICAgICAgICAgICAgICAgKX1gXHJcbiAgICAgICAgICAgICAgICApO1xyXG4gICAgICAgICAgICAgICAgaW5wdXQudmFsdWUgPSAnJztcclxuICAgICAgICAgICAgICAgIHJldHVybjtcclxuICAgICAgICAgICAgfVxyXG5cclxuICAgICAgICAgICAgLy8gQ3JlYXRlIG9iamVjdCBVUkwgYW5kIGdldCBpbWFnZSBkaW1lbnNpb25zXHJcbiAgICAgICAgICAgIGNvbnN0IHJlYWRlciA9IG5ldyBGaWxlUmVhZGVyKCk7XHJcbiAgICAgICAgICAgIHJlYWRlci5vbmxvYWQgPSAoZTogYW55KSA9PiB7XHJcbiAgICAgICAgICAgICAgICBjb25zdCBpbWcgPSBuZXcgSW1hZ2UoKTtcclxuICAgICAgICAgICAgICAgIGltZy5vbmxvYWQgPSAoKSA9PiB7XHJcbiAgICAgICAgICAgICAgICAgICAgY29uc3QgaW1hZ2VJbmZvOiBJbWFnZUluZm8gPSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIGZpbGU6IGZpbGUsXHJcbiAgICAgICAgICAgICAgICAgICAgICAgIHVybDogdGhpcy5zYW5pdGl6ZXIuYnlwYXNzU2VjdXJpdHlUcnVzdFVybChlLnRhcmdldC5yZXN1bHQpLFxyXG4gICAgICAgICAgICAgICAgICAgICAgICB3aWR0aDogaW1nLndpZHRoLFxyXG4gICAgICAgICAgICAgICAgICAgICAgICBoZWlnaHQ6IGltZy5oZWlnaHQsXHJcbiAgICAgICAgICAgICAgICAgICAgICAgIHNpemU6IGZpbGUuc2l6ZSxcclxuICAgICAgICAgICAgICAgICAgICB9O1xyXG5cclxuICAgICAgICAgICAgICAgICAgICB0aGlzLnNlbGVjdGVkSW1hZ2UgPSBpbWFnZUluZm87XHJcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5jb250cm9sLnNldFZhbHVlKGltYWdlSW5mbyk7XHJcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5ibHVyLmVtaXQoKTtcclxuICAgICAgICAgICAgICAgIH07XHJcbiAgICAgICAgICAgICAgICBpbWcuc3JjID0gZS50YXJnZXQucmVzdWx0O1xyXG4gICAgICAgICAgICB9O1xyXG4gICAgICAgICAgICByZWFkZXIucmVhZEFzRGF0YVVSTChmaWxlKTtcclxuICAgICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgb3BlbkltYWdlRGlhbG9nKCk6IHZvaWQge1xyXG4gICAgICAgIGlmICghdGhpcy5kaXNhYmxlZCkge1xyXG4gICAgICAgICAgICB0aGlzLmltYWdlSW5wdXQubmF0aXZlRWxlbWVudC5jbGljaygpO1xyXG4gICAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICByZW1vdmVJbWFnZSgpOiB2b2lkIHtcclxuICAgICAgICB0aGlzLnNlbGVjdGVkSW1hZ2UgPSBudWxsO1xyXG4gICAgICAgIHRoaXMuY29udHJvbC5zZXRWYWx1ZShudWxsKTtcclxuICAgICAgICBpZiAodGhpcy5pbWFnZUlucHV0KSB7XHJcbiAgICAgICAgICAgIHRoaXMuaW1hZ2VJbnB1dC5uYXRpdmVFbGVtZW50LnZhbHVlID0gJyc7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIHRoaXMuYmx1ci5lbWl0KCk7XHJcbiAgICB9XHJcblxyXG4gICAgZm9ybWF0RmlsZVNpemUoYnl0ZXM6IG51bWJlcik6IHN0cmluZyB7XHJcbiAgICAgICAgaWYgKGJ5dGVzID09PSAwKSByZXR1cm4gJzAgQnl0ZXMnO1xyXG4gICAgICAgIGNvbnN0IGsgPSAxMDI0O1xyXG4gICAgICAgIGNvbnN0IHNpemVzID0gWydCeXRlcycsICdLQicsICdNQicsICdHQiddO1xyXG4gICAgICAgIGNvbnN0IGkgPSBNYXRoLmZsb29yKE1hdGgubG9nKGJ5dGVzKSAvIE1hdGgubG9nKGspKTtcclxuICAgICAgICByZXR1cm4gTWF0aC5yb3VuZCgoYnl0ZXMgLyBNYXRoLnBvdyhrLCBpKSkgKiAxMDApIC8gMTAwICsgJyAnICsgc2l6ZXNbaV07XHJcbiAgICB9XHJcblxyXG4gICAgaXNSZXF1aXJlZCgpOiBib29sZWFuIHtcclxuICAgICAgICByZXR1cm4gKFxyXG4gICAgICAgICAgICB0aGlzLnNjaGVtYT8ucnVsZXM/LnNvbWUoXHJcbiAgICAgICAgICAgICAgICAocikgPT4gci5uYW1lID09PSAncmVxdWlyZWQnICYmIHIucGFyYW1zPy5bJ2VuYWJsZWQnXVxyXG4gICAgICAgICAgICApIHx8IGZhbHNlXHJcbiAgICAgICAgKTtcclxuICAgIH1cclxuXHJcbiAgICBnZXRFcnJvck1lc3NhZ2UoKTogc3RyaW5nIHtcclxuICAgICAgICBpZiAoIXRoaXMuZXJyb3JNZXNzYWdlKSByZXR1cm4gJyc7XHJcblxyXG4gICAgICAgIGNvbnN0IGVycm9yTWVzc2FnZXM6IFJlY29yZDxzdHJpbmcsIHN0cmluZz4gPSB7XHJcbiAgICAgICAgICAgIEVSUl9SRVFVSVJFRDogJ1RoaXMgZmllbGQgaXMgcmVxdWlyZWQnLFxyXG4gICAgICAgICAgICBFUlJfSU5WQUxJRF9JTUFHRTogJ0ludmFsaWQgaW1hZ2UnLFxyXG4gICAgICAgIH07XHJcblxyXG4gICAgICAgIHJldHVybiBlcnJvck1lc3NhZ2VzW3RoaXMuZXJyb3JNZXNzYWdlXSB8fCB0aGlzLmVycm9yTWVzc2FnZTtcclxuICAgIH1cclxufVxyXG4iLCI8ZGl2IGNsYXNzPVwiZnYtaW1hZ2Utc2VsZWN0b3ItY29udGFpbmVyXCI+XHJcbiAgICA8bGFiZWwgKm5nSWY9XCJsYWJlbFwiIGNsYXNzPVwiZnYtaW1hZ2Utc2VsZWN0b3ItbGFiZWxcIj5cclxuICAgICAgICB7eyBsYWJlbCB9fVxyXG4gICAgICAgIDxzcGFuICpuZ0lmPVwiaXNSZXF1aXJlZCgpXCIgY2xhc3M9XCJyZXF1aXJlZC1hc3Rlcmlza1wiPio8L3NwYW4+XHJcbiAgICA8L2xhYmVsPlxyXG5cclxuICAgIDxpbnB1dCAjaW1hZ2VJbnB1dCB0eXBlPVwiZmlsZVwiIGFjY2VwdD1cImltYWdlLypcIiAoY2hhbmdlKT1cIm9uSW1hZ2VTZWxlY3RlZCgkZXZlbnQpXCIgc3R5bGU9XCJkaXNwbGF5OiBub25lXCIgLz5cclxuXHJcbiAgICA8ZGl2ICpuZ0lmPVwiIXNlbGVjdGVkSW1hZ2U7IGVsc2UgcHJldmlld1RlbXBsYXRlXCI+XHJcbiAgICAgICAgPGJ1dHRvbiB0eXBlPVwiYnV0dG9uXCIgY2xhc3M9XCJmdi1pbWFnZS1zZWxlY3Rvci1idXR0b25cIiBbY2xhc3MuZnYtaW1hZ2Utc2VsZWN0b3ItYnV0dG9uLWVycm9yXT1cImVycm9yTWVzc2FnZVwiXHJcbiAgICAgICAgICAgIFtjbGFzcy5mdi1pbWFnZS1zZWxlY3Rvci1idXR0b24tZGlzYWJsZWRdPVwiZGlzYWJsZWRcIiAoY2xpY2spPVwib3BlbkltYWdlRGlhbG9nKClcIiBbZGlzYWJsZWRdPVwiZGlzYWJsZWRcIj5cclxuICAgICAgICAgICAg8J+TtyB7eyBwbGFjZWhvbGRlciB9fVxyXG4gICAgICAgIDwvYnV0dG9uPlxyXG4gICAgPC9kaXY+XHJcblxyXG4gICAgPG5nLXRlbXBsYXRlICNwcmV2aWV3VGVtcGxhdGU+XHJcbiAgICAgICAgPGRpdiBjbGFzcz1cImZ2LWltYWdlLXByZXZpZXctY29udGFpbmVyXCI+XHJcbiAgICAgICAgICAgIDxpbWcgW3NyY109XCJzZWxlY3RlZEltYWdlIS51cmxcIiBjbGFzcz1cImZ2LWltYWdlLXByZXZpZXdcIiBhbHQ9XCJTZWxlY3RlZCBpbWFnZVwiIC8+XHJcbiAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJmdi1pbWFnZS1hY3Rpb25zXCI+XHJcbiAgICAgICAgICAgICAgICA8YnV0dG9uIHR5cGU9XCJidXR0b25cIiBjbGFzcz1cImZ2LWltYWdlLWNoYW5nZS1idXR0b25cIiAoY2xpY2spPVwib3BlbkltYWdlRGlhbG9nKClcIiBbZGlzYWJsZWRdPVwiZGlzYWJsZWRcIj5cclxuICAgICAgICAgICAgICAgICAgICBDaGFuZ2VcclxuICAgICAgICAgICAgICAgIDwvYnV0dG9uPlxyXG4gICAgICAgICAgICAgICAgPGJ1dHRvbiB0eXBlPVwiYnV0dG9uXCIgY2xhc3M9XCJmdi1pbWFnZS1yZW1vdmUtYnV0dG9uXCIgKGNsaWNrKT1cInJlbW92ZUltYWdlKClcIiBbZGlzYWJsZWRdPVwiZGlzYWJsZWRcIj5cclxuICAgICAgICAgICAgICAgICAgICBSZW1vdmVcclxuICAgICAgICAgICAgICAgIDwvYnV0dG9uPlxyXG4gICAgICAgICAgICA8L2Rpdj5cclxuICAgICAgICAgICAgPGRpdiBjbGFzcz1cImZ2LWltYWdlLWluZm9cIj5cclxuICAgICAgICAgICAgICAgIHt7IHNlbGVjdGVkSW1hZ2UhLndpZHRoIH19IMOXIHt7IHNlbGVjdGVkSW1hZ2UhLmhlaWdodCB9fSDigKJcclxuICAgICAgICAgICAgICAgIHt7IGZvcm1hdEZpbGVTaXplKHNlbGVjdGVkSW1hZ2UhLnNpemUpIH19XHJcbiAgICAgICAgICAgIDwvZGl2PlxyXG4gICAgICAgIDwvZGl2PlxyXG4gICAgPC9uZy10ZW1wbGF0ZT5cclxuXHJcbiAgICA8ZGl2ICpuZ0lmPVwiZXJyb3JNZXNzYWdlXCIgY2xhc3M9XCJmdi1pbWFnZS1zZWxlY3Rvci1lcnJvci1tZXNzYWdlXCI+XHJcbiAgICAgICAg4pqgIHt7IGdldEVycm9yTWVzc2FnZSgpIH19XHJcbiAgICA8L2Rpdj5cclxuPC9kaXY+Il19
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import { Component, Input, Output, EventEmitter, } from '@angular/core';
|
|
2
|
+
import { CommonModule } from '@angular/common';
|
|
3
|
+
import { ReactiveFormsModule } from '@angular/forms';
|
|
4
|
+
import { Validator } from '@fovestta2/validation-engine';
|
|
5
|
+
import * as i0 from "@angular/core";
|
|
6
|
+
import * as i1 from "@angular/common";
|
|
7
|
+
import * as i2 from "@angular/forms";
|
|
8
|
+
export class FvMonthYearFieldComponent {
|
|
9
|
+
label = '';
|
|
10
|
+
schema;
|
|
11
|
+
control;
|
|
12
|
+
disabled = false;
|
|
13
|
+
readonly = false;
|
|
14
|
+
min; // YYYY-MM
|
|
15
|
+
max; // YYYY-MM
|
|
16
|
+
valueChange = new EventEmitter();
|
|
17
|
+
blur = new EventEmitter();
|
|
18
|
+
focus = new EventEmitter();
|
|
19
|
+
errorMessage = null;
|
|
20
|
+
subscription;
|
|
21
|
+
ngOnInit() {
|
|
22
|
+
if (!this.control) {
|
|
23
|
+
console.error('FvMonthYearField: control is required');
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
this.extractConstraintsFromSchema();
|
|
27
|
+
this.subscription = this.control.valueChanges.subscribe((value) => {
|
|
28
|
+
this.validateValue(value);
|
|
29
|
+
this.valueChange.emit(value);
|
|
30
|
+
});
|
|
31
|
+
if (this.control.value) {
|
|
32
|
+
this.validateValue(this.control.value);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
ngOnDestroy() {
|
|
36
|
+
this.subscription?.unsubscribe();
|
|
37
|
+
}
|
|
38
|
+
extractConstraintsFromSchema() {
|
|
39
|
+
if (!this.schema?.rules)
|
|
40
|
+
return;
|
|
41
|
+
for (const rule of this.schema.rules) {
|
|
42
|
+
if (rule.name === 'minDate' && !this.min) {
|
|
43
|
+
this.min = this.formatMonth(rule.params?.['value']);
|
|
44
|
+
}
|
|
45
|
+
if (rule.name === 'maxDate' && !this.max) {
|
|
46
|
+
this.max = this.formatMonth(rule.params?.['value']);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
formatMonth(date) {
|
|
51
|
+
if (!date)
|
|
52
|
+
return '';
|
|
53
|
+
const d = new Date(date);
|
|
54
|
+
if (isNaN(d.getTime()))
|
|
55
|
+
return '';
|
|
56
|
+
return d.toISOString().slice(0, 7); // YYYY-MM
|
|
57
|
+
}
|
|
58
|
+
validateValue(value) {
|
|
59
|
+
if (!this.schema)
|
|
60
|
+
return;
|
|
61
|
+
// For month picker, value is YYYY-MM.
|
|
62
|
+
// The generic Validator rules use new Date(value), which treats YYYY-MM as YYYY-MM-01.
|
|
63
|
+
// This generally works for min/max logic.
|
|
64
|
+
const result = Validator.validate(value, this.schema);
|
|
65
|
+
this.errorMessage = result.errorKey;
|
|
66
|
+
if (!result.isValid && result.errorKey) {
|
|
67
|
+
this.control.setErrors({ [result.errorKey]: true });
|
|
68
|
+
}
|
|
69
|
+
else {
|
|
70
|
+
this.control.setErrors(null);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
onBlur(event) {
|
|
74
|
+
this.validateValue(this.control.value);
|
|
75
|
+
this.blur.emit();
|
|
76
|
+
}
|
|
77
|
+
onFocus(event) {
|
|
78
|
+
this.focus.emit();
|
|
79
|
+
}
|
|
80
|
+
isRequired() {
|
|
81
|
+
return (this.schema?.rules?.some((r) => r.name === 'required' && r.params?.['enabled']) || false);
|
|
82
|
+
}
|
|
83
|
+
getErrorMessage() {
|
|
84
|
+
if (!this.errorMessage)
|
|
85
|
+
return '';
|
|
86
|
+
const errorMessages = {
|
|
87
|
+
ERR_REQUIRED: 'Month/Year is required',
|
|
88
|
+
ERR_MIN_DATE: `Date must be after ${this.min}`,
|
|
89
|
+
ERR_MAX_DATE: `Date must be before ${this.max}`,
|
|
90
|
+
};
|
|
91
|
+
return errorMessages[this.errorMessage] || this.errorMessage;
|
|
92
|
+
}
|
|
93
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: FvMonthYearFieldComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
94
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.14", type: FvMonthYearFieldComponent, isStandalone: true, selector: "fv-month-year-field", inputs: { label: "label", schema: "schema", control: "control", disabled: "disabled", readonly: "readonly", min: "min", max: "max" }, outputs: { valueChange: "valueChange", blur: "blur", focus: "focus" }, ngImport: i0, template: "<div class=\"fv-field-container\">\r\n <label *ngIf=\"label\" class=\"fv-label\">\r\n {{ label }} <span *ngIf=\"isRequired()\" class=\"required\">*</span>\r\n </label>\r\n\r\n <input type=\"month\" [formControl]=\"control\" class=\"fv-input\" [class.error]=\"!!errorMessage\" [attr.min]=\"min\"\r\n [attr.max]=\"max\" [readonly]=\"readonly\" (blur)=\"onBlur($event)\" (focus)=\"onFocus($event)\" />\r\n\r\n <div *ngIf=\"errorMessage\" class=\"fv-error-message\">\r\n {{ getErrorMessage() }}\r\n </div>\r\n</div>", styles: [".fv-field-container{display:flex;flex-direction:column;margin-bottom:1rem}.fv-label{font-size:.875rem;font-weight:500;margin-bottom:.5rem;color:#374151}.required{color:#ef4444}.fv-input{padding:.5rem .75rem;border:1px solid #d1d5db;border-radius:.375rem;font-size:1rem;line-height:1.5;transition:border-color .15s ease-in-out,box-shadow .15s ease-in-out}.fv-input:focus{outline:none;border-color:#3b82f6;box-shadow:0 0 0 3px #3b82f61a}.fv-input.error{border-color:#ef4444}.fv-input.error:focus{box-shadow:0 0 0 3px #ef44441a}.fv-error-message{margin-top:.25rem;font-size:.75rem;color:#ef4444}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { 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.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }] });
|
|
95
|
+
}
|
|
96
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: FvMonthYearFieldComponent, decorators: [{
|
|
97
|
+
type: Component,
|
|
98
|
+
args: [{ standalone: true, imports: [CommonModule, ReactiveFormsModule], selector: 'fv-month-year-field', template: "<div class=\"fv-field-container\">\r\n <label *ngIf=\"label\" class=\"fv-label\">\r\n {{ label }} <span *ngIf=\"isRequired()\" class=\"required\">*</span>\r\n </label>\r\n\r\n <input type=\"month\" [formControl]=\"control\" class=\"fv-input\" [class.error]=\"!!errorMessage\" [attr.min]=\"min\"\r\n [attr.max]=\"max\" [readonly]=\"readonly\" (blur)=\"onBlur($event)\" (focus)=\"onFocus($event)\" />\r\n\r\n <div *ngIf=\"errorMessage\" class=\"fv-error-message\">\r\n {{ getErrorMessage() }}\r\n </div>\r\n</div>", styles: [".fv-field-container{display:flex;flex-direction:column;margin-bottom:1rem}.fv-label{font-size:.875rem;font-weight:500;margin-bottom:.5rem;color:#374151}.required{color:#ef4444}.fv-input{padding:.5rem .75rem;border:1px solid #d1d5db;border-radius:.375rem;font-size:1rem;line-height:1.5;transition:border-color .15s ease-in-out,box-shadow .15s ease-in-out}.fv-input:focus{outline:none;border-color:#3b82f6;box-shadow:0 0 0 3px #3b82f61a}.fv-input.error{border-color:#ef4444}.fv-input.error:focus{box-shadow:0 0 0 3px #ef44441a}.fv-error-message{margin-top:.25rem;font-size:.75rem;color:#ef4444}\n"] }]
|
|
99
|
+
}], propDecorators: { label: [{
|
|
100
|
+
type: Input
|
|
101
|
+
}], schema: [{
|
|
102
|
+
type: Input
|
|
103
|
+
}], control: [{
|
|
104
|
+
type: Input
|
|
105
|
+
}], disabled: [{
|
|
106
|
+
type: Input
|
|
107
|
+
}], readonly: [{
|
|
108
|
+
type: Input
|
|
109
|
+
}], min: [{
|
|
110
|
+
type: Input
|
|
111
|
+
}], max: [{
|
|
112
|
+
type: Input
|
|
113
|
+
}], valueChange: [{
|
|
114
|
+
type: Output
|
|
115
|
+
}], blur: [{
|
|
116
|
+
type: Output
|
|
117
|
+
}], focus: [{
|
|
118
|
+
type: Output
|
|
119
|
+
}] } });
|
|
120
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZnYtbW9udGgteWVhci1maWVsZC5jb21wb25lbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi9wcm9qZWN0cy9mdi1jb250cm9scy9zcmMvbGliL2Z2LW1vbnRoLXllYXItZmllbGQvZnYtbW9udGgteWVhci1maWVsZC5jb21wb25lbnQudHMiLCIuLi8uLi8uLi8uLi8uLi9wcm9qZWN0cy9mdi1jb250cm9scy9zcmMvbGliL2Z2LW1vbnRoLXllYXItZmllbGQvZnYtbW9udGgteWVhci1maWVsZC5jb21wb25lbnQuaHRtbCJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQ0gsU0FBUyxFQUNULEtBQUssRUFDTCxNQUFNLEVBQ04sWUFBWSxHQUdmLE1BQU0sZUFBZSxDQUFDO0FBQ3ZCLE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQztBQUMvQyxPQUFPLEVBQWUsbUJBQW1CLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUVsRSxPQUFPLEVBQUUsU0FBUyxFQUFvQixNQUFNLDhCQUE4QixDQUFDOzs7O0FBUzNFLE1BQU0sT0FBTyx5QkFBeUI7SUFDekIsS0FBSyxHQUFXLEVBQUUsQ0FBQztJQUNuQixNQUFNLENBQW9CO0lBQzFCLE9BQU8sQ0FBZTtJQUN0QixRQUFRLEdBQVksS0FBSyxDQUFDO0lBQzFCLFFBQVEsR0FBWSxLQUFLLENBQUM7SUFFMUIsR0FBRyxDQUFVLENBQUMsVUFBVTtJQUN4QixHQUFHLENBQVUsQ0FBQyxVQUFVO0lBRXZCLFdBQVcsR0FBRyxJQUFJLFlBQVksRUFBVSxDQUFDO0lBQ3pDLElBQUksR0FBRyxJQUFJLFlBQVksRUFBUSxDQUFDO0lBQ2hDLEtBQUssR0FBRyxJQUFJLFlBQVksRUFBUSxDQUFDO0lBRTNDLFlBQVksR0FBa0IsSUFBSSxDQUFDO0lBQzNCLFlBQVksQ0FBZ0I7SUFFcEMsUUFBUTtRQUNKLElBQUksQ0FBQyxJQUFJLENBQUMsT0FBTyxFQUFFLENBQUM7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SSxXQUFXO3NCQUFwQixNQUFNO2dCQUNHLElBQUk7c0JBQWIsTUFBTTtnQkFDRyxLQUFLO3NCQUFkLE1BQU0iLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQge1xyXG4gICAgQ29tcG9uZW50LFxyXG4gICAgSW5wdXQsXHJcbiAgICBPdXRwdXQsXHJcbiAgICBFdmVudEVtaXR0ZXIsXHJcbiAgICBPbkluaXQsXHJcbiAgICBPbkRlc3Ryb3ksXHJcbn0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XHJcbmltcG9ydCB7IENvbW1vbk1vZHVsZSB9IGZyb20gJ0Bhbmd1bGFyL2NvbW1vbic7XHJcbmltcG9ydCB7IEZvcm1Db250cm9sLCBSZWFjdGl2ZUZvcm1zTW9kdWxlIH0gZnJvbSAnQGFuZ3VsYXIvZm9ybXMnO1xyXG5pbXBvcnQgeyBTdWJzY3JpcHRpb24gfSBmcm9tICdyeGpzJztcclxuaW1wb3J0IHsgVmFsaWRhdG9yLCBWYWxpZGF0aW9uU2NoZW1hIH0gZnJvbSAnQGZvdmVzdHRhMi92YWxpZGF0aW9uLWVuZ2luZSc7XHJcblxyXG5AQ29tcG9uZW50KHtcclxuICAgIHN0YW5kYWxvbmU6IHRydWUsXHJcbiAgICBpbXBvcnRzOiBbQ29tbW9uTW9kdWxlLCBSZWFjdGl2ZUZvcm1zTW9kdWxlXSxcclxuICAgIHNlbGVjdG9yOiAnZnYtbW9udGgteWVhci1maWVsZCcsXHJcbiAgICB0ZW1wbGF0ZVVybDogJy4vZnYtbW9udGgteWVhci1maWVsZC5jb21wb25lbnQuaHRtbCcsXHJcbiAgICBzdHlsZVVybDogJy4vZnYtbW9udGgteWVhci1maWVsZC5jb21wb25lbnQuY3NzJyxcclxufSlcclxuZXhwb3J0IGNsYXNzIEZ2TW9udGhZZWFyRmllbGRDb21wb25lbnQgaW1wbGVtZW50cyBPbkluaXQsIE9uRGVzdHJveSB7XHJcbiAgICBASW5wdXQoKSBsYWJlbDogc3RyaW5nID0gJyc7XHJcbiAgICBASW5wdXQoKSBzY2hlbWEhOiBWYWxpZGF0aW9uU2NoZW1hO1xyXG4gICAgQElucHV0KCkgY29udHJvbCE6IEZvcm1Db250cm9sO1xyXG4gICAgQElucHV0KCkgZGlzYWJsZWQ6IGJvb2xlYW4gPSBmYWxzZTtcclxuICAgIEBJbnB1dCgpIHJlYWRvbmx5OiBib29sZWFuID0gZmFsc2U7XHJcblxyXG4gICAgQElucHV0KCkgbWluPzogc3RyaW5nOyAvLyBZWVlZLU1NXHJcbiAgICBASW5wdXQoKSBtYXg/OiBzdHJpbmc7IC8vIFlZWVktTU1cclxuXHJcbiAgICBAT3V0cHV0KCkgdmFsdWVDaGFuZ2UgPSBuZXcgRXZlbnRFbWl0dGVyPHN0cmluZz4oKTtcclxuICAgIEBPdXRwdXQoKSBibHVyID0gbmV3IEV2ZW50RW1pdHRlcjx2b2lkPigpO1xyXG4gICAgQE91dHB1dCgpIGZvY3VzID0gbmV3IEV2ZW50RW1pdHRlcjx2b2lkPigpO1xyXG5cclxuICAgIGVycm9yTWVzc2FnZTogc3RyaW5nIHwgbnVsbCA9IG51bGw7XHJcbiAgICBwcml2YXRlIHN1YnNjcmlwdGlvbj86IFN1YnNjcmlwdGlvbjtcclxuXHJcbiAgICBuZ09uSW5pdCgpOiB2b2lkIHtcclxuICAgICAgICBpZiAoIXRoaXMuY29udHJvbCkge1xyXG4gICAgICAgICAgICBjb25zb2xlLmVycm9yKCdGdk1vbnRoWWVhckZpZWxkOiBjb250cm9sIGlzIHJlcXVpcmVkJyk7XHJcbiAgICAgICAgICAgIHJldHVybjtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIHRoaXMuZXh0cmFjdENvbnN0cmFpbnRzRnJvbVNjaGVtYSgpO1xyXG5cclxuICAgICAgICB0aGlzLnN1YnNjcmlwdGlvbiA9IHRoaXMuY29udHJvbC52YWx1ZUNoYW5nZXMuc3Vic2NyaWJlKCh2YWx1ZSkgPT4ge1xyXG4gICAgICAgICAgICB0aGlzLnZhbGlkYXRlVmFsdWUodmFsdWUpO1xyXG4gICAgICAgICAgICB0aGlzLnZhbHVlQ2hhbmdlLmVtaXQodmFsdWUpO1xyXG4gICAgICAgIH0pO1xyXG5cclxuICAgICAgICBpZiAodGhpcy5jb250cm9sLnZhbHVlKSB7XHJcbiAgICAgICAgICAgIHRoaXMudmFsaWRhdGVWYWx1ZSh0aGlzLmNvbnRyb2wudmFsdWUpO1xyXG4gICAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICBuZ09uRGVzdHJveSgpOiB2b2lkIHtcclxuICAgICAgICB0aGlzLnN1YnNjcmlwdGlvbj8udW5zdWJzY3JpYmUoKTtcclxuICAgIH1cclxuXHJcbiAgICBwcml2YXRlIGV4dHJhY3RDb25zdHJhaW50c0Zyb21TY2hlbWEoKTogdm9pZCB7XHJcbiAgICAgICAgaWYgKCF0aGlzLnNjaGVtYT8ucnVsZXMpIHJldHVybjtcclxuXHJcbiAgICAgICAgZm9yIChjb25zdCBydWxlIG9mIHRoaXMuc2NoZW1hLnJ1bGVzKSB7XHJcbiAgICAgICAgICAgIGlmIChydWxlLm5hbWUgPT09ICdtaW5EYXRlJyAmJiAhdGhpcy5taW4pIHtcclxuICAgICAgICAgICAgICAgIHRoaXMubWluID0gdGhpcy5mb3JtYXRNb250aChydWxlLnBhcmFtcz8uWyd2YWx1ZSddKTtcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICBpZiAocnVsZS5uYW1lID09PSAnbWF4RGF0ZScgJiYgIXRoaXMubWF4KSB7XHJcbiAgICAgICAgICAgICAgICB0aGlzLm1heCA9IHRoaXMuZm9ybWF0TW9udGgocnVsZS5wYXJhbXM/LlsndmFsdWUnXSk7XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgcHJpdmF0ZSBmb3JtYXRNb250aChkYXRlOiBzdHJpbmcgfCBEYXRlKTogc3RyaW5nIHtcclxuICAgICAgICBpZiAoIWRhdGUpIHJldHVybiAnJztcclxuICAgICAgICBjb25zdCBkID0gbmV3IERhdGUoZGF0ZSk7XHJcbiAgICAgICAgaWYgKGlzTmFOKGQuZ2V0VGltZSgpKSkgcmV0dXJuICcnO1xyXG4gICAgICAgIHJldHVybiBkLnRvSVNPU3RyaW5nKCkuc2xpY2UoMCwgNyk7IC8vIFlZWVktTU1cclxuICAgIH1cclxuXHJcbiAgICBwcml2YXRlIHZhbGlkYXRlVmFsdWUodmFsdWU6IGFueSk6IHZvaWQge1xyXG4gICAgICAgIGlmICghdGhpcy5zY2hlbWEpIHJldHVybjtcclxuXHJcbiAgICAgICAgLy8gRm9yIG1vbnRoIHBpY2tlciwgdmFsdWUgaXMgWVlZWS1NTS4gXHJcbiAgICAgICAgLy8gVGhlIGdlbmVyaWMgVmFsaWRhdG9yIHJ1bGVzIHVzZSBuZXcgRGF0ZSh2YWx1ZSksIHdoaWNoIHRyZWF0cyBZWVlZLU1NIGFzIFlZWVktTU0tMDEuXHJcbiAgICAgICAgLy8gVGhpcyBnZW5lcmFsbHkgd29ya3MgZm9yIG1pbi9tYXggbG9naWMuXHJcbiAgICAgICAgY29uc3QgcmVzdWx0ID0gVmFsaWRhdG9yLnZhbGlkYXRlKHZhbHVlLCB0aGlzLnNjaGVtYSk7XHJcbiAgICAgICAgdGhpcy5lcnJvck1lc3NhZ2UgPSByZXN1bHQuZXJyb3JLZXk7XHJcblxyXG4gICAgICAgIGlmICghcmVzdWx0LmlzVmFsaWQgJiYgcmVzdWx0LmVycm9yS2V5KSB7XHJcbiAgICAgICAgICAgIHRoaXMuY29udHJvbC5zZXRFcnJvcnMoeyBbcmVzdWx0LmVycm9yS2V5XTogdHJ1ZSB9KTtcclxuICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgICB0aGlzLmNvbnRyb2wuc2V0RXJyb3JzKG51bGwpO1xyXG4gICAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICBvbkJsdXIoZXZlbnQ/OiBGb2N1c0V2ZW50KTogdm9pZCB7XHJcbiAgICAgICAgdGhpcy52YWxpZGF0ZVZhbHVlKHRoaXMuY29udHJvbC52YWx1ZSk7XHJcbiAgICAgICAgdGhpcy5ibHVyLmVtaXQoKTtcclxuICAgIH1cclxuXHJcbiAgICBvbkZvY3VzKGV2ZW50PzogRm9jdXNFdmVudCk6IHZvaWQge1xyXG4gICAgICAgIHRoaXMuZm9jdXMuZW1pdCgpO1xyXG4gICAgfVxyXG5cclxuICAgIGlzUmVxdWlyZWQoKTogYm9vbGVhbiB7XHJcbiAgICAgICAgcmV0dXJuIChcclxuICAgICAgICAgICAgdGhpcy5zY2hlbWE/LnJ1bGVzPy5zb21lKFxyXG4gICAgICAgICAgICAgICAgKHIpID0+IHIubmFtZSA9PT0gJ3JlcXVpcmVkJyAmJiByLnBhcmFtcz8uWydlbmFibGVkJ11cclxuICAgICAgICAgICAgKSB8fCBmYWxzZVxyXG4gICAgICAgICk7XHJcbiAgICB9XHJcblxyXG4gICAgZ2V0RXJyb3JNZXNzYWdlKCk6IHN0cmluZyB7XHJcbiAgICAgICAgaWYgKCF0aGlzLmVycm9yTWVzc2FnZSkgcmV0dXJuICcnO1xyXG5cclxuICAgICAgICBjb25zdCBlcnJvck1lc3NhZ2VzOiBSZWNvcmQ8c3RyaW5nLCBzdHJpbmc+ID0ge1xyXG4gICAgICAgICAgICBFUlJfUkVRVUlSRUQ6ICdNb250aC9ZZWFyIGlzIHJlcXVpcmVkJyxcclxuICAgICAgICAgICAgRVJSX01JTl9EQVRFOiBgRGF0ZSBtdXN0IGJlIGFmdGVyICR7dGhpcy5taW59YCxcclxuICAgICAgICAgICAgRVJSX01BWF9EQVRFOiBgRGF0ZSBtdXN0IGJlIGJlZm9yZSAke3RoaXMubWF4fWAsXHJcbiAgICAgICAgfTtcclxuXHJcbiAgICAgICAgcmV0dXJuIGVycm9yTWVzc2FnZXNbdGhpcy5lcnJvck1lc3NhZ2VdIHx8IHRoaXMuZXJyb3JNZXNzYWdlO1xyXG4gICAgfVxyXG59XHJcbiIsIjxkaXYgY2xhc3M9XCJmdi1maWVsZC1jb250YWluZXJcIj5cclxuICAgIDxsYWJlbCAqbmdJZj1cImxhYmVsXCIgY2xhc3M9XCJmdi1sYWJlbFwiPlxyXG4gICAgICAgIHt7IGxhYmVsIH19IDxzcGFuICpuZ0lmPVwiaXNSZXF1aXJlZCgpXCIgY2xhc3M9XCJyZXF1aXJlZFwiPio8L3NwYW4+XHJcbiAgICA8L2xhYmVsPlxyXG5cclxuICAgIDxpbnB1dCB0eXBlPVwibW9udGhcIiBbZm9ybUNvbnRyb2xdPVwiY29udHJvbFwiIGNsYXNzPVwiZnYtaW5wdXRcIiBbY2xhc3MuZXJyb3JdPVwiISFlcnJvck1lc3NhZ2VcIiBbYXR0ci5taW5dPVwibWluXCJcclxuICAgICAgICBbYXR0ci5tYXhdPVwibWF4XCIgW3JlYWRvbmx5XT1cInJlYWRvbmx5XCIgKGJsdXIpPVwib25CbHVyKCRldmVudClcIiAoZm9jdXMpPVwib25Gb2N1cygkZXZlbnQpXCIgLz5cclxuXHJcbiAgICA8ZGl2ICpuZ0lmPVwiZXJyb3JNZXNzYWdlXCIgY2xhc3M9XCJmdi1lcnJvci1tZXNzYWdlXCI+XHJcbiAgICAgICAge3sgZ2V0RXJyb3JNZXNzYWdlKCkgfX1cclxuICAgIDwvZGl2PlxyXG48L2Rpdj4iXX0=
|