@bnsights/bbsf-controls 1.0.176 → 1.0.178

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.
@@ -27,7 +27,7 @@ import * as i2$1 from 'ngx-toastr';
27
27
  import { ToastrModule } from 'ngx-toastr';
28
28
  import { OverlayModule } from '@angular/cdk/overlay';
29
29
  import * as i5 from '@angular/common';
30
- import { CommonModule, DatePipe } from '@angular/common';
30
+ import { CommonModule, DatePipe, KeyValuePipe } from '@angular/common';
31
31
  import * as i1 from '@angular/common/http';
32
32
  import { HttpHeaders, HttpParams, HttpEventType, HttpClientModule } from '@angular/common/http';
33
33
  import * as i0 from '@angular/core';
@@ -52,7 +52,7 @@ import { TranslateService } from '@ngx-translate/core';
52
52
  import { SweetAlert2Module } from '@sweetalert2/ngx-sweetalert2';
53
53
  import * as i3 from '@bnsights/bbsf-utilities';
54
54
  import { RequestOptionsModel, environment as environment$1, BBSFUtilitiesModule, UtilityService, ConfigurationService, EnvironmentService, AuthService } from '@bnsights/bbsf-utilities';
55
- import { Subject, Observable, noop as noop$1, of, EMPTY, Subscription, switchMap as switchMap$1 } from 'rxjs';
55
+ import { Subject, Observable, noop as noop$1, of, Subscription, EMPTY, switchMap as switchMap$1 } from 'rxjs';
56
56
  import { switchMap, map, tap } from 'rxjs/operators';
57
57
  import * as i6 from '@angular/cdk/bidi';
58
58
  import dayGridPlugin from '@fullcalendar/daygrid';
@@ -2107,563 +2107,1069 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImpo
2107
2107
  }], ctorParameters: () => [{ type: i3.RequestHandlerService }] });
2108
2108
 
2109
2109
  class FileUploadComponent {
2110
- static { this.controlContainerstatic = null; }
2111
- constructor(controlContainer, MultipleFileUplaodControlHost, controlUtility, UtilityService, controlValidationService, globalSettings, fileUploadService) {
2110
+ static { this.controlContainerStatic = null; }
2111
+ constructor(controlContainer, multipleFileUploadControlHost, controlUtility, utilityService, controlValidationService, globalSettings, fileUploadService) {
2112
2112
  this.controlContainer = controlContainer;
2113
- this.MultipleFileUplaodControlHost = MultipleFileUplaodControlHost;
2113
+ this.multipleFileUploadControlHost = multipleFileUploadControlHost;
2114
2114
  this.controlUtility = controlUtility;
2115
- this.UtilityService = UtilityService;
2115
+ this.utilityService = utilityService;
2116
2116
  this.controlValidationService = controlValidationService;
2117
2117
  this.globalSettings = globalSettings;
2118
2118
  this.fileUploadService = fileUploadService;
2119
+ this.BYTES_TO_MB = 1024 * 1024;
2120
+ this.PROGRESS_COMPLETE = 100;
2121
+ this.PROGRESS_NEAR_COMPLETE = 95;
2122
+ this.ERROR_DISPLAY_DURATION = 5000;
2123
+ this.MAX_MEMORY_USAGE = 100 * 1024 * 1024; // 100MB limit
2124
+ this.currentMemoryUsage = 0;
2125
+ this.isSubmitted = false;
2119
2126
  this.OnChange = new EventEmitter();
2120
2127
  this.isUploadComplete = new EventEmitter();
2121
2128
  this.validationMessage = '';
2122
2129
  this.validationCountMessage = '';
2130
+ this.hasAnotherDropZoneOver = false;
2123
2131
  this.acceptedType = '';
2124
2132
  this.acceptedTypeArray = [];
2125
2133
  this.toolTipTypeArray = [];
2126
2134
  this.markAllAsTouched = false;
2127
2135
  this.validationRules = [];
2128
- this.validationRulesasync = [];
2136
+ this.validationRulesAsync = [];
2137
+ this.file = null;
2129
2138
  this.deletedFiles = [];
2139
+ this.subscriptions = new Subscription();
2130
2140
  this.resetError = () => {
2131
2141
  this.controlValidationService.removeGlobalError();
2132
2142
  };
2133
- //External Method
2134
2143
  this.removeRequiredValidation = () => {
2135
2144
  this.controlUtility.removeRequiredValidation(this.fileUploadFormControl, this.validationRules, this.options);
2136
2145
  };
2137
- //External Method
2138
2146
  this.addRequiredValidation = () => {
2139
2147
  this.controlUtility.addRequiredValidation(this.fileUploadFormControl, this.validationRules, this.options);
2140
2148
  };
2141
- //External Method
2142
2149
  this.removeCustomValidation = (customValidation) => {
2143
2150
  this.controlUtility.removeCustomValidation(this.fileUploadFormControl, this.validationRules, customValidation);
2144
2151
  };
2145
- //External Method
2146
2152
  this.addCustomValidation = (customValidation) => {
2147
2153
  this.controlUtility.addCustomValidation(this.fileUploadFormControl, this.validationRules, customValidation);
2148
2154
  };
2149
- //External Method
2150
2155
  this.isValid = () => {
2151
2156
  this.controlUtility.isValid(this.fileUploadFormControl);
2157
+ return this.fileUploadFormControl.valid;
2152
2158
  };
2153
- FileUploadComponent.controlContainerstatic = this.controlContainer;
2159
+ FileUploadComponent.controlContainerStatic = this.controlContainer;
2160
+ this.initializeUploader();
2161
+ }
2162
+ initializeUploader() {
2154
2163
  this.uploader = new FileUploader({
2155
- disableMultipart: false // 'DisableMultipart' must be 'true' for formatDataFunction to be called.
2164
+ disableMultipart: false
2156
2165
  });
2157
- this.hasAnotherDropZoneOver = false;
2158
2166
  }
2159
2167
  ngOnInit() {
2168
+ this.initializeModels();
2169
+ this.setViewType();
2170
+ this.processInitialValue();
2171
+ this.setupLabels();
2172
+ this.setupFileTypeValidation();
2173
+ this.setupFormControl();
2174
+ this.setupSubscriptions();
2175
+ }
2176
+ initializeModels() {
2160
2177
  this.fileUploadModel = new FileUploadModel();
2161
2178
  this.multipleFileUploadModel = new MultipleFileUploadModel();
2162
- if (!this.options.viewType)
2179
+ }
2180
+ setViewType() {
2181
+ if (!this.options.viewType) {
2163
2182
  this.options.viewType = this.globalSettings.viewType;
2183
+ }
2184
+ }
2185
+ processInitialValue() {
2164
2186
  if (this.options.value == null) {
2165
- if (this.options.isMultipleFile == true) {
2166
- //this.options.Value=this.multipleFileUploadModel
2167
- }
2168
- else {
2169
- // this.options.Value=this.fileUploadModel
2170
- }
2187
+ return;
2188
+ }
2189
+ if (this.options.isMultipleFile) {
2190
+ this.processMultipleFileValue();
2171
2191
  }
2172
2192
  else {
2173
- if (this.options.isMultipleFile == true) {
2174
- let files = [];
2175
- this.multipleFileUploadModel.existingFiles = this.options.value.existingFiles;
2176
- this.multipleFileUploadModel.uploadedFiles = [];
2177
- for (let index = 0; index < this.options.value.existingFiles.length; index++) {
2178
- const element = this.options.value.existingFiles[index];
2179
- var bytes = new Uint8Array(element.bytes);
2180
- var base64 = btoa(String.fromCharCode(null, bytes));
2181
- this.fileLikeObject = {
2182
- name: element.nameWithExtension,
2183
- type: element.mimeType,
2184
- rawFile: base64
2185
- };
2186
- // let blob: any;
2187
- // blob = new Blob(['']) as any;
2188
- // blob.name = element.FileName;
2189
- // blob.lastModifiedDate = null;
2190
- // blob.webkitRelativePath = '';
2191
- let file = this.fileLikeObject;
2192
- file.url = element.fileURL;
2193
- files.push(file);
2194
- }
2195
- this.uploader.addToQueue(files);
2196
- console.log(this.uploader.queue);
2193
+ this.processSingleFileValue();
2194
+ }
2195
+ this.uploader.queue.forEach((element) => {
2196
+ element.progress = this.PROGRESS_COMPLETE;
2197
+ });
2198
+ }
2199
+ processMultipleFileValue() {
2200
+ const files = [];
2201
+ this.multipleFileUploadModel.existingFiles = this.options.value.existingFiles;
2202
+ this.multipleFileUploadModel.uploadedFiles = [];
2203
+ for (const element of this.options.value.existingFiles) {
2204
+ const fileLikeObject = this.createFileLikeObject(element);
2205
+ files.push(fileLikeObject);
2206
+ }
2207
+ this.uploader.addToQueue(files);
2208
+ }
2209
+ processSingleFileValue() {
2210
+ const element = this.options.value.file ?? this.options.value;
2211
+ const fileLikeObject = this.createFileLikeObject(element);
2212
+ this.file = element;
2213
+ this.uploader.addToQueue([fileLikeObject]);
2214
+ if (!this.options.value.file) {
2215
+ this.fileUploadModel = new FileUploadModel();
2216
+ this.fileUploadModel.file = this.options.value;
2217
+ }
2218
+ else {
2219
+ this.fileUploadModel = this.options.value;
2220
+ }
2221
+ this.options.value = this.fileUploadModel;
2222
+ }
2223
+ createFileLikeObject(element) {
2224
+ const bytes = new Uint8Array(element.bytes);
2225
+ const base64 = btoa(String.fromCharCode(...bytes));
2226
+ return {
2227
+ name: element.nameWithExtension || element.fileName,
2228
+ type: element.mimeType || element.fileType,
2229
+ rawFile: base64,
2230
+ size: element.fileSizeInMB ? element.fileSizeInMB * this.BYTES_TO_MB : 0,
2231
+ lastModifiedDate: new Date(),
2232
+ url: element.fullFileURL
2233
+ };
2234
+ }
2235
+ setupLabels() {
2236
+ if (this.options.labelKey) {
2237
+ this.options.labelValue = this.utilityService.getResourceValue(this.options.labelKey);
2238
+ }
2239
+ }
2240
+ setupFileTypeValidation() {
2241
+ if (!this.options.fileUploadAcceptsTypes?.length) {
2242
+ console.warn('FileUpload: No file types specified in fileUploadAcceptsTypes');
2243
+ return;
2244
+ }
2245
+ try {
2246
+ this.processAcceptedTypes();
2247
+ this.buildValidationMessage();
2248
+ // Log the processed types for debugging
2249
+ console.log('FileUpload: Processed file types:', {
2250
+ original: this.options.fileUploadAcceptsTypes,
2251
+ processed: this.acceptedTypeArray,
2252
+ acceptAttribute: this.acceptedType,
2253
+ displayTypes: this.toolTipTypeArray
2254
+ });
2255
+ }
2256
+ catch (error) {
2257
+ console.error('FileUpload: Error processing file types:', error);
2258
+ // Fallback to accepting all files if processing fails
2259
+ this.acceptedType = '';
2260
+ this.acceptedTypeArray = [];
2261
+ this.toolTipTypeArray = [];
2262
+ }
2263
+ }
2264
+ processAcceptedTypes() {
2265
+ // Process each file type and extract individual MIME types
2266
+ const allMimeTypes = [];
2267
+ for (const fileType of this.options.fileUploadAcceptsTypes) {
2268
+ if (fileType.includes(',')) {
2269
+ // Handle types like ImageTypes that contain multiple MIME types
2270
+ const mimeTypes = fileType.split(',').map(type => type.trim());
2271
+ allMimeTypes.push(...mimeTypes);
2197
2272
  }
2198
2273
  else {
2199
- const element = this.options.value.file ?? this.options.value;
2200
- var bytes = new Uint8Array(element.bytes);
2201
- var base64 = btoa(String.fromCharCode(null, bytes));
2202
- this.fileLikeObject = {
2203
- name: element.nameWithExtension,
2204
- type: element.mimeType,
2205
- rawFile: base64
2206
- };
2207
- this.file = element;
2208
- let file = this.fileLikeObject;
2209
- file.url = element.fileURL;
2210
- this.uploader.addToQueue([file]);
2211
- if (!this.options.value.file) {
2212
- this.fileUploadModel = new FileUploadModel();
2213
- this.fileUploadModel.file = this.options.value;
2214
- }
2215
- else
2216
- this.fileUploadModel = this.options.value;
2217
- this.options.value = this.fileUploadModel;
2274
+ // Single MIME type
2275
+ allMimeTypes.push(fileType);
2218
2276
  }
2219
- this.uploader.queue.forEach((element) => {
2220
- element.progress = 100;
2221
- });
2222
2277
  }
2223
- if (this.options.labelKey != null && this.options.labelKey != '')
2224
- this.options.labelValue = this.UtilityService.getResourceValue(this.options.labelKey);
2225
- if (this.options.fileUploadAcceptsTypes != null &&
2226
- this.options.fileUploadAcceptsTypes.length > 0) {
2227
- for (let index = 0; index < this.options.fileUploadAcceptsTypes.length; index++) {
2228
- const Type = this.options.fileUploadAcceptsTypes[index];
2229
- this.acceptedType = this.acceptedType + Type + ',';
2230
- }
2231
- this.acceptedTypeArray = this.acceptedType.split(',');
2232
- this.acceptedTypeArray = this.acceptedTypeArray.filter((value) => value != '');
2233
- for (let index = 0; index < this.acceptedTypeArray.length; index++) {
2234
- const element = this.acceptedTypeArray[index];
2235
- for (let index = 0; index < this.acceptedTypeArray.length; index++) {
2236
- const element = this.acceptedTypeArray[index];
2237
- switch (element) {
2238
- case 'application/pdf':
2239
- if (!this.toolTipTypeArray.includes('PDF'))
2240
- this.toolTipTypeArray.push('PDF');
2241
- break;
2242
- case 'application/msword':
2243
- if (!this.toolTipTypeArray.includes('Word'))
2244
- this.toolTipTypeArray.push('Word');
2245
- break;
2246
- case 'application/vnd.openxmlformats-officedocument.wordprocessingml.document':
2247
- if (!this.toolTipTypeArray.includes('Word'))
2248
- this.toolTipTypeArray.push('Word');
2249
- break;
2250
- case 'application/vnd.ms-excel':
2251
- if (!this.toolTipTypeArray.includes('Excel'))
2252
- this.toolTipTypeArray.push('Excel');
2253
- break;
2254
- case 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet':
2255
- if (!this.toolTipTypeArray.includes('Excel'))
2256
- this.toolTipTypeArray.push('Excel');
2257
- break;
2258
- case 'application/vnd.ms-powerpoint':
2259
- if (!this.toolTipTypeArray.includes('PowerPoint'))
2260
- this.toolTipTypeArray.push('PowerPoint');
2261
- break;
2262
- case 'application/vnd.openxmlformats-officedocument.presentationml.presentation':
2263
- if (!this.toolTipTypeArray.includes('PowerPoint'))
2264
- this.toolTipTypeArray.push('PowerPoint');
2265
- break;
2266
- case 'image/png':
2267
- if (!this.toolTipTypeArray.includes('PNG'))
2268
- this.toolTipTypeArray.push('PNG');
2269
- break;
2270
- case 'image/bmp':
2271
- if (!this.toolTipTypeArray.includes('BMP'))
2272
- this.toolTipTypeArray.push('BMP');
2273
- break;
2274
- case 'image/jpeg':
2275
- if (!this.toolTipTypeArray.includes('JPEG'))
2276
- this.toolTipTypeArray.push('JPEG');
2277
- break;
2278
- case 'application/zip':
2279
- if (!this.toolTipTypeArray.includes('ZIP'))
2280
- this.toolTipTypeArray.push('ZIP');
2281
- break;
2282
- case 'application/x-rar-compressed':
2283
- if (!this.toolTipTypeArray.includes('RAR'))
2284
- this.toolTipTypeArray.push('RAR');
2285
- break;
2286
- case 'video/mp4':
2287
- if (!this.toolTipTypeArray.includes('MP4'))
2288
- this.toolTipTypeArray.push('MP4');
2289
- break;
2290
- case 'video/avi':
2291
- if (!this.toolTipTypeArray.includes('AVI'))
2292
- this.toolTipTypeArray.push('AVI');
2293
- break;
2294
- case 'video/quicktime':
2295
- if (!this.toolTipTypeArray.includes('MOV'))
2296
- this.toolTipTypeArray.push('MOV');
2297
- break;
2298
- case 'video/mpeg':
2299
- if (!this.toolTipTypeArray.includes('MPEG'))
2300
- this.toolTipTypeArray.push('MPEG');
2301
- break;
2302
- case 'audio/mpeg':
2303
- if (!this.toolTipTypeArray.includes('MP3'))
2304
- this.toolTipTypeArray.push('MP3');
2305
- break;
2306
- case 'video/x-flv':
2307
- if (!this.toolTipTypeArray.includes('FLV'))
2308
- this.toolTipTypeArray.push('FLV');
2309
- break;
2310
- case 'video/x-ms-wmv':
2311
- if (!this.toolTipTypeArray.includes('WMV'))
2312
- this.toolTipTypeArray.push('WMV');
2313
- break;
2314
- case 'image/svg+xml':
2315
- if (!this.toolTipTypeArray.includes('SVG'))
2316
- this.toolTipTypeArray.push('SVG');
2317
- break;
2318
- case 'text/plain':
2319
- if (!this.toolTipTypeArray.includes('Txt'))
2320
- this.toolTipTypeArray.push('Txt');
2321
- break;
2322
- case 'application/BN':
2323
- if (!this.toolTipTypeArray.includes('License'))
2324
- this.toolTipTypeArray.push('License');
2325
- break;
2326
- default:
2327
- break;
2328
- }
2329
- }
2278
+ // Filter out empty strings and normalize MIME types
2279
+ const normalizedMimeTypes = allMimeTypes
2280
+ .filter(type => type.trim())
2281
+ .map(type => type.trim().toLowerCase());
2282
+ // Create the accept attribute string for HTML input
2283
+ this.acceptedType = normalizedMimeTypes.join(',');
2284
+ // Store the processed array for validation (keep original case for display)
2285
+ this.acceptedTypeArray = allMimeTypes.filter(type => type.trim());
2286
+ const mimeTypeMap = this.getMimeTypeMap();
2287
+ for (const type of this.acceptedTypeArray) {
2288
+ const displayType = mimeTypeMap[type];
2289
+ if (displayType && !this.toolTipTypeArray.includes(displayType)) {
2290
+ this.toolTipTypeArray.push(displayType);
2330
2291
  }
2331
- this.validationMessage =
2332
- this.validationMessage +
2333
- `${this.UtilityService.getResourceValue('Extensions')} (${this.toolTipTypeArray}) `;
2292
+ }
2293
+ }
2294
+ getMimeTypeMap() {
2295
+ return {
2296
+ 'application/pdf': 'PDF',
2297
+ 'application/msword': 'Word',
2298
+ 'application/vnd.openxmlformats-officedocument.wordprocessingml.document': 'Word',
2299
+ 'application/vnd.ms-excel': 'Excel',
2300
+ 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet': 'Excel',
2301
+ 'application/vnd.ms-powerpoint': 'PowerPoint',
2302
+ 'application/vnd.openxmlformats-officedocument.presentationml.presentation': 'PowerPoint',
2303
+ 'image/png': 'PNG',
2304
+ 'image/bmp': 'BMP',
2305
+ 'image/jpeg': 'JPEG',
2306
+ 'image/svg+xml': 'SVG',
2307
+ 'application/zip': 'ZIP',
2308
+ 'application/x-rar-compressed': 'RAR',
2309
+ 'video/webm': 'WebM',
2310
+ 'video/ogg': 'OGG',
2311
+ 'video/mp4': 'MP4',
2312
+ 'video/quicktime': 'MOV',
2313
+ 'video/x-msvideo': 'AVI',
2314
+ 'video/x-ms-wmv': 'WMV',
2315
+ 'video/avi': 'AVI',
2316
+ 'video/mpeg': 'MPEG',
2317
+ 'video/x-flv': 'FLV',
2318
+ 'audio/mpeg': 'MP3',
2319
+ 'text/plain': 'Txt',
2320
+ 'text/xml': 'XML',
2321
+ 'application/json': 'JSON',
2322
+ 'application/octet-stream': 'Binary',
2323
+ 'application/BN': 'License'
2324
+ };
2325
+ }
2326
+ buildValidationMessage() {
2327
+ const messages = [];
2328
+ if (this.toolTipTypeArray.length) {
2329
+ messages.push(`${this.utilityService.getResourceValue('Extensions')} (${this.toolTipTypeArray.join(', ')})`);
2334
2330
  }
2335
2331
  if (this.options.fileMaxSizeInMB > 0) {
2336
- this.validationMessage =
2337
- this.validationMessage +
2338
- `<br /> ${this.UtilityService.getResourceValue('FileMaxSizeInMB') + this.options.fileMaxSizeInMB} `;
2332
+ messages.push(`${this.utilityService.getResourceValue('FileMaxSizeInMB')}${this.options.fileMaxSizeInMB}`);
2339
2333
  }
2340
2334
  if (this.options.minNoOfFiles > 0) {
2341
- this.validationMessage =
2342
- this.validationMessage +
2343
- `<br /> ${this.UtilityService.getResourceValue('MinFileCountValidationKey') + this.options.minNoOfFiles}`;
2335
+ messages.push(`${this.utilityService.getResourceValue('MinFileCountValidationKey')}${this.options.minNoOfFiles}`);
2344
2336
  }
2345
2337
  if (this.options.maxNoOfFiles > 0) {
2346
- this.validationMessage =
2347
- this.validationMessage +
2348
- `<br /> ${this.UtilityService.getResourceValue('MaxFileCountValidationKey') + this.options.maxNoOfFiles}`;
2349
- }
2350
- if (this.options.fileUploadAcceptsTypes != null &&
2351
- this.options.fileUploadAcceptsTypes.length > 0) {
2338
+ messages.push(`${this.utilityService.getResourceValue('MaxFileCountValidationKey')}${this.options.maxNoOfFiles}`);
2352
2339
  }
2340
+ this.validationMessage = messages.join(' <br/> ');
2341
+ }
2342
+ setupFormControl() {
2353
2343
  this.group.addControl(this.options.name, new FormControl(''));
2354
- this.fileUploadFormControl = this.group.controls[this.options.name]; // new FormControl('',validationRules);
2355
- if (this.options.customValidation.length > 0) {
2356
- let Validations = this.options.customValidation;
2357
- for (let index = 0; index < Validations.length; index++) {
2358
- const Validation = Validations[index];
2359
- this.validationRules.push(Validation.functionBody);
2344
+ this.fileUploadFormControl = this.group.controls[this.options.name];
2345
+ this.setupValidators();
2346
+ this.setupCountMessage();
2347
+ this.applyValidatorsAndState();
2348
+ this.fileUploadFormControl.setValue(this.options.value, { emitEvent: false });
2349
+ }
2350
+ setupValidators() {
2351
+ if (this.options.customValidation?.length) {
2352
+ for (const validation of this.options.customValidation) {
2353
+ this.validationRules.push(validation.functionBody);
2360
2354
  }
2361
2355
  }
2362
- if (this.options.isMultipleFile && this.options.maxNoOfFiles > 0) {
2363
- this.validationCountMessage = `${this.UtilityService.getResourceValue('MaxFilesCount')} : ${this.options.maxNoOfFiles}`;
2364
- }
2365
2356
  if (this.options.isRequired) {
2366
2357
  this.validationRules.push(Validators.required);
2367
2358
  }
2359
+ }
2360
+ setupCountMessage() {
2361
+ if (this.options.isMultipleFile && this.options.maxNoOfFiles > 0) {
2362
+ this.validationCountMessage = `${this.utilityService.getResourceValue('MaxFilesCount')} : ${this.options.maxNoOfFiles}`;
2363
+ }
2364
+ }
2365
+ applyValidatorsAndState() {
2368
2366
  this.fileUploadFormControl.setValidators(this.validationRules);
2369
- this.fileUploadFormControl.setAsyncValidators(this.validationRulesasync);
2367
+ if (this.validationRulesAsync.length > 0) {
2368
+ this.fileUploadFormControl.setAsyncValidators(this.validationRulesAsync);
2369
+ }
2370
2370
  if (this.options.isDisabled) {
2371
2371
  this.fileUploadFormControl.disable();
2372
2372
  }
2373
- this.MultipleFileUplaodControlHost.ngSubmit.subscribe((value) => {
2373
+ }
2374
+ setupSubscriptions() {
2375
+ this.multipleFileUploadControlHost.ngSubmit.subscribe(() => {
2374
2376
  this.group.markAllAsTouched();
2375
2377
  this.markAllAsTouched = true;
2376
2378
  });
2377
- this.fileUploadFormControl.setValue(this.options.value);
2378
2379
  }
2379
2380
  ngAfterViewInit() {
2380
- if (this.options.attributeList != null) {
2381
- var element = document.getElementById(this.options.name);
2382
- for (let index = 0; index < this.options.attributeList.length; index++) {
2383
- element.setAttribute(this.options.attributeList[index].key, this.options.attributeList[index].value);
2381
+ this.applyAttributes();
2382
+ }
2383
+ applyAttributes() {
2384
+ if (!this.options.attributeList?.length) {
2385
+ return;
2386
+ }
2387
+ const element = document.getElementById(this.options.name);
2388
+ if (element) {
2389
+ for (const attribute of this.options.attributeList) {
2390
+ element.setAttribute(attribute.key, attribute.value);
2384
2391
  }
2385
2392
  }
2386
2393
  }
2387
2394
  showGlobalError() {
2388
2395
  this.controlUtility.showGlobalError();
2389
2396
  }
2390
- getErrorValidation(ErrorList) {
2397
+ getErrorValidation(errorList) {
2391
2398
  if (this.markAllAsTouched && this.group.invalid) {
2392
2399
  this.showGlobalError();
2393
2400
  this.markAllAsTouched = false;
2394
2401
  }
2395
- return this.controlUtility.getErrorValidationMassage(ErrorList, this.group, this.options);
2402
+ if (errorList && errorList.length > 0) {
2403
+ for (const error of errorList) {
2404
+ if (error.key === 'InvalidFiles') {
2405
+ return error.value;
2406
+ }
2407
+ }
2408
+ }
2409
+ return this.controlUtility.getErrorValidationMassage(errorList, this.group, this.options);
2396
2410
  }
2397
2411
  fileOverAnother(event) {
2398
- this.hasAnotherDropZoneOver = event;
2412
+ this.hasAnotherDropZoneOver = !!event;
2399
2413
  }
2400
2414
  isHideInput() {
2401
2415
  if (this.options.isMultipleFile) {
2402
- if (this.options.maxNoOfFiles != null &&
2403
- this.options.maxNoOfFiles > 0 &&
2404
- this.options.maxNoOfFiles == this.uploader.queue.length) {
2405
- return true;
2416
+ return this.options.maxNoOfFiles > 0 &&
2417
+ this.options.maxNoOfFiles === this.uploader.queue.length;
2418
+ }
2419
+ return this.uploader.queue.length > 0;
2420
+ }
2421
+ onFileChange() {
2422
+ this.validateFileConstraints();
2423
+ const fileProcessingResult = this.processNewlyAddedFiles();
2424
+ this.handleFileValidationResults(fileProcessingResult);
2425
+ this.processValidFilesForUpload();
2426
+ }
2427
+ processNewlyAddedFiles() {
2428
+ const addedQueue = this.getNewlyAddedFiles();
2429
+ const validationResult = this.validateFilesInQueue(addedQueue);
2430
+ return {
2431
+ validFiles: addedQueue.filter(file => !validationResult.invalidFiles.includes(file)),
2432
+ invalidFiles: validationResult.invalidFiles,
2433
+ errors: validationResult.errors
2434
+ };
2435
+ }
2436
+ getNewlyAddedFiles() {
2437
+ return this.uploader.queue.filter((obj) => obj['some']?.lastModified != null);
2438
+ }
2439
+ validateFilesInQueue(fileQueue) {
2440
+ const validationErrors = [];
2441
+ const invalidFiles = [];
2442
+ const processedDuplicateNames = new Set();
2443
+ for (const element of fileQueue) {
2444
+ const file = element.file;
2445
+ if (!file)
2446
+ continue;
2447
+ const fileValidation = this.validateSingleFile(file, element, processedDuplicateNames);
2448
+ if (!fileValidation.isValid) {
2449
+ invalidFiles.push(element);
2450
+ validationErrors.push(...fileValidation.errors);
2406
2451
  }
2407
2452
  }
2408
- else {
2409
- if (this.uploader.queue.length > 0) {
2410
- return true;
2453
+ return {
2454
+ isValid: invalidFiles.length === 0,
2455
+ errors: validationErrors,
2456
+ invalidFiles
2457
+ };
2458
+ }
2459
+ validateSingleFile(file, element, processedDuplicateNames) {
2460
+ const errors = [];
2461
+ const sizeValid = this.validateIndividualFileSize(file);
2462
+ const typeValid = this.validateIndividualFileType(file);
2463
+ const nameValid = this.validateDuplicateFileName(file, element);
2464
+ if (!sizeValid) {
2465
+ errors.push(this.createFileSizeErrorMessage(file.name));
2466
+ }
2467
+ if (!typeValid) {
2468
+ errors.push(this.createFileTypeErrorMessage(file.name));
2469
+ }
2470
+ if (!nameValid) {
2471
+ const duplicateError = this.createDuplicateFileErrorMessage(file.name, processedDuplicateNames);
2472
+ if (duplicateError) {
2473
+ errors.push(duplicateError);
2411
2474
  }
2412
2475
  }
2413
- return false;
2476
+ return {
2477
+ isValid: sizeValid && typeValid && nameValid,
2478
+ errors,
2479
+ invalidFiles: []
2480
+ };
2414
2481
  }
2415
- onFileChange() {
2416
- let FilesArray = [];
2417
- if (this.options.isMultipleFile &&
2418
- this.options.minNoOfFiles != null &&
2419
- this.options.minNoOfFiles > 0 &&
2420
- this.options.minNoOfFiles > this.uploader.queue.length) {
2421
- const formControl = this.fileUploadFormControl;
2422
- formControl.setErrors({
2423
- MinFileCountValidationKey: this.options.minNoOfFiles
2424
- });
2425
- formControl.markAsTouched();
2426
- this.uploader.queue = [];
2427
- return;
2482
+ createFileSizeErrorMessage(fileName) {
2483
+ return this.utilityService.getResourceValue('FileExceedsMaxSize')
2484
+ .replace('{fileName}', fileName)
2485
+ .replace('{maxSize}', this.options.fileMaxSizeInMB.toString());
2486
+ }
2487
+ createFileTypeErrorMessage(fileName) {
2488
+ return this.utilityService.getResourceValue('FileTypeNotAccepted')
2489
+ .replace('{fileName}', fileName);
2490
+ }
2491
+ createDuplicateFileErrorMessage(fileName, processedDuplicateNames) {
2492
+ const fileNameLower = fileName.toLowerCase();
2493
+ if (processedDuplicateNames.has(fileNameLower)) {
2494
+ return null;
2495
+ }
2496
+ processedDuplicateNames.add(fileNameLower);
2497
+ let duplicateErrorMsg = this.utilityService.getResourceValue('DuplicateFileName');
2498
+ if (!duplicateErrorMsg || duplicateErrorMsg === 'DuplicateFileName') {
2499
+ duplicateErrorMsg = `File '{fileName}' already exists. Please choose a different file or rename it.`;
2500
+ }
2501
+ return duplicateErrorMsg.replace('{fileName}', fileName);
2502
+ }
2503
+ handleFileValidationResults(result) {
2504
+ if (result.invalidFiles.length > 0) {
2505
+ this.removeInvalidFiles(result.invalidFiles);
2506
+ }
2507
+ if (result.errors.length > 0) {
2508
+ this.showValidationErrors(result.errors);
2509
+ }
2510
+ }
2511
+ processValidFilesForUpload() {
2512
+ const filesArray = [];
2513
+ const validQueue = this.getNewlyAddedFiles();
2514
+ for (const element of validQueue) {
2515
+ const file = element.file;
2516
+ if (!file)
2517
+ continue;
2518
+ if (this.shouldUseAsyncUpload(element)) {
2519
+ this.handleAsyncFileUpload(element, filesArray);
2520
+ }
2521
+ else {
2522
+ this.handleSyncFileUpload(file, filesArray);
2523
+ }
2524
+ }
2525
+ }
2526
+ shouldUseAsyncUpload(element) {
2527
+ return this.options.isUploadFileAsync && !element._file['iD_GUID'];
2528
+ }
2529
+ validateFileConstraints() {
2530
+ if (this.options.isMultipleFile) {
2531
+ if (!this.validateMinFileCount() || !this.validateMaxFileCount() || !this.validateTotalFileSize()) {
2532
+ return false;
2533
+ }
2534
+ }
2535
+ return true;
2536
+ }
2537
+ validateMinFileCount() {
2538
+ if (this.options.minNoOfFiles > 0 && this.options.minNoOfFiles > this.uploader.queue.length) {
2539
+ const minFileMsg = this.utilityService.getResourceValue('MinimumFilesRequired')
2540
+ .replace('{count}', this.options.minNoOfFiles.toString());
2541
+ this.showFileCountError('MinFileCountValidationKey', minFileMsg);
2542
+ return false;
2543
+ }
2544
+ return true;
2545
+ }
2546
+ validateMaxFileCount() {
2547
+ if (this.options.maxNoOfFiles > 0 && this.options.maxNoOfFiles < this.uploader.queue.length) {
2548
+ const maxFileMsg = this.utilityService.getResourceValue('MaximumFilesExceeded') ||
2549
+ `Maximum {maxCount} files allowed. You have selected {currentCount} files.`;
2550
+ const finalMsg = maxFileMsg
2551
+ .replace('{maxCount}', this.options.maxNoOfFiles.toString())
2552
+ .replace('{currentCount}', this.uploader.queue.length.toString());
2553
+ this.showFileCountError('MaxFileCountValidationKey', finalMsg);
2554
+ return false;
2428
2555
  }
2429
- if (this.options.isMultipleFile &&
2430
- this.options.maxNoOfFiles != null &&
2431
- this.options.maxNoOfFiles > 0 &&
2432
- this.options.maxNoOfFiles < this.uploader.queue.length) {
2433
- const formControl = this.fileUploadFormControl;
2434
- formControl.setErrors({
2435
- MaxFileCountValidationKey: this.options.maxNoOfFiles
2556
+ return true;
2557
+ }
2558
+ showFileCountError(errorKey, message) {
2559
+ const currentErrors = this.fileUploadFormControl.errors || {};
2560
+ currentErrors[errorKey] = message;
2561
+ this.fileUploadFormControl.setErrors(currentErrors);
2562
+ this.fileUploadFormControl.markAsTouched();
2563
+ }
2564
+ clearFileCountError(errorKey) {
2565
+ const currentErrors = this.fileUploadFormControl.errors;
2566
+ if (currentErrors && currentErrors[errorKey]) {
2567
+ delete currentErrors[errorKey];
2568
+ if (Object.keys(currentErrors).length === 0) {
2569
+ this.fileUploadFormControl.setErrors(null);
2570
+ }
2571
+ else {
2572
+ this.fileUploadFormControl.setErrors(currentErrors);
2573
+ }
2574
+ }
2575
+ }
2576
+ validateTotalFileSize() {
2577
+ if (this.options.maxSizeForAllFilesInMB > 0) {
2578
+ const totalSize = this.uploader.queue.reduce((sum, element) => sum + element.file.size, 0);
2579
+ const maxSizeBytes = this.options.maxSizeForAllFilesInMB * this.BYTES_TO_MB;
2580
+ if (totalSize > maxSizeBytes) {
2581
+ this.showTotalSizeError();
2582
+ return false;
2583
+ }
2584
+ }
2585
+ return true;
2586
+ }
2587
+ showTotalSizeError() {
2588
+ const totalSizeMsg = this.utilityService.getResourceValue('TotalFileSizeExceeded')
2589
+ .replace('{maxSize}', this.options.maxSizeForAllFilesInMB.toString());
2590
+ const currentErrors = this.fileUploadFormControl.errors || {};
2591
+ currentErrors['MaxSizeForAllFilesInMB'] = totalSizeMsg;
2592
+ this.fileUploadFormControl.setErrors(currentErrors);
2593
+ this.fileUploadFormControl.markAsTouched();
2594
+ }
2595
+ validateFileSize(file) {
2596
+ const maxFileSize = this.options.fileMaxSizeInMB * this.BYTES_TO_MB;
2597
+ if (file.size > maxFileSize) {
2598
+ this.setFormControlError('FileMaxSizeInMB', `${this.options.fileMaxSizeInMB}MB`);
2599
+ return false;
2600
+ }
2601
+ return true;
2602
+ }
2603
+ validateFileType(file) {
2604
+ if (this.options.fileUploadAcceptsTypes?.length) {
2605
+ const fileType = file.type;
2606
+ const isAccepted = this.acceptedTypeArray.some(type => type.toLowerCase() === fileType.toLowerCase());
2607
+ if (!isAccepted) {
2608
+ this.setFormControlError('ToolTipTypeError', this.toolTipTypeArray);
2609
+ return false;
2610
+ }
2611
+ }
2612
+ return true;
2613
+ }
2614
+ validateIndividualFileSize(file) {
2615
+ const maxFileSize = this.options.fileMaxSizeInMB * this.BYTES_TO_MB;
2616
+ return file.size <= maxFileSize;
2617
+ }
2618
+ validateIndividualFileType(file) {
2619
+ if (!this.options.fileUploadAcceptsTypes?.length) {
2620
+ return true;
2621
+ }
2622
+ const fileType = file.type?.toLowerCase();
2623
+ if (!fileType) {
2624
+ return false;
2625
+ }
2626
+ return this.acceptedTypeArray.some(type => type.toLowerCase() === fileType);
2627
+ }
2628
+ validateDuplicateFileName(file, currentElement) {
2629
+ if (!file?.name) {
2630
+ return true;
2631
+ }
2632
+ const currentFileName = file.name.toLowerCase();
2633
+ const existingFiles = this.uploader.queue.filter(item => item !== currentElement);
2634
+ const duplicateExists = existingFiles.some(item => {
2635
+ const existingFileName = item.file?.name || item._file?.name;
2636
+ return existingFileName && existingFileName.toLowerCase() === currentFileName;
2637
+ });
2638
+ if (duplicateExists) {
2639
+ return false;
2640
+ }
2641
+ if (this.options.value) {
2642
+ const uploadedFiles = Array.isArray(this.options.value) ? this.options.value : [this.options.value];
2643
+ const duplicateInUploaded = uploadedFiles.some(uploadedFile => {
2644
+ const uploadedFileName = uploadedFile?.fileName || uploadedFile?.name;
2645
+ return uploadedFileName && uploadedFileName.toLowerCase() === currentFileName;
2436
2646
  });
2437
- formControl.markAsTouched();
2438
- this.uploader.queue = [];
2439
- return;
2647
+ return !duplicateInUploaded;
2440
2648
  }
2441
- if (this.options.isMultipleFile &&
2442
- this.options.maxSizeForAllFilesInMB != null &&
2443
- this.options.maxSizeForAllFilesInMB > 0) {
2444
- let AllSizeFile = 0;
2445
- for (let index = 0; index < this.uploader.queue.length; index++) {
2446
- const element = this.uploader.queue[index];
2447
- const file = element.file;
2448
- AllSizeFile = AllSizeFile + file.size;
2449
- }
2450
- const MaxSizeForAllFiles = this.options.maxSizeForAllFilesInMB * 1000 * 1000;
2451
- if (AllSizeFile > MaxSizeForAllFiles) {
2452
- const formControl = this.fileUploadFormControl;
2453
- formControl.setErrors({
2454
- MaxSizeForAllFilesInMB: this.options.maxSizeForAllFilesInMB + 'MB'
2455
- });
2456
- formControl.markAsTouched();
2457
- this.uploader.queue = [];
2458
- return;
2649
+ return true;
2650
+ }
2651
+ removeInvalidFiles(invalidFiles) {
2652
+ invalidFiles.forEach(invalidFile => {
2653
+ const index = this.uploader.queue.indexOf(invalidFile);
2654
+ if (index > -1) {
2655
+ this.uploader.queue.splice(index, 1);
2656
+ }
2657
+ });
2658
+ }
2659
+ showValidationErrors(errors) {
2660
+ if (errors.length === 0)
2661
+ return;
2662
+ const errorMessage = errors.join('<br/>');
2663
+ this.setValidationError('InvalidFiles', errorMessage);
2664
+ setTimeout(() => {
2665
+ this.clearInvalidFilesError();
2666
+ }, this.ERROR_DISPLAY_DURATION);
2667
+ }
2668
+ setValidationError(errorKey, errorMessage) {
2669
+ const currentErrors = this.fileUploadFormControl.errors || {};
2670
+ currentErrors[errorKey] = errorMessage;
2671
+ this.fileUploadFormControl.setErrors(currentErrors);
2672
+ this.fileUploadFormControl.markAsTouched();
2673
+ }
2674
+ clearInvalidFilesError() {
2675
+ const currentErrors = this.fileUploadFormControl.errors;
2676
+ if (currentErrors && currentErrors['InvalidFiles']) {
2677
+ delete currentErrors['InvalidFiles'];
2678
+ if (Object.keys(currentErrors).length === 0) {
2679
+ this.fileUploadFormControl.setErrors(null);
2680
+ }
2681
+ else {
2682
+ this.fileUploadFormControl.setErrors(currentErrors);
2459
2683
  }
2460
2684
  }
2461
- let AddedQueue = this.uploader.queue.filter((obj) => obj['some'].lastModified != null);
2462
- for (let index = 0; index < AddedQueue.length; index++) {
2463
- const element = AddedQueue[index];
2464
- const file = element.file;
2465
- const maxFileSize = this.options.fileMaxSizeInMB * 1000 * 1000;
2466
- if (file) {
2467
- const fileType = file.type;
2468
- if (file.size > maxFileSize) {
2469
- const formControl = this.fileUploadFormControl;
2470
- formControl.setErrors({
2471
- FileMaxSizeInMB: this.options.fileMaxSizeInMB + 'M'
2472
- });
2473
- formControl.markAsTouched();
2474
- this.uploader.queue = [];
2475
- return;
2476
- }
2477
- if (this.options.fileUploadAcceptsTypes != null &&
2478
- this.options.fileUploadAcceptsTypes.length > 0 &&
2479
- !(this.acceptedTypeArray.includes(fileType.toUpperCase()) ||
2480
- this.acceptedTypeArray.includes(fileType.toLowerCase()))) {
2481
- const formControl = this.fileUploadFormControl;
2482
- formControl.setErrors({ ToolTipTypeError: this.toolTipTypeArray });
2483
- formControl.markAsTouched();
2484
- this.uploader.queue = [];
2485
- return;
2486
- }
2487
- if (this.options.isUploadFileAsync && !element._file['iD_GUID']) {
2488
- this.fileUploadService.uploadFile(element._file).subscribe({
2489
- next: (event) => {
2490
- let queueIndex = this.uploader.queue.findIndex((file) => file == element);
2491
- if (event.type === HttpEventType.UploadProgress) {
2492
- let value = Math.round((100 * event.loaded) / event.total);
2493
- this.uploader.queue[queueIndex].progress = value >= 95 ? 95 : value;
2494
- }
2495
- else if (event.type === HttpEventType.Response) {
2496
- this.uploader.queue[queueIndex].progress = 100;
2497
- let fileID = event.body.val;
2498
- this.uploader.queue[queueIndex]._file['iD_GUID'] = fileID;
2499
- this.uploader.queue[queueIndex]._file['isNew'] = true;
2500
- let AddedFile = {
2501
- iD_GUID: fileID,
2502
- fileName: this.uploader.queue[queueIndex]._file['name'],
2503
- fileType: this.uploader.queue[queueIndex]._file['type'],
2504
- isNew: true
2505
- };
2506
- if (this.options.isMultipleFile == false) {
2507
- this.fileUploadModel = new FileUploadModel();
2508
- this.fileUploadModel.file = AddedFile;
2509
- this.fileUploadFormControl.setValue(this.fileUploadModel);
2510
- this.group.get(this.options.name).setValue(this.fileUploadModel);
2511
- //Use this line to enable two way binding.
2512
- this.options.value = this.fileUploadModel;
2513
- }
2514
- else {
2515
- FilesArray.push(AddedFile);
2516
- this.multipleFileUploadModel.uploadedFiles = FilesArray;
2517
- if (this.options.value != null && this.options.value != undefined) {
2518
- if (this.options.value.correlationID_GUID == null) {
2519
- this.multipleFileUploadModel.removedFiles = [];
2520
- }
2521
- }
2522
- this.multipleFileUploadModel.correlationID_GUID =
2523
- this.options.value?.correlationID_GUID;
2524
- this.fileUploadFormControl.setValue(this.multipleFileUploadModel);
2525
- this.group.get(this.options.name).setValue(this.multipleFileUploadModel);
2526
- //Use this line to enable two way binding.
2527
- this.options.value = this.multipleFileUploadModel;
2528
- this.isUploadComplete.emit(true);
2529
- }
2530
- }
2531
- }
2532
- });
2685
+ }
2686
+ setFormControlError(errorKey, errorValue) {
2687
+ this.fileUploadFormControl.setErrors({ [errorKey]: errorValue });
2688
+ this.fileUploadFormControl.markAsTouched();
2689
+ this.uploader.queue = [];
2690
+ }
2691
+ handleAsyncFileUpload(element, filesArray) {
2692
+ const uploadSubscription = this.fileUploadService.uploadFile(element._file).subscribe({
2693
+ next: (event) => {
2694
+ if (event.type === HttpEventType.UploadProgress) {
2695
+ this.handleUploadProgress(element, event);
2533
2696
  }
2534
- else {
2535
- let reader = new FileReader();
2536
- let fileObject = file.rawFile;
2537
- reader.readAsDataURL(fileObject);
2538
- reader.onload = () => {
2539
- let existingID_GUID = null;
2540
- if (!this.options.isMultipleFile && this.file)
2541
- existingID_GUID = this.file.NameWithExtension == file.name ? this.file.iD_GUID : null;
2542
- let AddedFile = {
2543
- fileName: file.name,
2544
- fileType: file.type,
2545
- fileBase64: reader.result.toString().split(',')[1],
2546
- fileSizeInMB: file.size / 1000 / 1000,
2547
- nameWithExtension: file.name,
2548
- iD_GUID: existingID_GUID,
2549
- isNew: true
2550
- };
2551
- if (this.options.isMultipleFile == false) {
2552
- this.fileUploadModel = new FileUploadModel();
2553
- this.fileUploadModel.file = AddedFile;
2554
- this.fileUploadFormControl.setValue(this.fileUploadModel);
2555
- this.group.get(this.options.name).setValue(this.fileUploadModel);
2556
- //Use this line to enable two way binding.
2557
- this.options.value = this.fileUploadModel;
2558
- }
2559
- else {
2560
- FilesArray.push(AddedFile);
2561
- this.multipleFileUploadModel.uploadedFiles = FilesArray;
2562
- if (this.options.value != null && this.options.value != undefined) {
2563
- if (this.options.value.correlationID_GUID == null) {
2564
- this.multipleFileUploadModel.removedFiles = [];
2565
- }
2566
- }
2567
- this.multipleFileUploadModel.correlationID_GUID =
2568
- this.options.value?.correlationID_GUID;
2569
- this.fileUploadFormControl.setValue(this.multipleFileUploadModel);
2570
- this.group.get(this.options.name).setValue(this.multipleFileUploadModel);
2571
- //Use this line to enable two way binding.
2572
- this.options.value = this.multipleFileUploadModel;
2573
- }
2574
- };
2575
- let originalValue = this.group.get(this.options.name).value;
2576
- if (this.options.patchFunction &&
2577
- this.options.patchPath &&
2578
- this.group.get(this.options.name).valid) {
2579
- this.controlUtility.patchControlValue(originalValue, this.options.patchFunction, this.options.patchPath);
2580
- }
2581
- this.OnChange.emit(originalValue);
2697
+ else if (event.type === HttpEventType.Response) {
2698
+ this.handleUploadComplete(element, event, filesArray);
2582
2699
  }
2700
+ },
2701
+ error: (error) => {
2702
+ console.error('Upload failed:', error);
2703
+ // Handle upload error - you can add custom error handling here
2704
+ }
2705
+ });
2706
+ // Store subscription for cleanup
2707
+ this.subscriptions.add(uploadSubscription);
2708
+ }
2709
+ handleUploadProgress(element, event) {
2710
+ const queueIndex = this.uploader.queue.findIndex((file) => file === element);
2711
+ if (queueIndex === -1)
2712
+ return;
2713
+ const progress = Math.round((100 * event.loaded) / event.total);
2714
+ this.uploader.queue[queueIndex].progress =
2715
+ progress >= this.PROGRESS_NEAR_COMPLETE ? this.PROGRESS_NEAR_COMPLETE : progress;
2716
+ }
2717
+ handleUploadComplete(element, event, filesArray) {
2718
+ const queueIndex = this.uploader.queue.findIndex((file) => file === element);
2719
+ if (queueIndex === -1)
2720
+ return;
2721
+ this.uploader.queue[queueIndex].progress = this.PROGRESS_COMPLETE;
2722
+ const fileID = event.body.val;
2723
+ this.updateElementWithFileInfo(element, fileID, event.body.downloadUrl);
2724
+ const addedFile = this.createFileDTO(element, fileID, event.body.downloadUrl);
2725
+ this.updateFormValue(addedFile, filesArray);
2726
+ }
2727
+ updateElementWithFileInfo(element, fileID, downloadUrl) {
2728
+ element._file['iD_GUID'] = fileID;
2729
+ element._file['isNew'] = true;
2730
+ if (downloadUrl) {
2731
+ element._file['url'] = downloadUrl;
2732
+ element.file.url = downloadUrl;
2733
+ }
2734
+ }
2735
+ createFileDTO(element, fileID, downloadUrl) {
2736
+ return {
2737
+ iD_GUID: fileID,
2738
+ fileName: element._file['name'],
2739
+ fileType: element._file['type'],
2740
+ isNew: true,
2741
+ fileBase64: '',
2742
+ fileSizeInMB: element._file.size / this.BYTES_TO_MB,
2743
+ nameWithExtension: element._file['name'],
2744
+ fullFileURL: downloadUrl || null
2745
+ };
2746
+ }
2747
+ handleSyncFileUpload(file, filesArray) {
2748
+ this.trackMemoryUsage(file.size);
2749
+ const reader = new FileReader();
2750
+ // Store reader reference for cleanup
2751
+ const readerRef = reader;
2752
+ reader.onload = () => {
2753
+ try {
2754
+ const existingGUID = this.getExistingFileGUID(file);
2755
+ this.updateQueueItemForSync(file);
2756
+ const addedFile = this.createSyncFileDTO(file, reader.result, existingGUID);
2757
+ this.updateFormValue(addedFile, filesArray);
2758
+ this.handlePatchAndEmit();
2759
+ }
2760
+ finally {
2761
+ // Clean up reader
2762
+ readerRef.onload = null;
2763
+ readerRef.onerror = null;
2764
+ readerRef.onabort = null;
2583
2765
  }
2766
+ };
2767
+ reader.onerror = () => {
2768
+ console.error('File reading failed');
2769
+ readerRef.onload = null;
2770
+ readerRef.onerror = null;
2771
+ readerRef.onabort = null;
2772
+ };
2773
+ reader.readAsDataURL(file.rawFile);
2774
+ }
2775
+ updateQueueItemForSync(file) {
2776
+ const queueItem = this.findQueueItemByFile(file);
2777
+ if (queueItem) {
2778
+ this.preserveFileReference(queueItem, file);
2779
+ queueItem.progress = this.PROGRESS_COMPLETE;
2584
2780
  }
2585
2781
  }
2782
+ findQueueItemByFile(file) {
2783
+ return this.uploader.queue.find(item => item.file.name === file.name && item.file.size === file.size);
2784
+ }
2785
+ preserveFileReference(queueItem, file) {
2786
+ queueItem._file.rawFile = file.rawFile;
2787
+ queueItem.file.rawFile = file.rawFile;
2788
+ }
2789
+ createSyncFileDTO(file, readerResult, existingGUID) {
2790
+ return {
2791
+ fileName: file.name,
2792
+ fileType: file.type,
2793
+ fileBase64: readerResult.split(',')[1],
2794
+ fileSizeInMB: file.size / this.BYTES_TO_MB,
2795
+ nameWithExtension: file.name,
2796
+ iD_GUID: existingGUID,
2797
+ isNew: true,
2798
+ fullFileURL: null
2799
+ };
2800
+ }
2801
+ getExistingFileGUID(file) {
2802
+ if (!this.options.isMultipleFile && this.file) {
2803
+ return this.file.nameWithExtension === file.name ? this.file.iD_GUID : null;
2804
+ }
2805
+ return null;
2806
+ }
2807
+ updateFormValue(addedFile, filesArray) {
2808
+ if (!this.options.isMultipleFile) {
2809
+ this.fileUploadModel = new FileUploadModel();
2810
+ this.fileUploadModel.file = addedFile;
2811
+ this.updateFormControl(this.fileUploadModel);
2812
+ }
2813
+ else {
2814
+ filesArray.push(addedFile);
2815
+ this.multipleFileUploadModel.uploadedFiles = filesArray;
2816
+ this.setupMultipleFileModel();
2817
+ this.updateFormControl(this.multipleFileUploadModel);
2818
+ this.isUploadComplete.emit(true);
2819
+ }
2820
+ }
2821
+ setupMultipleFileModel() {
2822
+ if (this.options.value?.correlationID_GUID == null) {
2823
+ this.multipleFileUploadModel.removedFiles = [];
2824
+ }
2825
+ this.multipleFileUploadModel.correlationID_GUID = this.options.value?.correlationID_GUID;
2826
+ }
2827
+ updateFormControl(value) {
2828
+ this.preserveErrorsAndUpdateValue(value);
2829
+ this.options.value = value;
2830
+ }
2831
+ preserveErrorsAndUpdateValue(value) {
2832
+ const currentErrors = this.fileUploadFormControl.errors;
2833
+ this.fileUploadFormControl.setValue(value, { emitEvent: false });
2834
+ this.group.get(this.options.name)?.setValue(value, { emitEvent: false });
2835
+ if (currentErrors) {
2836
+ this.fileUploadFormControl.setErrors(currentErrors);
2837
+ }
2838
+ }
2839
+ handlePatchAndEmit() {
2840
+ const originalValue = this.group.get(this.options.name)?.value;
2841
+ if (this.options.patchFunction && this.options.patchPath && this.group.get(this.options.name)?.valid) {
2842
+ this.controlUtility.patchControlValue(originalValue, this.options.patchFunction, this.options.patchPath);
2843
+ }
2844
+ this.OnChange.emit(originalValue);
2845
+ }
2586
2846
  removeFromControlValue(item) {
2587
- if (this.options.isUploadFileAsync && item.progress == 100 && item._file['isNew']) {
2588
- this.fileUploadService.deleteFile(item._file['iD_GUID']).subscribe((res) => { });
2847
+ // Clean up blob URL before removing
2848
+ const downloadUrl = this.getFileDownloadUrl(item);
2849
+ if (downloadUrl && downloadUrl.startsWith('blob:')) {
2850
+ this.cleanupBlobUrl(downloadUrl);
2589
2851
  }
2590
- if (this.options.isMultipleFile == false) {
2591
- this.fileUploadModel = null;
2592
- if (this.options.isRequired == true) {
2593
- this.fileUploadFormControl.markAsTouched();
2594
- this.fileUploadFormControl.invalid;
2595
- }
2596
- this.group.get(this.options.name).setValue(this.fileUploadModel);
2597
- this.options.value = this.fileUploadModel;
2852
+ this.handleAsyncFileDeletion(item);
2853
+ if (!this.options.isMultipleFile) {
2854
+ this.handleSingleFileRemoval();
2598
2855
  }
2599
2856
  else {
2600
- if (this.options.value != null && this.options.value != undefined) {
2601
- if (this.options.value.correlationID_GUID == null) {
2602
- this.deletedFiles = [];
2603
- this.multipleFileUploadModel.removedFiles = [];
2604
- }
2605
- else {
2606
- if (this.multipleFileUploadModel.removedFiles.length == 0) {
2607
- let FileObject = item.file.rawFile;
2608
- let DeletedItem = this.multipleFileUploadModel.existingFiles.filter((obj) => obj.nameWithExtension == FileObject.name)[0];
2609
- this.multipleFileUploadModel.existingFiles =
2610
- this.multipleFileUploadModel.existingFiles.filter((obj) => obj.nameWithExtension != FileObject.name);
2611
- this.deletedFiles.push(DeletedItem);
2612
- this.multipleFileUploadModel.removedFiles.push(DeletedItem.iD_GUID);
2613
- }
2614
- else {
2615
- let FileObject = item.file.rawFile;
2616
- let deletedList = this.deletedFiles.filter((obj) => obj.nameWithExtension == FileObject.name);
2617
- if (deletedList.length == 0 || deletedList == undefined) {
2618
- let DeletedItem = this.multipleFileUploadModel.existingFiles.filter((obj) => obj.nameWithExtension == FileObject.name)[0];
2619
- this.multipleFileUploadModel.existingFiles =
2620
- this.multipleFileUploadModel.existingFiles.filter((obj) => obj.nameWithExtension != FileObject.name);
2621
- this.deletedFiles.push(DeletedItem);
2622
- this.multipleFileUploadModel.removedFiles.push(DeletedItem.iD_GUID);
2623
- }
2624
- }
2857
+ this.handleMultipleFileRemoval(item);
2858
+ }
2859
+ this.checkAndClearMaxFileCountValidation();
2860
+ }
2861
+ handleAsyncFileDeletion(item) {
2862
+ if (this.options.isUploadFileAsync &&
2863
+ item.progress === this.PROGRESS_COMPLETE &&
2864
+ item._file['isNew']) {
2865
+ const deleteSubscription = this.fileUploadService.deleteFile(item._file['iD_GUID']).subscribe({
2866
+ error: (error) => console.error('Delete failed:', error)
2867
+ });
2868
+ this.subscriptions.add(deleteSubscription);
2869
+ }
2870
+ }
2871
+ handleSingleFileRemoval() {
2872
+ this.uploader.queue = [];
2873
+ this.fileUploadModel = null;
2874
+ if (this.options.isRequired) {
2875
+ this.fileUploadFormControl.markAsTouched();
2876
+ }
2877
+ const currentErrors = this.fileUploadFormControl.errors;
2878
+ this.group.get(this.options.name)?.setValue(this.fileUploadModel, { emitEvent: false });
2879
+ if (currentErrors) {
2880
+ this.fileUploadFormControl.setErrors(currentErrors);
2881
+ }
2882
+ this.options.value = this.fileUploadModel;
2883
+ }
2884
+ handleMultipleFileRemoval(item) {
2885
+ // Clean up blob URL
2886
+ const downloadUrl = this.getFileDownloadUrl(item);
2887
+ if (downloadUrl && downloadUrl.startsWith('blob:')) {
2888
+ this.cleanupBlobUrl(downloadUrl);
2889
+ }
2890
+ const queueIndex = this.uploader.queue.indexOf(item);
2891
+ if (queueIndex > -1) {
2892
+ this.uploader.queue.splice(queueIndex, 1);
2893
+ }
2894
+ this.processFileRemovalFromExisting(item);
2895
+ this.removeFromUploadedFiles(item);
2896
+ this.validateRemainingFiles();
2897
+ this.updateMultipleFileModel();
2898
+ }
2899
+ processFileRemovalFromExisting(item) {
2900
+ if (!this.options.value) {
2901
+ this.resetDeletedFiles();
2902
+ return;
2903
+ }
2904
+ if (!this.options.value.correlationID_GUID) {
2905
+ this.resetDeletedFiles();
2906
+ }
2907
+ else {
2908
+ this.handleExistingFileRemoval(item);
2909
+ }
2910
+ }
2911
+ resetDeletedFiles() {
2912
+ this.deletedFiles = [];
2913
+ this.multipleFileUploadModel.removedFiles = [];
2914
+ }
2915
+ handleExistingFileRemoval(item) {
2916
+ const fileName = item.file.rawFile.name;
2917
+ const existingFile = this.multipleFileUploadModel.existingFiles
2918
+ .find(obj => obj.nameWithExtension === fileName);
2919
+ if (existingFile && !this.deletedFiles.some(obj => obj.nameWithExtension === fileName)) {
2920
+ this.multipleFileUploadModel.existingFiles =
2921
+ this.multipleFileUploadModel.existingFiles.filter(obj => obj.nameWithExtension !== fileName);
2922
+ this.deletedFiles.push(existingFile);
2923
+ this.multipleFileUploadModel.removedFiles.push(existingFile.iD_GUID);
2924
+ }
2925
+ }
2926
+ removeFromUploadedFiles(item) {
2927
+ const itemFileName = item._file.name || item.file.name;
2928
+ const itemFileSize = item._file.size || item.file.size;
2929
+ const itemGUID = item._file['iD_GUID'];
2930
+ this.multipleFileUploadModel.uploadedFiles =
2931
+ this.multipleFileUploadModel.uploadedFiles.filter(obj => {
2932
+ if (itemGUID && obj.iD_GUID) {
2933
+ return obj.iD_GUID !== itemGUID;
2625
2934
  }
2626
- }
2627
- else {
2628
- this.deletedFiles = [];
2629
- this.multipleFileUploadModel.removedFiles = [];
2630
- }
2631
- this.multipleFileUploadModel.uploadedFiles =
2632
- this.multipleFileUploadModel.uploadedFiles.filter((obj) => (obj.nameWithExtension && obj.nameWithExtension != item._file.name) ||
2633
- obj.iD_GUID != item._file['iD_GUID']);
2634
- if ((this.multipleFileUploadModel.uploadedFiles == null ||
2635
- this.multipleFileUploadModel.uploadedFiles.length == 0) &&
2636
- this.options.isRequired) {
2637
- const formControl = this.fileUploadFormControl;
2638
- formControl.setErrors({
2639
- MinFileCountValidationKey: this.options.minNoOfFiles
2640
- });
2641
- this.fileUploadFormControl.markAsTouched();
2642
- this.fileUploadFormControl.invalid;
2643
- }
2644
- this.multipleFileUploadModel.correlationID_GUID = this.options.value?.correlationID_GUID;
2645
- this.fileUploadFormControl.setValue(this.multipleFileUploadModel);
2646
- this.group.get(this.options.name).setValue(this.multipleFileUploadModel);
2647
- //Use this line to enable two way binding.
2648
- this.options.value = this.multipleFileUploadModel;
2935
+ const objFileName = obj.nameWithExtension || obj.fileName;
2936
+ const objFileSize = obj.fileSizeInMB ? obj.fileSizeInMB * this.BYTES_TO_MB : 0;
2937
+ return !(objFileName === itemFileName && Math.abs(objFileSize - itemFileSize) < 1000);
2938
+ });
2939
+ }
2940
+ validateRemainingFiles() {
2941
+ if ((!this.multipleFileUploadModel.uploadedFiles ||
2942
+ this.multipleFileUploadModel.uploadedFiles.length === 0) &&
2943
+ this.options.isRequired) {
2944
+ this.fileUploadFormControl.setErrors({
2945
+ MinFileCountValidationKey: this.options.minNoOfFiles
2946
+ });
2947
+ this.fileUploadFormControl.markAsTouched();
2948
+ }
2949
+ }
2950
+ updateMultipleFileModel() {
2951
+ this.multipleFileUploadModel.correlationID_GUID = this.options.value?.correlationID_GUID;
2952
+ const currentErrors = this.fileUploadFormControl.errors;
2953
+ this.fileUploadFormControl.setValue(this.multipleFileUploadModel, { emitEvent: false });
2954
+ this.group.get(this.options.name)?.setValue(this.multipleFileUploadModel, { emitEvent: false });
2955
+ this.options.value = this.multipleFileUploadModel;
2956
+ if (currentErrors) {
2957
+ this.fileUploadFormControl.setErrors(currentErrors);
2649
2958
  }
2650
2959
  }
2651
2960
  convertSizeToMB(size) {
2652
2961
  if (size === 0) {
2653
2962
  return 0;
2654
2963
  }
2655
- // Convert size to megabytes
2656
- const megabytes = size / (1024 * 1024);
2657
- // Round to two decimal places
2658
- const roundedMegabytes = Math.round(megabytes * 100) / 100;
2659
- return roundedMegabytes;
2964
+ const BYTES_TO_MB_ACCURATE = 1024 * 1024;
2965
+ const megabytes = size / BYTES_TO_MB_ACCURATE;
2966
+ return Math.round(megabytes * 100) / 100;
2967
+ }
2968
+ trackByFunction(index, item) {
2969
+ return item._file ? item._file.name + item._file.size : index;
2970
+ }
2971
+ shouldShowFileList() {
2972
+ return this.uploader?.queue && this.uploader.queue.length > 0;
2973
+ }
2974
+ isDownloadEnabled() {
2975
+ return true;
2976
+ }
2977
+ isRemoveEnabled() {
2978
+ return !this.options.isReadonly && !this.options.isDisabled;
2979
+ }
2980
+ getFileDownloadUrl(item) {
2981
+ const existingUrl = this.getExistingFileUrl(item);
2982
+ if (existingUrl) {
2983
+ return existingUrl;
2984
+ }
2985
+ return this.createFileUrl(item);
2986
+ }
2987
+ getExistingFileUrl(item) {
2988
+ return item?.file?.url ||
2989
+ item?._file?.url ||
2990
+ item?.url ||
2991
+ item?.file?.rawFile?.url ||
2992
+ item?._file?.rawFile?.url ||
2993
+ null;
2994
+ }
2995
+ createFileUrl(item) {
2996
+ const fileName = this.getFileName(item);
2997
+ const fileType = item?.file?.type || item?._file?.type;
2998
+ const originalFile = item?._file?.rawFile || item?.file?.rawFile;
2999
+ if (originalFile && originalFile instanceof File) {
3000
+ return URL.createObjectURL(originalFile);
3001
+ }
3002
+ const base64Data = typeof originalFile === 'string' ? originalFile : null;
3003
+ if (base64Data && fileName) {
3004
+ return this.createBlobUrlWithFilename(base64Data, fileType, fileName);
3005
+ }
3006
+ const fileId = item?._file?.['iD_GUID'];
3007
+ if (fileId && this.options.isUploadFileAsync) {
3008
+ return this.constructDownloadUrl(fileId, fileName);
3009
+ }
3010
+ return null;
3011
+ }
3012
+ createBlobUrlWithFilename(base64Data, fileType, fileName) {
3013
+ try {
3014
+ const byteCharacters = atob(base64Data);
3015
+ const byteNumbers = new Array(byteCharacters.length);
3016
+ for (let i = 0; i < byteCharacters.length; i++) {
3017
+ byteNumbers[i] = byteCharacters.charCodeAt(i);
3018
+ }
3019
+ const byteArray = new Uint8Array(byteNumbers);
3020
+ const blob = new Blob([byteArray], { type: fileType || 'application/octet-stream' });
3021
+ return URL.createObjectURL(blob);
3022
+ }
3023
+ catch (error) {
3024
+ const errorMsg = this.utilityService.getResourceValue('ErrorCreatingBlobUrl');
3025
+ console.error(errorMsg, error);
3026
+ return `data:${fileType || 'application/octet-stream'};base64,${base64Data}`;
3027
+ }
3028
+ }
3029
+ constructDownloadUrl(fileId, fileName) {
3030
+ const downloadBaseUrl = this.options.downloadBaseUrl;
3031
+ let url;
3032
+ if (downloadBaseUrl) {
3033
+ url = `${downloadBaseUrl}/${fileId}`;
3034
+ }
3035
+ else {
3036
+ url = `/api/files/download/${fileId}`;
3037
+ }
3038
+ if (fileName) {
3039
+ const separator = url.includes('?') ? '&' : '?';
3040
+ url += `${separator}filename=${encodeURIComponent(fileName)}`;
3041
+ }
3042
+ return url;
3043
+ }
3044
+ getFileName(item) {
3045
+ return item?.file?.name || item?._file?.name || 'file';
3046
+ }
3047
+ downloadFile(item) {
3048
+ const downloadInfo = this.prepareFileDownload(item);
3049
+ if (!downloadInfo.url) {
3050
+ this.handleDownloadError(downloadInfo.fileName);
3051
+ return;
3052
+ }
3053
+ this.executeFileDownload(downloadInfo.url, downloadInfo.fileName);
3054
+ }
3055
+ prepareFileDownload(item) {
3056
+ return {
3057
+ url: this.getFileDownloadUrl(item),
3058
+ fileName: this.getFileName(item)
3059
+ };
3060
+ }
3061
+ handleDownloadError(fileName) {
3062
+ const errorMsg = this.utilityService.getResourceValue('NoDownloadUrlAvailable')
3063
+ .replace('{fileName}', fileName);
3064
+ console.error(errorMsg);
3065
+ }
3066
+ executeFileDownload(url, fileName) {
3067
+ const link = this.createDownloadLink(url, fileName);
3068
+ this.triggerDownload(link);
3069
+ this.cleanupBlobUrl(url);
3070
+ }
3071
+ createDownloadLink(url, fileName) {
3072
+ const link = document.createElement('a');
3073
+ link.href = url;
3074
+ link.download = fileName;
3075
+ link.style.display = 'none';
3076
+ return link;
3077
+ }
3078
+ triggerDownload(link) {
3079
+ document.body.appendChild(link);
3080
+ link.click();
3081
+ document.body.removeChild(link);
3082
+ }
3083
+ cleanupBlobUrl(url) {
3084
+ if (url.startsWith('blob:')) {
3085
+ setTimeout(() => {
3086
+ URL.revokeObjectURL(url);
3087
+ }, 100);
3088
+ }
3089
+ }
3090
+ trackMemoryUsage(fileSize) {
3091
+ this.currentMemoryUsage += fileSize;
3092
+ // If memory usage exceeds limit, clean up old files
3093
+ if (this.currentMemoryUsage > this.MAX_MEMORY_USAGE) {
3094
+ this.cleanupOldFiles();
3095
+ }
3096
+ }
3097
+ cleanupOldFiles() {
3098
+ if (this.uploader?.queue && this.uploader.queue.length > 0) {
3099
+ // Remove oldest files to free memory
3100
+ const oldestFile = this.uploader.queue.shift();
3101
+ if (oldestFile) {
3102
+ const url = this.getFileDownloadUrl(oldestFile);
3103
+ if (url && url.startsWith('blob:')) {
3104
+ this.cleanupBlobUrl(url);
3105
+ }
3106
+ this.currentMemoryUsage -= (oldestFile.file?.size || 0);
3107
+ }
3108
+ }
3109
+ }
3110
+ cleanupEventListeners() {
3111
+ // Clear file input references
3112
+ if (this.fileInput?.nativeElement) {
3113
+ this.fileInput.nativeElement.value = '';
3114
+ }
3115
+ // Clear uploader queue to prevent memory leaks
3116
+ if (this.uploader?.queue) {
3117
+ this.uploader.queue = [];
3118
+ }
3119
+ }
3120
+ cleanupUploaderQueue() {
3121
+ if (this.uploader?.queue) {
3122
+ // Clear all items and their associated resources
3123
+ this.uploader.queue.forEach(item => {
3124
+ // Clean up blob URLs
3125
+ const url = this.getFileDownloadUrl(item);
3126
+ if (url && url.startsWith('blob:')) {
3127
+ this.cleanupBlobUrl(url);
3128
+ }
3129
+ // Clear file references
3130
+ if (item._file) {
3131
+ item._file = null;
3132
+ }
3133
+ if (item.file) {
3134
+ item.file = null;
3135
+ }
3136
+ });
3137
+ // Clear the queue
3138
+ this.uploader.queue = [];
3139
+ }
3140
+ }
3141
+ ngOnDestroy() {
3142
+ // Clean up subscriptions
3143
+ this.subscriptions.unsubscribe();
3144
+ // Clean up uploader queue
3145
+ this.cleanupUploaderQueue();
3146
+ // Clean up event listeners
3147
+ this.cleanupEventListeners();
3148
+ // Clean up blob URLs
3149
+ if (this.uploader?.queue) {
3150
+ this.uploader.queue.forEach(item => {
3151
+ const url = this.getFileDownloadUrl(item);
3152
+ if (url && url.startsWith('blob:')) {
3153
+ URL.revokeObjectURL(url);
3154
+ }
3155
+ });
3156
+ }
3157
+ }
3158
+ checkAndClearMaxFileCountValidation() {
3159
+ if (!this.options.maxNoOfFiles || this.options.maxNoOfFiles <= 0) {
3160
+ return;
3161
+ }
3162
+ const currentQueueLength = this.uploader.queue.length;
3163
+ if (currentQueueLength <= this.options.maxNoOfFiles) {
3164
+ this.clearFileCountError('MaxFileCountValidationKey');
3165
+ }
2660
3166
  }
2661
3167
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: FileUploadComponent, deps: [{ token: i2.ControlContainer, optional: true }, { token: i2.FormGroupDirective }, { token: ControlUtility }, { token: i3.UtilityService }, { token: i3.ControlValidationService }, { token: GlobalSettings }, { token: FileUploadService }], target: i0.ɵɵFactoryTarget.Component }); }
2662
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.3.12", type: FileUploadComponent, selector: "BBSF-FileUplaod", inputs: { group: "group", options: "options" }, outputs: { OnChange: "OnChange", isUploadComplete: "isUploadComplete" }, viewQueries: [{ propertyName: "fileInput", first: true, predicate: ["fileInput"], descendants: true }], ngImport: i0, template: "<div class=\"form-group bbsf-control bbsf-file-upload\" [formGroup]=\"group\">\r\n <div [ngClass]=\"options.viewType == 1 ? 'bbsf-vertical' : 'bbsf-horizontal'\">\r\n <!--label-->\r\n <label [hidden]=\"options.hideLabel\" class=\"bbsf-label {{ options.labelExtraClasses }}\">\r\n {{ options.labelValue }}\r\n <!--Asterisk-->\r\n <span *ngIf=\"((options.showAsterisk && options.isRequired) || options.isRequired) && !options.isReadonly\" class=\"text-danger\">*</span>\r\n </label>\r\n <!--Allow dropZone-->\r\n <div\r\n ng2FileDrop\r\n class=\"bbsf-input-container {{ options.extraClasses }}\"\r\n *ngIf=\"options.isDropZone && !(options.isMultipleFile == false && uploader.queue.length > 0) && !options.isReadonly\"\r\n [ngClass]=\"{ 'another-file-over-class': hasAnotherDropZoneOver }\"\r\n (onFileDrop)=\"onFileChange()\"\r\n (fileOver)=\"fileOverAnother($event)\"\r\n [uploader]=\"uploader\"\r\n [accept]=\"acceptedType\"\r\n id=\"{{ options.name }}\"\r\n multiple=\"{{ options.isMultipleFile ? 'multiple' : '' }}\"\r\n aria-describedby=\"email-error\"\r\n aria-invalid=\"true\"\r\n type=\"file\"\r\n #fileInput\r\n [class.is-invalid]=\"fileUploadFormControl.invalid && fileUploadFormControl.touched\"\r\n (click)=\"fileInputControl.click()\">\r\n <div class=\"dropzone-label\">\r\n <div class=\"svg-and-validation\">\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"70\" height=\"70\" viewBox=\"0 0 70 70\" fill=\"none\">\r\n <path\r\n opacity=\"0.4\"\r\n d=\"M58.333 48.8332C61.8957 45.8908 64.1663 41.4397 64.1663 36.4583C64.1663 27.5988 56.9843 20.4167 48.1247 20.4167C47.4874 20.4167 46.8912 20.0842 46.5675 19.5351C42.7641 13.0808 35.7417 8.75 27.708 8.75C15.6268 8.75 5.83301 18.5438 5.83301 30.625C5.83301 36.6511 8.26974 42.1082 12.2116 46.0644\"\r\n stroke=\"#4B5489\"\r\n stroke-width=\"2\"\r\n stroke-linecap=\"round\"\r\n stroke-linejoin=\"round\" />\r\n <path\r\n d=\"M23.333 46.6667L34.9997 35M34.9997 35L46.6663 46.6667M34.9997 35V61.25\"\r\n stroke=\"#4B5489\"\r\n stroke-width=\"2\"\r\n stroke-linecap=\"round\"\r\n stroke-linejoin=\"round\" />\r\n </svg>\r\n <!--Validation text-->\r\n <div class=\"bbsf-validation-msg validation-msg-header text-center\">\r\n {{ UtilityService.getResourceValue('DragAndDropHere') }}\r\n </div>\r\n <div class=\"bbsf-validation-msg text-center\" *ngIf=\"validationMessage\" [innerHTML]=\"validationMessage\"></div>\r\n <div\r\n class=\"bbsf-validation-msg ng-star-inserted text-center text-danger\"\r\n *ngIf=\"validationCountMessage && options.isMultipleFile && options.maxNoOfFiles > 0\"\r\n [innerHTML]=\"validationCountMessage\"></div>\r\n </div>\r\n </div>\r\n <input\r\n ng2FileSelect\r\n [uploader]=\"uploader\"\r\n [accept]=\"acceptedType\"\r\n class=\"fileSelector customFileUploadPlacment hidden v-required-multiplefiles d-none\"\r\n multiple=\"{{ options.isMultipleFile ? 'multiple' : '' }}\"\r\n name=\"file\"\r\n type=\"file\"\r\n value=\"\"\r\n autocomplete=\"off\"\r\n (change)=\"onFileChange()\"\r\n [ngClass]=\"options.viewType == 1 ? '' : 'col-md-9'\"\r\n id=\"{{ options.name }}\"\r\n aria-describedby=\"email-error\"\r\n aria-invalid=\"true\"\r\n formControlName=\"{{ options.name }}\"\r\n #fileInputControl\r\n [class.is-invalid]=\"fileUploadFormControl.invalid && fileUploadFormControl.touched\" />\r\n </div>\r\n <!--Not allowed dropZone-->\r\n <div class=\"bbsf-input-container\" *ngIf=\"!options.isDropZone && !isHideInput() && !options.isReadonly\" (click)=\"fileInput.click()\">\r\n <div class=\"dropzone-label\">\r\n <div class=\"svg-and-validation\">\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"70\" height=\"70\" viewBox=\"0 0 70 70\" fill=\"none\">\r\n <path\r\n opacity=\"0.4\"\r\n d=\"M58.333 48.8332C61.8957 45.8908 64.1663 41.4397 64.1663 36.4583C64.1663 27.5988 56.9843 20.4167 48.1247 20.4167C47.4874 20.4167 46.8912 20.0842 46.5675 19.5351C42.7641 13.0808 35.7417 8.75 27.708 8.75C15.6268 8.75 5.83301 18.5438 5.83301 30.625C5.83301 36.6511 8.26974 42.1082 12.2116 46.0644\"\r\n stroke=\"#4B5489\"\r\n stroke-width=\"2\"\r\n stroke-linecap=\"round\"\r\n stroke-linejoin=\"round\" />\r\n <path\r\n d=\"M23.333 46.6667L34.9997 35M34.9997 35L46.6663 46.6667M34.9997 35V61.25\"\r\n stroke=\"#4B5489\"\r\n stroke-width=\"2\"\r\n stroke-linecap=\"round\"\r\n stroke-linejoin=\"round\" />\r\n </svg>\r\n <!--Validation text-->\r\n <div class=\"bbsf-validation-msg text-center\">{{ UtilityService.getResourceValue('Upload') }}</div>\r\n <div class=\"bbsf-validation-msg text-center\" *ngIf=\"validationMessage\" [innerHTML]=\"validationMessage\"></div>\r\n <div\r\n class=\"bbsf-validation-msg ng-star-inserted text-center text-danger\"\r\n *ngIf=\"validationCountMessage && options.isMultipleFile && options.maxNoOfFiles > 0\"\r\n [innerHTML]=\"validationCountMessage\"></div>\r\n </div>\r\n </div>\r\n <input\r\n ng2FileSelect\r\n [uploader]=\"uploader\"\r\n [accept]=\"acceptedType\"\r\n class=\"fileSelector customFileUploadPlacment hidden v-required-multiplefiles d-none\"\r\n multiple=\"{{ options.isMultipleFile ? 'multiple' : '' }}\"\r\n name=\"file\"\r\n type=\"file\"\r\n value=\"\"\r\n autocomplete=\"off\"\r\n (change)=\"onFileChange()\"\r\n [ngClass]=\"options.viewType == 1 ? '' : 'col-md-9'\"\r\n id=\"{{ options.name }}\"\r\n aria-describedby=\"email-error\"\r\n aria-invalid=\"true\"\r\n formControlName=\"{{ options.name }}\"\r\n #fileInput\r\n [class.is-invalid]=\"fileUploadFormControl.invalid && fileUploadFormControl.touched\" />\r\n </div>\r\n <!-- readonly -->\r\n <div *ngIf=\"options.isReadonly && !options.value\">\r\n <span class=\"readonly-view\">{{ UtilityService.getResourceValue('NA') }}</span>\r\n </div>\r\n </div>\r\n <!--items uploaded-->\r\n <div class=\"uploaded-items\">\r\n <div class=\"btn-group\" *ngFor=\"let item of uploader.queue\">\r\n <ng-container *ngIf=\"item?.progress == 100 && options.isUploadFileAsync\">\r\n <a *ngIf=\"item?.file?.rawFile['url']\" href=\"{{ item?.file?.rawFile['url'] }}\" class=\"btn-download-file btn-sm btn-progress-upload\" download>\r\n <span class=\"file-name\">{{ item?.file?.name }}</span>\r\n </a>\r\n <a *ngIf=\"item?.file?.rawFile['url'] == null\" class=\"btn-download-file btn-sm btn-progress-upload\">\r\n <span class=\"file-name\">{{ item?.file?.name }}</span>\r\n </a>\r\n <button *ngIf=\"!options.isReadonly\" class=\"btn btn-download-file btn-sm\" (click)=\"item.remove(); removeFromControlValue(item)\">\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"14\" height=\"14\" viewBox=\"0 0 14 14\" fill=\"none\">\r\n <path\r\n opacity=\"0.4\"\r\n d=\"M9.33301 3.70584V3.26663C9.33301 2.65166 9.33301 2.34419 9.20587 2.1093C9.09405 1.9027 8.91555 1.73471 8.69604 1.62944C8.44647 1.50977 8.11977 1.50977 7.46638 1.50977H6.53305C5.87965 1.50977 5.55296 1.50977 5.30339 1.62944C5.08387 1.73471 4.90539 1.9027 4.79354 2.1093C4.66638 2.34419 4.66638 2.65166 4.66638 3.26663V3.70584\"\r\n stroke=\"#D83731\"\r\n stroke-width=\"1.5\"\r\n stroke-linecap=\"round\"\r\n stroke-linejoin=\"round\" />\r\n <path\r\n d=\"M1.75 3.70605H12.25M11.0834 3.70605V9.8551C11.0834 10.7775 11.0834 11.2387 10.8926 11.591C10.7248 11.901 10.4571 12.1529 10.1278 12.3109C9.75345 12.4904 9.26345 12.4904 8.28334 12.4904H5.71666C4.73658 12.4904 4.24653 12.4904 3.87218 12.3109C3.5429 12.1529 3.27519 11.901 3.10741 11.591C2.91666 11.2387 2.91666 10.7775 2.91666 9.8551V3.70605\"\r\n stroke=\"#D83731\"\r\n stroke-width=\"1.5\"\r\n stroke-linecap=\"round\"\r\n stroke-linejoin=\"round\" />\r\n </svg>\r\n </button>\r\n </ng-container>\r\n <ng-container *ngIf=\"!options.isUploadFileAsync\">\r\n <a href=\"{{ item?.file?.rawFile['url'] }}\" class=\"btn btn-download-file btn-sm\" download>\r\n <svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\r\n <path\r\n d=\"M21 22H3C2.4 22 2 21.6 2 21C2 20.4 2.4 20 3 20H21C21.6 20 22 20.4 22 21C22 21.6 21.6 22 21 22ZM13 13.4V3C13 2.4 12.6 2 12 2C11.4 2 11 2.4 11 3V13.4H13Z\"\r\n fill=\"currentColor\"></path>\r\n <path opacity=\"0.3\" d=\"M7 13.4H17L12.7 17.7C12.3 18.1 11.7 18.1 11.3 17.7L7 13.4Z\" fill=\"currentColor\"></path>\r\n </svg>\r\n <span class=\"file-name\">{{ item?.file?.name }}</span>\r\n </a>\r\n <button *ngIf=\"!options.isReadonly\" class=\"btn btn-download-file btn-sm btn-danger\" (click)=\"item.remove(); removeFromControlValue(item)\">\r\n <i class=\"fa fa-times px-0\"></i>\r\n </button>\r\n </ng-container>\r\n </div>\r\n </div>\r\n <!--progress bar file upload-->\r\n <div *ngFor=\"let item of uploader.queue\">\r\n <div class=\"upload-items\" [ngClass]=\"{ 'mt-4': options.isMultipleFile == true }\" *ngIf=\"item?.progress < 100 && options.isUploadFileAsync\">\r\n <div class=\"upload-items-toolbar\">\r\n <h4>{{ item?.file?.name }}</h4>\r\n <span (click)=\"item.remove(); removeFromControlValue(item)\">\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"18\" height=\"18\" viewBox=\"0 0 18 18\" fill=\"none\">\r\n <g clip-path=\"url(#clip0_1324_13216)\">\r\n <path\r\n opacity=\"0.4\"\r\n d=\"M9 16.5C13.1421 16.5 16.5 13.1421 16.5 9C16.5 4.85786 13.1421 1.5 9 1.5C4.85786 1.5 1.5 4.85786 1.5 9C1.5 13.1421 4.85786 16.5 9 16.5Z\"\r\n stroke=\"#DBE1F0\"\r\n stroke-width=\"2\"\r\n stroke-linecap=\"round\"\r\n stroke-linejoin=\"round\" />\r\n <path\r\n d=\"M11.25 6.75L6.75 11.25M6.75 6.75L11.25 11.25\"\r\n stroke=\"#DBE1F0\"\r\n stroke-width=\"2\"\r\n stroke-linecap=\"round\"\r\n stroke-linejoin=\"round\" />\r\n </g>\r\n <defs>\r\n <clipPath id=\"clip0_1324_13216\">\r\n <rect width=\"18\" height=\"18\" fill=\"white\" />\r\n </clipPath>\r\n </defs>\r\n </svg>\r\n </span>\r\n </div>\r\n <div class=\"progress\">\r\n <div\r\n class=\"progress-bar\"\r\n role=\"progressbar\"\r\n aria-valuenow=\"70\"\r\n aria-valuemin=\"0\"\r\n aria-valuemax=\"100\"\r\n [class.file-uploaded]=\"item?.progress < 100\"\r\n [style.width.%]=\"item?.progress\"\r\n *ngIf=\"item?.progress > 0\"></div>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <div class=\"subtext-container\" *ngIf=\"!options.isReadonly\">\r\n <!-- required text-->\r\n <div class=\"bbsf-validation\" *ngIf=\"fileUploadFormControl.invalid && fileUploadFormControl.touched\">\r\n {{ getErrorValidation(fileUploadFormControl.errors | keyvalue) }}\r\n </div>\r\n <!-- LabelDescription-->\r\n <div class=\"bbsf-control-desc\" *ngIf=\"options.labelDescription != null\">{{ options.labelDescription }}</div>\r\n <div *ngIf=\"(group.valid && group.dirty && group.touched) || (group.untouched && group.invalid && group.dirty)\">\r\n {{ resetError() }}\r\n </div>\r\n </div>\r\n</div>\r\n", dependencies: [{ kind: "directive", type: i5.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i5.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i5.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i7$2.FileDropDirective, selector: "[ng2FileDrop]", inputs: ["uploader"], outputs: ["fileOver", "onFileDrop"] }, { kind: "directive", type: i7$2.FileSelectDirective, selector: "[ng2FileSelect]", inputs: ["uploader"], outputs: ["onFileSelected"] }, { kind: "directive", type: i7.NativeElementInjectorDirective, selector: "[ngModel], [formControl], [formControlName]" }, { 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.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i2.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "pipe", type: i5.KeyValuePipe, name: "keyvalue" }] }); }
3168
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.3.12", type: FileUploadComponent, selector: "BBSF-FileUpload", inputs: { group: "group", options: "options" }, outputs: { OnChange: "OnChange", isUploadComplete: "isUploadComplete" }, viewQueries: [{ propertyName: "fileInput", first: true, predicate: ["fileInput"], descendants: true }], ngImport: i0, template: "<div class=\"form-group bbsf-control bbsf-file-upload\" [formGroup]=\"group\">\r\n <div [ngClass]=\"options.viewType === 1 ? 'bbsf-vertical' : 'bbsf-horizontal'\">\r\n <!-- Label -->\r\n <label [hidden]=\"options.hideLabel\" class=\"bbsf-label {{ options.labelExtraClasses }}\">\r\n {{ options.labelValue }}\r\n <!-- Required asterisk -->\r\n <span *ngIf=\"options.isRequired && !options.isReadonly && (options.showAsterisk || true)\"\r\n class=\"text-danger\">*</span>\r\n </label>\r\n <!-- Drop zone enabled -->\r\n <div ng2FileDrop class=\"bbsf-input-container {{ options.extraClasses }}\"\r\n *ngIf=\"options.isDropZone && !isHideInput() && !options.isReadonly\"\r\n [ngClass]=\"{ 'another-file-over-class': hasAnotherDropZoneOver }\" (onFileDrop)=\"onFileChange()\"\r\n (fileOver)=\"fileOverAnother($event)\" [uploader]=\"uploader\" [accept]=\"acceptedType\" [id]=\"options.name\"\r\n [attr.multiple]=\"options.isMultipleFile ? 'multiple' : null\"\r\n [class.is-invalid]=\"fileUploadFormControl.invalid && fileUploadFormControl.touched\"\r\n (click)=\"fileInputControl.click()\">\r\n\r\n <div class=\"dropzone-label\">\r\n <div class=\"svg-and-validation\">\r\n <!-- Upload icon -->\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"70\" height=\"70\" viewBox=\"0 0 70 70\" fill=\"none\">\r\n <path opacity=\"0.4\"\r\n d=\"M58.333 48.8332C61.8957 45.8908 64.1663 41.4397 64.1663 36.4583C64.1663 27.5988 56.9843 20.4167 48.1247 20.4167C47.4874 20.4167 46.8912 20.0842 46.5675 19.5351C42.7641 13.0808 35.7417 8.75 27.708 8.75C15.6268 8.75 5.83301 18.5438 5.83301 30.625C5.83301 36.6511 8.26974 42.1082 12.2116 46.0644\"\r\n stroke=\"#4B5489\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\r\n <path d=\"M23.333 46.6667L34.9997 35M34.9997 35L46.6663 46.6667M34.9997 35V61.25\" stroke=\"#4B5489\"\r\n stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\r\n </svg>\r\n\r\n <!-- Instruction text -->\r\n <div class=\"bbsf-validation-msg validation-msg-header text-center\">\r\n {{ utilityService.getResourceValue('DragAndDropHere') }}\r\n </div>\r\n\r\n <!-- Validation messages -->\r\n <div class=\"bbsf-validation-msg text-center\" *ngIf=\"validationMessage\" [innerHTML]=\"validationMessage\">\r\n </div>\r\n\r\n <div class=\"bbsf-validation-msg text-center text-danger\"\r\n *ngIf=\"validationCountMessage && options.isMultipleFile && options.maxNoOfFiles > 0\"\r\n [innerHTML]=\"validationCountMessage\">\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- Hidden file input -->\r\n <input ng2FileSelect [uploader]=\"uploader\" [accept]=\"acceptedType\"\r\n class=\"fileSelector customFileUploadPlacment hidden v-required-multiplefiles d-none\"\r\n [attr.multiple]=\"options.isMultipleFile ? 'multiple' : null\" name=\"file\" type=\"file\" autocomplete=\"off\"\r\n (change)=\"onFileChange()\" [ngClass]=\"options.viewType === 1 ? '' : 'col-md-9'\" [id]=\"options.name\"\r\n #fileInputControl [class.is-invalid]=\"fileUploadFormControl.invalid && fileUploadFormControl.touched\" />\r\n </div>\r\n <!-- Click to upload (no drop zone) -->\r\n <div class=\"bbsf-input-container\" *ngIf=\"!options.isDropZone && !isHideInput() && !options.isReadonly\"\r\n (click)=\"fileInput.click()\">\r\n\r\n <div class=\"dropzone-label\">\r\n <div class=\"svg-and-validation\">\r\n <!-- Upload icon -->\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"70\" height=\"70\" viewBox=\"0 0 70 70\" fill=\"none\">\r\n <path opacity=\"0.4\"\r\n d=\"M58.333 48.8332C61.8957 45.8908 64.1663 41.4397 64.1663 36.4583C64.1663 27.5988 56.9843 20.4167 48.1247 20.4167C47.4874 20.4167 46.8912 20.0842 46.5675 19.5351C42.7641 13.0808 35.7417 8.75 27.708 8.75C15.6268 8.75 5.83301 18.5438 5.83301 30.625C5.83301 36.6511 8.26974 42.1082 12.2116 46.0644\"\r\n stroke=\"#4B5489\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\r\n <path d=\"M23.333 46.6667L34.9997 35M34.9997 35L46.6663 46.6667M34.9997 35V61.25\" stroke=\"#4B5489\"\r\n stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\r\n </svg>\r\n\r\n <!-- Upload text -->\r\n <div class=\"bbsf-validation-msg text-center\">\r\n {{ utilityService.getResourceValue('Upload') }}\r\n </div>\r\n\r\n <!-- Validation messages -->\r\n <div class=\"bbsf-validation-msg text-center\" *ngIf=\"validationMessage\" [innerHTML]=\"validationMessage\">\r\n </div>\r\n\r\n <div class=\"bbsf-validation-msg text-center text-danger\"\r\n *ngIf=\"validationCountMessage && options.isMultipleFile && options.maxNoOfFiles > 0\"\r\n [innerHTML]=\"validationCountMessage\">\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- Hidden file input -->\r\n <input ng2FileSelect [uploader]=\"uploader\" [accept]=\"acceptedType\"\r\n class=\"fileSelector customFileUploadPlacment hidden v-required-multiplefiles d-none\"\r\n [attr.multiple]=\"options.isMultipleFile ? 'multiple' : null\" name=\"file\" type=\"file\" autocomplete=\"off\"\r\n (change)=\"onFileChange()\" [ngClass]=\"options.viewType === 1 ? '' : 'col-md-9'\" [id]=\"options.name\" #fileInput\r\n [class.is-invalid]=\"fileUploadFormControl.invalid && fileUploadFormControl.touched\" />\r\n </div>\r\n <!-- Read-only state with no files -->\r\n <div *ngIf=\"options.isReadonly && (!options.value || (uploader.queue && uploader.queue.length === 0))\">\r\n <span class=\"readonly-view\">{{ utilityService.getResourceValue('NA') }}</span>\r\n </div>\r\n </div>\r\n <!-- Uploaded files list -->\r\n <div class=\"uploaded-items\" *ngIf=\"shouldShowFileList()\">\r\n <div class=\"btn-group\" *ngFor=\"let item of uploader.queue; trackBy: trackByFunction\">\r\n\r\n <!-- Async upload completed files -->\r\n <ng-container *ngIf=\"item?.progress === 100 && options.isUploadFileAsync\">\r\n <!-- Download link - always visible -->\r\n <button *ngIf=\"getFileDownloadUrl(item); else noUrlTemplate\" type=\"button\"\r\n class=\"btn-download-file btn-sm btn-progress-upload\" (click)=\"downloadFile(item)\"\r\n [title]=\"'Download ' + getFileName(item)\">\r\n <span class=\"file-name\">{{ getFileName(item) }}</span>\r\n </button>\r\n\r\n <!-- File name display when no URL available -->\r\n <ng-template #noUrlTemplate>\r\n <span class=\"btn-download-file btn-sm btn-progress-upload\" [title]=\"getFileName(item)\">\r\n <span class=\"file-name\">{{ getFileName(item) }}</span>\r\n </span>\r\n </ng-template>\r\n\r\n <!-- Remove button - only show when not readonly and not disabled -->\r\n <button *ngIf=\"isRemoveEnabled()\" class=\"btn btn-download-file btn-sm\" type=\"button\"\r\n (click)=\"item.remove(); removeFromControlValue(item)\" [attr.aria-label]=\"'Remove ' + getFileName(item)\"\r\n [title]=\"'Remove ' + getFileName(item)\">\r\n <!-- Delete icon -->\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"14\" height=\"14\" viewBox=\"0 0 14 14\" fill=\"none\">\r\n <path opacity=\"0.4\"\r\n d=\"M9.33301 3.70584V3.26663C9.33301 2.65166 9.33301 2.34419 9.20587 2.1093C9.09405 1.9027 8.91555 1.73471 8.69604 1.62944C8.44647 1.50977 8.11977 1.50977 7.46638 1.50977H6.53305C5.87965 1.50977 5.55296 1.50977 5.30339 1.62944C5.08387 1.73471 4.90539 1.9027 4.79354 2.1093C4.66638 2.34419 4.66638 2.65166 4.66638 3.26663V3.70584\"\r\n stroke=\"#D83731\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\r\n <path\r\n d=\"M1.75 3.70605H12.25M11.0834 3.70605V9.8551C11.0834 10.7775 11.0834 11.2387 10.8926 11.591C10.7248 11.901 10.4571 12.1529 10.1278 12.3109C9.75345 12.4904 9.26345 12.4904 8.28334 12.4904H5.71666C4.73658 12.4904 4.24653 12.4904 3.87218 12.3109C3.5429 12.1529 3.27519 11.901 3.10741 11.591C2.91666 11.2387 2.91666 10.7775 2.91666 9.8551V3.70605\"\r\n stroke=\"#D83731\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\r\n </svg>\r\n </button>\r\n </ng-container>\r\n\r\n <!-- Sync upload files -->\r\n <ng-container *ngIf=\"!options.isUploadFileAsync\">\r\n <!-- Download link - always visible -->\r\n <button type=\"button\" class=\"btn btn-download-file btn-sm\" (click)=\"downloadFile(item)\"\r\n [title]=\"'Download ' + getFileName(item)\">\r\n <!-- Download icon -->\r\n <svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\r\n <path\r\n d=\"M21 22H3C2.4 22 2 21.6 2 21C2 20.4 2.4 20 3 20H21C21.6 20 22 20.4 22 21C22 21.6 21.6 22 21 22ZM13 13.4V3C13 2.4 12.6 2 12 2C11.4 2 11 2.4 11 3V13.4H13Z\"\r\n fill=\"currentColor\"></path>\r\n <path opacity=\"0.3\" d=\"M7 13.4H17L12.7 17.7C12.3 18.1 11.7 18.1 11.3 17.7L7 13.4Z\" fill=\"currentColor\">\r\n </path>\r\n </svg>\r\n <span class=\"file-name\">{{ getFileName(item) }}</span>\r\n </button>\r\n\r\n <!-- Remove button - only show when not readonly and not disabled -->\r\n <button *ngIf=\"isRemoveEnabled()\" class=\"btn btn-download-file btn-sm btn-danger\" type=\"button\"\r\n (click)=\"item.remove(); removeFromControlValue(item)\" [attr.aria-label]=\"'Remove ' + getFileName(item)\"\r\n [title]=\"'Remove ' + getFileName(item)\">\r\n <i class=\"fa fa-times px-0\" aria-hidden=\"true\"></i>\r\n </button>\r\n </ng-container>\r\n </div>\r\n </div>\r\n <!-- File upload progress indicators -->\r\n <div *ngFor=\"let item of uploader.queue; trackBy: trackByFunction\">\r\n <div class=\"upload-items\" [ngClass]=\"{ 'mt-4': options.isMultipleFile }\"\r\n *ngIf=\"item?.progress < 100 && options.isUploadFileAsync && !options.isReadonly\">\r\n\r\n <div class=\"upload-items-toolbar\">\r\n <h4>{{ getFileName(item) }}</h4>\r\n <button *ngIf=\"isRemoveEnabled()\" type=\"button\" class=\"btn-cancel-upload\"\r\n (click)=\"item.remove(); removeFromControlValue(item)\"\r\n [attr.aria-label]=\"'Cancel upload for ' + getFileName(item)\">\r\n <!-- Cancel icon -->\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"18\" height=\"18\" viewBox=\"0 0 18 18\" fill=\"none\">\r\n <g clip-path=\"url(#clip0_1324_13216)\">\r\n <path opacity=\"0.4\"\r\n d=\"M9 16.5C13.1421 16.5 16.5 13.1421 16.5 9C16.5 4.85786 13.1421 1.5 9 1.5C4.85786 1.5 1.5 4.85786 1.5 9C1.5 13.1421 4.85786 16.5 9 16.5Z\"\r\n stroke=\"#DBE1F0\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\r\n <path d=\"M11.25 6.75L6.75 11.25M6.75 6.75L11.25 11.25\" stroke=\"#DBE1F0\" stroke-width=\"2\"\r\n stroke-linecap=\"round\" stroke-linejoin=\"round\" />\r\n </g>\r\n <defs>\r\n <clipPath id=\"clip0_1324_13216\">\r\n <rect width=\"18\" height=\"18\" fill=\"white\" />\r\n </clipPath>\r\n </defs>\r\n </svg>\r\n </button>\r\n </div>\r\n\r\n <div class=\"progress\">\r\n <div class=\"progress-bar\" role=\"progressbar\" [attr.aria-valuenow]=\"item?.progress\" aria-valuemin=\"0\"\r\n aria-valuemax=\"100\" [class.file-uploaded]=\"item?.progress < 100\" [style.width.%]=\"item?.progress\"\r\n *ngIf=\"item?.progress > 0\">\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- Validation and description section -->\r\n <div class=\"subtext-container\" *ngIf=\"!options.isReadonly\">\r\n <!-- Validation messages -->\r\n <div class=\"bbsf-validation\" *ngIf=\"fileUploadFormControl.invalid && fileUploadFormControl.touched\">\r\n <span [innerHTML]=\"getErrorValidation(fileUploadFormControl.errors | keyvalue)\"></span>\r\n </div>\r\n\r\n <!-- Control description -->\r\n <div class=\"bbsf-control-desc\" *ngIf=\"options.labelDescription\">\r\n {{ options.labelDescription }}\r\n </div>\r\n\r\n <!-- Reset error state -->\r\n <div *ngIf=\"(group.valid && group.dirty && group.touched) || (group.untouched && group.invalid && group.dirty)\">\r\n {{ resetError() }}\r\n </div>\r\n </div>\r\n</div>", dependencies: [{ kind: "directive", type: i5.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i5.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i5.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i7$2.FileDropDirective, selector: "[ng2FileDrop]", inputs: ["uploader"], outputs: ["fileOver", "onFileDrop"] }, { kind: "directive", type: i7$2.FileSelectDirective, selector: "[ng2FileSelect]", inputs: ["uploader"], outputs: ["onFileSelected"] }, { kind: "directive", type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "pipe", type: i5.KeyValuePipe, name: "keyvalue" }] }); }
2663
3169
  }
2664
3170
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: FileUploadComponent, decorators: [{
2665
3171
  type: Component,
2666
- args: [{ selector: 'BBSF-FileUplaod', template: "<div class=\"form-group bbsf-control bbsf-file-upload\" [formGroup]=\"group\">\r\n <div [ngClass]=\"options.viewType == 1 ? 'bbsf-vertical' : 'bbsf-horizontal'\">\r\n <!--label-->\r\n <label [hidden]=\"options.hideLabel\" class=\"bbsf-label {{ options.labelExtraClasses }}\">\r\n {{ options.labelValue }}\r\n <!--Asterisk-->\r\n <span *ngIf=\"((options.showAsterisk && options.isRequired) || options.isRequired) && !options.isReadonly\" class=\"text-danger\">*</span>\r\n </label>\r\n <!--Allow dropZone-->\r\n <div\r\n ng2FileDrop\r\n class=\"bbsf-input-container {{ options.extraClasses }}\"\r\n *ngIf=\"options.isDropZone && !(options.isMultipleFile == false && uploader.queue.length > 0) && !options.isReadonly\"\r\n [ngClass]=\"{ 'another-file-over-class': hasAnotherDropZoneOver }\"\r\n (onFileDrop)=\"onFileChange()\"\r\n (fileOver)=\"fileOverAnother($event)\"\r\n [uploader]=\"uploader\"\r\n [accept]=\"acceptedType\"\r\n id=\"{{ options.name }}\"\r\n multiple=\"{{ options.isMultipleFile ? 'multiple' : '' }}\"\r\n aria-describedby=\"email-error\"\r\n aria-invalid=\"true\"\r\n type=\"file\"\r\n #fileInput\r\n [class.is-invalid]=\"fileUploadFormControl.invalid && fileUploadFormControl.touched\"\r\n (click)=\"fileInputControl.click()\">\r\n <div class=\"dropzone-label\">\r\n <div class=\"svg-and-validation\">\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"70\" height=\"70\" viewBox=\"0 0 70 70\" fill=\"none\">\r\n <path\r\n opacity=\"0.4\"\r\n d=\"M58.333 48.8332C61.8957 45.8908 64.1663 41.4397 64.1663 36.4583C64.1663 27.5988 56.9843 20.4167 48.1247 20.4167C47.4874 20.4167 46.8912 20.0842 46.5675 19.5351C42.7641 13.0808 35.7417 8.75 27.708 8.75C15.6268 8.75 5.83301 18.5438 5.83301 30.625C5.83301 36.6511 8.26974 42.1082 12.2116 46.0644\"\r\n stroke=\"#4B5489\"\r\n stroke-width=\"2\"\r\n stroke-linecap=\"round\"\r\n stroke-linejoin=\"round\" />\r\n <path\r\n d=\"M23.333 46.6667L34.9997 35M34.9997 35L46.6663 46.6667M34.9997 35V61.25\"\r\n stroke=\"#4B5489\"\r\n stroke-width=\"2\"\r\n stroke-linecap=\"round\"\r\n stroke-linejoin=\"round\" />\r\n </svg>\r\n <!--Validation text-->\r\n <div class=\"bbsf-validation-msg validation-msg-header text-center\">\r\n {{ UtilityService.getResourceValue('DragAndDropHere') }}\r\n </div>\r\n <div class=\"bbsf-validation-msg text-center\" *ngIf=\"validationMessage\" [innerHTML]=\"validationMessage\"></div>\r\n <div\r\n class=\"bbsf-validation-msg ng-star-inserted text-center text-danger\"\r\n *ngIf=\"validationCountMessage && options.isMultipleFile && options.maxNoOfFiles > 0\"\r\n [innerHTML]=\"validationCountMessage\"></div>\r\n </div>\r\n </div>\r\n <input\r\n ng2FileSelect\r\n [uploader]=\"uploader\"\r\n [accept]=\"acceptedType\"\r\n class=\"fileSelector customFileUploadPlacment hidden v-required-multiplefiles d-none\"\r\n multiple=\"{{ options.isMultipleFile ? 'multiple' : '' }}\"\r\n name=\"file\"\r\n type=\"file\"\r\n value=\"\"\r\n autocomplete=\"off\"\r\n (change)=\"onFileChange()\"\r\n [ngClass]=\"options.viewType == 1 ? '' : 'col-md-9'\"\r\n id=\"{{ options.name }}\"\r\n aria-describedby=\"email-error\"\r\n aria-invalid=\"true\"\r\n formControlName=\"{{ options.name }}\"\r\n #fileInputControl\r\n [class.is-invalid]=\"fileUploadFormControl.invalid && fileUploadFormControl.touched\" />\r\n </div>\r\n <!--Not allowed dropZone-->\r\n <div class=\"bbsf-input-container\" *ngIf=\"!options.isDropZone && !isHideInput() && !options.isReadonly\" (click)=\"fileInput.click()\">\r\n <div class=\"dropzone-label\">\r\n <div class=\"svg-and-validation\">\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"70\" height=\"70\" viewBox=\"0 0 70 70\" fill=\"none\">\r\n <path\r\n opacity=\"0.4\"\r\n d=\"M58.333 48.8332C61.8957 45.8908 64.1663 41.4397 64.1663 36.4583C64.1663 27.5988 56.9843 20.4167 48.1247 20.4167C47.4874 20.4167 46.8912 20.0842 46.5675 19.5351C42.7641 13.0808 35.7417 8.75 27.708 8.75C15.6268 8.75 5.83301 18.5438 5.83301 30.625C5.83301 36.6511 8.26974 42.1082 12.2116 46.0644\"\r\n stroke=\"#4B5489\"\r\n stroke-width=\"2\"\r\n stroke-linecap=\"round\"\r\n stroke-linejoin=\"round\" />\r\n <path\r\n d=\"M23.333 46.6667L34.9997 35M34.9997 35L46.6663 46.6667M34.9997 35V61.25\"\r\n stroke=\"#4B5489\"\r\n stroke-width=\"2\"\r\n stroke-linecap=\"round\"\r\n stroke-linejoin=\"round\" />\r\n </svg>\r\n <!--Validation text-->\r\n <div class=\"bbsf-validation-msg text-center\">{{ UtilityService.getResourceValue('Upload') }}</div>\r\n <div class=\"bbsf-validation-msg text-center\" *ngIf=\"validationMessage\" [innerHTML]=\"validationMessage\"></div>\r\n <div\r\n class=\"bbsf-validation-msg ng-star-inserted text-center text-danger\"\r\n *ngIf=\"validationCountMessage && options.isMultipleFile && options.maxNoOfFiles > 0\"\r\n [innerHTML]=\"validationCountMessage\"></div>\r\n </div>\r\n </div>\r\n <input\r\n ng2FileSelect\r\n [uploader]=\"uploader\"\r\n [accept]=\"acceptedType\"\r\n class=\"fileSelector customFileUploadPlacment hidden v-required-multiplefiles d-none\"\r\n multiple=\"{{ options.isMultipleFile ? 'multiple' : '' }}\"\r\n name=\"file\"\r\n type=\"file\"\r\n value=\"\"\r\n autocomplete=\"off\"\r\n (change)=\"onFileChange()\"\r\n [ngClass]=\"options.viewType == 1 ? '' : 'col-md-9'\"\r\n id=\"{{ options.name }}\"\r\n aria-describedby=\"email-error\"\r\n aria-invalid=\"true\"\r\n formControlName=\"{{ options.name }}\"\r\n #fileInput\r\n [class.is-invalid]=\"fileUploadFormControl.invalid && fileUploadFormControl.touched\" />\r\n </div>\r\n <!-- readonly -->\r\n <div *ngIf=\"options.isReadonly && !options.value\">\r\n <span class=\"readonly-view\">{{ UtilityService.getResourceValue('NA') }}</span>\r\n </div>\r\n </div>\r\n <!--items uploaded-->\r\n <div class=\"uploaded-items\">\r\n <div class=\"btn-group\" *ngFor=\"let item of uploader.queue\">\r\n <ng-container *ngIf=\"item?.progress == 100 && options.isUploadFileAsync\">\r\n <a *ngIf=\"item?.file?.rawFile['url']\" href=\"{{ item?.file?.rawFile['url'] }}\" class=\"btn-download-file btn-sm btn-progress-upload\" download>\r\n <span class=\"file-name\">{{ item?.file?.name }}</span>\r\n </a>\r\n <a *ngIf=\"item?.file?.rawFile['url'] == null\" class=\"btn-download-file btn-sm btn-progress-upload\">\r\n <span class=\"file-name\">{{ item?.file?.name }}</span>\r\n </a>\r\n <button *ngIf=\"!options.isReadonly\" class=\"btn btn-download-file btn-sm\" (click)=\"item.remove(); removeFromControlValue(item)\">\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"14\" height=\"14\" viewBox=\"0 0 14 14\" fill=\"none\">\r\n <path\r\n opacity=\"0.4\"\r\n d=\"M9.33301 3.70584V3.26663C9.33301 2.65166 9.33301 2.34419 9.20587 2.1093C9.09405 1.9027 8.91555 1.73471 8.69604 1.62944C8.44647 1.50977 8.11977 1.50977 7.46638 1.50977H6.53305C5.87965 1.50977 5.55296 1.50977 5.30339 1.62944C5.08387 1.73471 4.90539 1.9027 4.79354 2.1093C4.66638 2.34419 4.66638 2.65166 4.66638 3.26663V3.70584\"\r\n stroke=\"#D83731\"\r\n stroke-width=\"1.5\"\r\n stroke-linecap=\"round\"\r\n stroke-linejoin=\"round\" />\r\n <path\r\n d=\"M1.75 3.70605H12.25M11.0834 3.70605V9.8551C11.0834 10.7775 11.0834 11.2387 10.8926 11.591C10.7248 11.901 10.4571 12.1529 10.1278 12.3109C9.75345 12.4904 9.26345 12.4904 8.28334 12.4904H5.71666C4.73658 12.4904 4.24653 12.4904 3.87218 12.3109C3.5429 12.1529 3.27519 11.901 3.10741 11.591C2.91666 11.2387 2.91666 10.7775 2.91666 9.8551V3.70605\"\r\n stroke=\"#D83731\"\r\n stroke-width=\"1.5\"\r\n stroke-linecap=\"round\"\r\n stroke-linejoin=\"round\" />\r\n </svg>\r\n </button>\r\n </ng-container>\r\n <ng-container *ngIf=\"!options.isUploadFileAsync\">\r\n <a href=\"{{ item?.file?.rawFile['url'] }}\" class=\"btn btn-download-file btn-sm\" download>\r\n <svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\r\n <path\r\n d=\"M21 22H3C2.4 22 2 21.6 2 21C2 20.4 2.4 20 3 20H21C21.6 20 22 20.4 22 21C22 21.6 21.6 22 21 22ZM13 13.4V3C13 2.4 12.6 2 12 2C11.4 2 11 2.4 11 3V13.4H13Z\"\r\n fill=\"currentColor\"></path>\r\n <path opacity=\"0.3\" d=\"M7 13.4H17L12.7 17.7C12.3 18.1 11.7 18.1 11.3 17.7L7 13.4Z\" fill=\"currentColor\"></path>\r\n </svg>\r\n <span class=\"file-name\">{{ item?.file?.name }}</span>\r\n </a>\r\n <button *ngIf=\"!options.isReadonly\" class=\"btn btn-download-file btn-sm btn-danger\" (click)=\"item.remove(); removeFromControlValue(item)\">\r\n <i class=\"fa fa-times px-0\"></i>\r\n </button>\r\n </ng-container>\r\n </div>\r\n </div>\r\n <!--progress bar file upload-->\r\n <div *ngFor=\"let item of uploader.queue\">\r\n <div class=\"upload-items\" [ngClass]=\"{ 'mt-4': options.isMultipleFile == true }\" *ngIf=\"item?.progress < 100 && options.isUploadFileAsync\">\r\n <div class=\"upload-items-toolbar\">\r\n <h4>{{ item?.file?.name }}</h4>\r\n <span (click)=\"item.remove(); removeFromControlValue(item)\">\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"18\" height=\"18\" viewBox=\"0 0 18 18\" fill=\"none\">\r\n <g clip-path=\"url(#clip0_1324_13216)\">\r\n <path\r\n opacity=\"0.4\"\r\n d=\"M9 16.5C13.1421 16.5 16.5 13.1421 16.5 9C16.5 4.85786 13.1421 1.5 9 1.5C4.85786 1.5 1.5 4.85786 1.5 9C1.5 13.1421 4.85786 16.5 9 16.5Z\"\r\n stroke=\"#DBE1F0\"\r\n stroke-width=\"2\"\r\n stroke-linecap=\"round\"\r\n stroke-linejoin=\"round\" />\r\n <path\r\n d=\"M11.25 6.75L6.75 11.25M6.75 6.75L11.25 11.25\"\r\n stroke=\"#DBE1F0\"\r\n stroke-width=\"2\"\r\n stroke-linecap=\"round\"\r\n stroke-linejoin=\"round\" />\r\n </g>\r\n <defs>\r\n <clipPath id=\"clip0_1324_13216\">\r\n <rect width=\"18\" height=\"18\" fill=\"white\" />\r\n </clipPath>\r\n </defs>\r\n </svg>\r\n </span>\r\n </div>\r\n <div class=\"progress\">\r\n <div\r\n class=\"progress-bar\"\r\n role=\"progressbar\"\r\n aria-valuenow=\"70\"\r\n aria-valuemin=\"0\"\r\n aria-valuemax=\"100\"\r\n [class.file-uploaded]=\"item?.progress < 100\"\r\n [style.width.%]=\"item?.progress\"\r\n *ngIf=\"item?.progress > 0\"></div>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <div class=\"subtext-container\" *ngIf=\"!options.isReadonly\">\r\n <!-- required text-->\r\n <div class=\"bbsf-validation\" *ngIf=\"fileUploadFormControl.invalid && fileUploadFormControl.touched\">\r\n {{ getErrorValidation(fileUploadFormControl.errors | keyvalue) }}\r\n </div>\r\n <!-- LabelDescription-->\r\n <div class=\"bbsf-control-desc\" *ngIf=\"options.labelDescription != null\">{{ options.labelDescription }}</div>\r\n <div *ngIf=\"(group.valid && group.dirty && group.touched) || (group.untouched && group.invalid && group.dirty)\">\r\n {{ resetError() }}\r\n </div>\r\n </div>\r\n</div>\r\n" }]
3172
+ args: [{ selector: 'BBSF-FileUpload', standalone: false, template: "<div class=\"form-group bbsf-control bbsf-file-upload\" [formGroup]=\"group\">\r\n <div [ngClass]=\"options.viewType === 1 ? 'bbsf-vertical' : 'bbsf-horizontal'\">\r\n <!-- Label -->\r\n <label [hidden]=\"options.hideLabel\" class=\"bbsf-label {{ options.labelExtraClasses }}\">\r\n {{ options.labelValue }}\r\n <!-- Required asterisk -->\r\n <span *ngIf=\"options.isRequired && !options.isReadonly && (options.showAsterisk || true)\"\r\n class=\"text-danger\">*</span>\r\n </label>\r\n <!-- Drop zone enabled -->\r\n <div ng2FileDrop class=\"bbsf-input-container {{ options.extraClasses }}\"\r\n *ngIf=\"options.isDropZone && !isHideInput() && !options.isReadonly\"\r\n [ngClass]=\"{ 'another-file-over-class': hasAnotherDropZoneOver }\" (onFileDrop)=\"onFileChange()\"\r\n (fileOver)=\"fileOverAnother($event)\" [uploader]=\"uploader\" [accept]=\"acceptedType\" [id]=\"options.name\"\r\n [attr.multiple]=\"options.isMultipleFile ? 'multiple' : null\"\r\n [class.is-invalid]=\"fileUploadFormControl.invalid && fileUploadFormControl.touched\"\r\n (click)=\"fileInputControl.click()\">\r\n\r\n <div class=\"dropzone-label\">\r\n <div class=\"svg-and-validation\">\r\n <!-- Upload icon -->\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"70\" height=\"70\" viewBox=\"0 0 70 70\" fill=\"none\">\r\n <path opacity=\"0.4\"\r\n d=\"M58.333 48.8332C61.8957 45.8908 64.1663 41.4397 64.1663 36.4583C64.1663 27.5988 56.9843 20.4167 48.1247 20.4167C47.4874 20.4167 46.8912 20.0842 46.5675 19.5351C42.7641 13.0808 35.7417 8.75 27.708 8.75C15.6268 8.75 5.83301 18.5438 5.83301 30.625C5.83301 36.6511 8.26974 42.1082 12.2116 46.0644\"\r\n stroke=\"#4B5489\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\r\n <path d=\"M23.333 46.6667L34.9997 35M34.9997 35L46.6663 46.6667M34.9997 35V61.25\" stroke=\"#4B5489\"\r\n stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\r\n </svg>\r\n\r\n <!-- Instruction text -->\r\n <div class=\"bbsf-validation-msg validation-msg-header text-center\">\r\n {{ utilityService.getResourceValue('DragAndDropHere') }}\r\n </div>\r\n\r\n <!-- Validation messages -->\r\n <div class=\"bbsf-validation-msg text-center\" *ngIf=\"validationMessage\" [innerHTML]=\"validationMessage\">\r\n </div>\r\n\r\n <div class=\"bbsf-validation-msg text-center text-danger\"\r\n *ngIf=\"validationCountMessage && options.isMultipleFile && options.maxNoOfFiles > 0\"\r\n [innerHTML]=\"validationCountMessage\">\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- Hidden file input -->\r\n <input ng2FileSelect [uploader]=\"uploader\" [accept]=\"acceptedType\"\r\n class=\"fileSelector customFileUploadPlacment hidden v-required-multiplefiles d-none\"\r\n [attr.multiple]=\"options.isMultipleFile ? 'multiple' : null\" name=\"file\" type=\"file\" autocomplete=\"off\"\r\n (change)=\"onFileChange()\" [ngClass]=\"options.viewType === 1 ? '' : 'col-md-9'\" [id]=\"options.name\"\r\n #fileInputControl [class.is-invalid]=\"fileUploadFormControl.invalid && fileUploadFormControl.touched\" />\r\n </div>\r\n <!-- Click to upload (no drop zone) -->\r\n <div class=\"bbsf-input-container\" *ngIf=\"!options.isDropZone && !isHideInput() && !options.isReadonly\"\r\n (click)=\"fileInput.click()\">\r\n\r\n <div class=\"dropzone-label\">\r\n <div class=\"svg-and-validation\">\r\n <!-- Upload icon -->\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"70\" height=\"70\" viewBox=\"0 0 70 70\" fill=\"none\">\r\n <path opacity=\"0.4\"\r\n d=\"M58.333 48.8332C61.8957 45.8908 64.1663 41.4397 64.1663 36.4583C64.1663 27.5988 56.9843 20.4167 48.1247 20.4167C47.4874 20.4167 46.8912 20.0842 46.5675 19.5351C42.7641 13.0808 35.7417 8.75 27.708 8.75C15.6268 8.75 5.83301 18.5438 5.83301 30.625C5.83301 36.6511 8.26974 42.1082 12.2116 46.0644\"\r\n stroke=\"#4B5489\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\r\n <path d=\"M23.333 46.6667L34.9997 35M34.9997 35L46.6663 46.6667M34.9997 35V61.25\" stroke=\"#4B5489\"\r\n stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\r\n </svg>\r\n\r\n <!-- Upload text -->\r\n <div class=\"bbsf-validation-msg text-center\">\r\n {{ utilityService.getResourceValue('Upload') }}\r\n </div>\r\n\r\n <!-- Validation messages -->\r\n <div class=\"bbsf-validation-msg text-center\" *ngIf=\"validationMessage\" [innerHTML]=\"validationMessage\">\r\n </div>\r\n\r\n <div class=\"bbsf-validation-msg text-center text-danger\"\r\n *ngIf=\"validationCountMessage && options.isMultipleFile && options.maxNoOfFiles > 0\"\r\n [innerHTML]=\"validationCountMessage\">\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- Hidden file input -->\r\n <input ng2FileSelect [uploader]=\"uploader\" [accept]=\"acceptedType\"\r\n class=\"fileSelector customFileUploadPlacment hidden v-required-multiplefiles d-none\"\r\n [attr.multiple]=\"options.isMultipleFile ? 'multiple' : null\" name=\"file\" type=\"file\" autocomplete=\"off\"\r\n (change)=\"onFileChange()\" [ngClass]=\"options.viewType === 1 ? '' : 'col-md-9'\" [id]=\"options.name\" #fileInput\r\n [class.is-invalid]=\"fileUploadFormControl.invalid && fileUploadFormControl.touched\" />\r\n </div>\r\n <!-- Read-only state with no files -->\r\n <div *ngIf=\"options.isReadonly && (!options.value || (uploader.queue && uploader.queue.length === 0))\">\r\n <span class=\"readonly-view\">{{ utilityService.getResourceValue('NA') }}</span>\r\n </div>\r\n </div>\r\n <!-- Uploaded files list -->\r\n <div class=\"uploaded-items\" *ngIf=\"shouldShowFileList()\">\r\n <div class=\"btn-group\" *ngFor=\"let item of uploader.queue; trackBy: trackByFunction\">\r\n\r\n <!-- Async upload completed files -->\r\n <ng-container *ngIf=\"item?.progress === 100 && options.isUploadFileAsync\">\r\n <!-- Download link - always visible -->\r\n <button *ngIf=\"getFileDownloadUrl(item); else noUrlTemplate\" type=\"button\"\r\n class=\"btn-download-file btn-sm btn-progress-upload\" (click)=\"downloadFile(item)\"\r\n [title]=\"'Download ' + getFileName(item)\">\r\n <span class=\"file-name\">{{ getFileName(item) }}</span>\r\n </button>\r\n\r\n <!-- File name display when no URL available -->\r\n <ng-template #noUrlTemplate>\r\n <span class=\"btn-download-file btn-sm btn-progress-upload\" [title]=\"getFileName(item)\">\r\n <span class=\"file-name\">{{ getFileName(item) }}</span>\r\n </span>\r\n </ng-template>\r\n\r\n <!-- Remove button - only show when not readonly and not disabled -->\r\n <button *ngIf=\"isRemoveEnabled()\" class=\"btn btn-download-file btn-sm\" type=\"button\"\r\n (click)=\"item.remove(); removeFromControlValue(item)\" [attr.aria-label]=\"'Remove ' + getFileName(item)\"\r\n [title]=\"'Remove ' + getFileName(item)\">\r\n <!-- Delete icon -->\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"14\" height=\"14\" viewBox=\"0 0 14 14\" fill=\"none\">\r\n <path opacity=\"0.4\"\r\n d=\"M9.33301 3.70584V3.26663C9.33301 2.65166 9.33301 2.34419 9.20587 2.1093C9.09405 1.9027 8.91555 1.73471 8.69604 1.62944C8.44647 1.50977 8.11977 1.50977 7.46638 1.50977H6.53305C5.87965 1.50977 5.55296 1.50977 5.30339 1.62944C5.08387 1.73471 4.90539 1.9027 4.79354 2.1093C4.66638 2.34419 4.66638 2.65166 4.66638 3.26663V3.70584\"\r\n stroke=\"#D83731\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\r\n <path\r\n d=\"M1.75 3.70605H12.25M11.0834 3.70605V9.8551C11.0834 10.7775 11.0834 11.2387 10.8926 11.591C10.7248 11.901 10.4571 12.1529 10.1278 12.3109C9.75345 12.4904 9.26345 12.4904 8.28334 12.4904H5.71666C4.73658 12.4904 4.24653 12.4904 3.87218 12.3109C3.5429 12.1529 3.27519 11.901 3.10741 11.591C2.91666 11.2387 2.91666 10.7775 2.91666 9.8551V3.70605\"\r\n stroke=\"#D83731\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\r\n </svg>\r\n </button>\r\n </ng-container>\r\n\r\n <!-- Sync upload files -->\r\n <ng-container *ngIf=\"!options.isUploadFileAsync\">\r\n <!-- Download link - always visible -->\r\n <button type=\"button\" class=\"btn btn-download-file btn-sm\" (click)=\"downloadFile(item)\"\r\n [title]=\"'Download ' + getFileName(item)\">\r\n <!-- Download icon -->\r\n <svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\r\n <path\r\n d=\"M21 22H3C2.4 22 2 21.6 2 21C2 20.4 2.4 20 3 20H21C21.6 20 22 20.4 22 21C22 21.6 21.6 22 21 22ZM13 13.4V3C13 2.4 12.6 2 12 2C11.4 2 11 2.4 11 3V13.4H13Z\"\r\n fill=\"currentColor\"></path>\r\n <path opacity=\"0.3\" d=\"M7 13.4H17L12.7 17.7C12.3 18.1 11.7 18.1 11.3 17.7L7 13.4Z\" fill=\"currentColor\">\r\n </path>\r\n </svg>\r\n <span class=\"file-name\">{{ getFileName(item) }}</span>\r\n </button>\r\n\r\n <!-- Remove button - only show when not readonly and not disabled -->\r\n <button *ngIf=\"isRemoveEnabled()\" class=\"btn btn-download-file btn-sm btn-danger\" type=\"button\"\r\n (click)=\"item.remove(); removeFromControlValue(item)\" [attr.aria-label]=\"'Remove ' + getFileName(item)\"\r\n [title]=\"'Remove ' + getFileName(item)\">\r\n <i class=\"fa fa-times px-0\" aria-hidden=\"true\"></i>\r\n </button>\r\n </ng-container>\r\n </div>\r\n </div>\r\n <!-- File upload progress indicators -->\r\n <div *ngFor=\"let item of uploader.queue; trackBy: trackByFunction\">\r\n <div class=\"upload-items\" [ngClass]=\"{ 'mt-4': options.isMultipleFile }\"\r\n *ngIf=\"item?.progress < 100 && options.isUploadFileAsync && !options.isReadonly\">\r\n\r\n <div class=\"upload-items-toolbar\">\r\n <h4>{{ getFileName(item) }}</h4>\r\n <button *ngIf=\"isRemoveEnabled()\" type=\"button\" class=\"btn-cancel-upload\"\r\n (click)=\"item.remove(); removeFromControlValue(item)\"\r\n [attr.aria-label]=\"'Cancel upload for ' + getFileName(item)\">\r\n <!-- Cancel icon -->\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"18\" height=\"18\" viewBox=\"0 0 18 18\" fill=\"none\">\r\n <g clip-path=\"url(#clip0_1324_13216)\">\r\n <path opacity=\"0.4\"\r\n d=\"M9 16.5C13.1421 16.5 16.5 13.1421 16.5 9C16.5 4.85786 13.1421 1.5 9 1.5C4.85786 1.5 1.5 4.85786 1.5 9C1.5 13.1421 4.85786 16.5 9 16.5Z\"\r\n stroke=\"#DBE1F0\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\r\n <path d=\"M11.25 6.75L6.75 11.25M6.75 6.75L11.25 11.25\" stroke=\"#DBE1F0\" stroke-width=\"2\"\r\n stroke-linecap=\"round\" stroke-linejoin=\"round\" />\r\n </g>\r\n <defs>\r\n <clipPath id=\"clip0_1324_13216\">\r\n <rect width=\"18\" height=\"18\" fill=\"white\" />\r\n </clipPath>\r\n </defs>\r\n </svg>\r\n </button>\r\n </div>\r\n\r\n <div class=\"progress\">\r\n <div class=\"progress-bar\" role=\"progressbar\" [attr.aria-valuenow]=\"item?.progress\" aria-valuemin=\"0\"\r\n aria-valuemax=\"100\" [class.file-uploaded]=\"item?.progress < 100\" [style.width.%]=\"item?.progress\"\r\n *ngIf=\"item?.progress > 0\">\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- Validation and description section -->\r\n <div class=\"subtext-container\" *ngIf=\"!options.isReadonly\">\r\n <!-- Validation messages -->\r\n <div class=\"bbsf-validation\" *ngIf=\"fileUploadFormControl.invalid && fileUploadFormControl.touched\">\r\n <span [innerHTML]=\"getErrorValidation(fileUploadFormControl.errors | keyvalue)\"></span>\r\n </div>\r\n\r\n <!-- Control description -->\r\n <div class=\"bbsf-control-desc\" *ngIf=\"options.labelDescription\">\r\n {{ options.labelDescription }}\r\n </div>\r\n\r\n <!-- Reset error state -->\r\n <div *ngIf=\"(group.valid && group.dirty && group.touched) || (group.untouched && group.invalid && group.dirty)\">\r\n {{ resetError() }}\r\n </div>\r\n </div>\r\n</div>" }]
2667
3173
  }], ctorParameters: () => [{ type: i2.ControlContainer, decorators: [{
2668
3174
  type: Optional
2669
3175
  }] }, { type: i2.FormGroupDirective }, { type: ControlUtility }, { type: i3.UtilityService }, { type: i3.ControlValidationService }, { type: GlobalSettings }, { type: FileUploadService }], propDecorators: { fileInput: [{
@@ -9251,6 +9757,7 @@ class BBSFControlsModule {
9251
9757
  NgbModal,
9252
9758
  NgbActiveModal,
9253
9759
  DatePipe,
9760
+ KeyValuePipe,
9254
9761
  BBSFDateTimePipe,
9255
9762
  BBSFDatePipe,
9256
9763
  RenderComponentService,
@@ -9374,6 +9881,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImpo
9374
9881
  NgbModal,
9375
9882
  NgbActiveModal,
9376
9883
  DatePipe,
9884
+ KeyValuePipe,
9377
9885
  BBSFDateTimePipe,
9378
9886
  BBSFDatePipe,
9379
9887
  RenderComponentService,
@@ -9748,6 +10256,7 @@ class FileDTO {
9748
10256
  this.bytes = undefined;
9749
10257
  this.fileSizeInMB = undefined;
9750
10258
  this.fileURL = undefined;
10259
+ this.fullFileURL = undefined;
9751
10260
  this.isNew = false;
9752
10261
  }
9753
10262
  }