cloud-ide-element 1.0.67 → 1.0.68
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/fesm2022/cloud-ide-element.mjs +265 -19
- package/fesm2022/cloud-ide-element.mjs.map +1 -1
- package/index.d.ts +54 -4
- package/package.json +1 -1
|
@@ -2598,6 +2598,7 @@ class ICoreCyfmSave {
|
|
|
2598
2598
|
cyfm_tags;
|
|
2599
2599
|
cyfm_version;
|
|
2600
2600
|
cyfm_file_status_sygmt;
|
|
2601
|
+
cyfm_group_id; // Group ID for multiple file uploads
|
|
2601
2602
|
cyfm_isactive;
|
|
2602
2603
|
cyfm_file_base64 = "";
|
|
2603
2604
|
cyfm_temp_unique_id = "";
|
|
@@ -2625,12 +2626,14 @@ class CideEleFileManagerService {
|
|
|
2625
2626
|
destroyRef = inject(DestroyRef);
|
|
2626
2627
|
// Angular 20: Signal-based state management
|
|
2627
2628
|
_baseUrl = signal('/api', ...(ngDevMode ? [{ debugName: "_baseUrl" }] : []));
|
|
2629
|
+
_userId = signal('', ...(ngDevMode ? [{ debugName: "_userId" }] : []));
|
|
2628
2630
|
_isUploading = signal(false, ...(ngDevMode ? [{ debugName: "_isUploading" }] : []));
|
|
2629
2631
|
_uploadQueue = signal([], ...(ngDevMode ? [{ debugName: "_uploadQueue" }] : []));
|
|
2630
2632
|
_activeUploads = signal(new Map(), ...(ngDevMode ? [{ debugName: "_activeUploads" }] : []));
|
|
2631
2633
|
_error = signal(null, ...(ngDevMode ? [{ debugName: "_error" }] : []));
|
|
2632
2634
|
// Angular 20: Computed values
|
|
2633
2635
|
baseUrl = this._baseUrl.asReadonly();
|
|
2636
|
+
userId = this._userId.asReadonly();
|
|
2634
2637
|
isUploading = this._isUploading.asReadonly();
|
|
2635
2638
|
uploadQueue = this._uploadQueue.asReadonly();
|
|
2636
2639
|
activeUploads = this._activeUploads.asReadonly();
|
|
@@ -2699,11 +2702,12 @@ class CideEleFileManagerService {
|
|
|
2699
2702
|
cyfm_size_in_byte: file.size,
|
|
2700
2703
|
cyfm_type: file.type,
|
|
2701
2704
|
cyfm_creation_dt: new Date().toISOString(),
|
|
2702
|
-
cyfm_id_user: uploadOptions?.userId || '',
|
|
2705
|
+
cyfm_id_user: uploadOptions?.userId || this._userId() || '',
|
|
2703
2706
|
cyfm_permissions: [], // Match the interface type
|
|
2704
2707
|
cyfm_tags: uploadOptions?.tags || [],
|
|
2705
2708
|
cyfm_version: 1,
|
|
2706
2709
|
cyfm_file_status_sygmt: uploadOptions?.fileStatus || 'file_manager_file_status_active',
|
|
2710
|
+
cyfm_group_id: uploadOptions?.groupId, // Group ID for multiple file uploads
|
|
2707
2711
|
cyfm_isactive: true,
|
|
2708
2712
|
cyfm_file_base64: base64Data,
|
|
2709
2713
|
cyfm_temp_unique_id: fileId
|
|
@@ -2796,6 +2800,29 @@ class CideEleFileManagerService {
|
|
|
2796
2800
|
console.log('🔍 [FileManagerService] Setting base URL:', url);
|
|
2797
2801
|
this._baseUrl.set(url);
|
|
2798
2802
|
}
|
|
2803
|
+
/**
|
|
2804
|
+
* Set the user ID for file uploads
|
|
2805
|
+
* Angular 20: Using signal-based state management
|
|
2806
|
+
* @param userId The user ID to associate with uploaded files
|
|
2807
|
+
*/
|
|
2808
|
+
setUserId(userId) {
|
|
2809
|
+
console.log('🔍 [FileManagerService] Setting user ID:', userId);
|
|
2810
|
+
this._userId.set(userId);
|
|
2811
|
+
}
|
|
2812
|
+
/**
|
|
2813
|
+
* Generate Object ID for group uploads
|
|
2814
|
+
* Calls the backend API to generate a unique ObjectId for grouping multiple files
|
|
2815
|
+
* @returns Observable with the generated ObjectId
|
|
2816
|
+
*/
|
|
2817
|
+
generateObjectId() {
|
|
2818
|
+
const url = `${this._baseUrl()}/utility/generateObjectId`;
|
|
2819
|
+
console.log('🆔 [FileManagerService] Generating ObjectId from:', url);
|
|
2820
|
+
return this.http.get(url).pipe(catchError((error) => {
|
|
2821
|
+
console.error('❌ [FileManagerService] Error generating ObjectId:', error);
|
|
2822
|
+
this._error.set(`Failed to generate ObjectId: ${error.message}`);
|
|
2823
|
+
return throwError(() => error);
|
|
2824
|
+
}), takeUntilDestroyed(this.destroyRef));
|
|
2825
|
+
}
|
|
2799
2826
|
/**
|
|
2800
2827
|
* Angular 20: Helper methods for state management
|
|
2801
2828
|
*/
|
|
@@ -3127,6 +3154,7 @@ class CideEleFileInputComponent {
|
|
|
3127
3154
|
placeholderIcon = '📷';
|
|
3128
3155
|
autoUpload = false;
|
|
3129
3156
|
uploadData = {};
|
|
3157
|
+
multipleFileUpload = false; // New property for multiple file upload mode
|
|
3130
3158
|
// Traditional @Output() decorators
|
|
3131
3159
|
fileChange = new EventEmitter();
|
|
3132
3160
|
uploadSuccess = new EventEmitter();
|
|
@@ -3149,6 +3177,7 @@ class CideEleFileInputComponent {
|
|
|
3149
3177
|
placeholderIconSignal = signal(this.placeholderIcon, ...(ngDevMode ? [{ debugName: "placeholderIconSignal" }] : []));
|
|
3150
3178
|
autoUploadSignal = signal(this.autoUpload, ...(ngDevMode ? [{ debugName: "autoUploadSignal" }] : []));
|
|
3151
3179
|
uploadDataSignal = signal(this.uploadData, ...(ngDevMode ? [{ debugName: "uploadDataSignal" }] : []));
|
|
3180
|
+
multipleFileUploadSignal = signal(this.multipleFileUpload, ...(ngDevMode ? [{ debugName: "multipleFileUploadSignal" }] : []));
|
|
3152
3181
|
// Reactive state with signals
|
|
3153
3182
|
id = signal(Math.random().toString(36).substring(2, 10), ...(ngDevMode ? [{ debugName: "id" }] : []));
|
|
3154
3183
|
isUploading = signal(false, ...(ngDevMode ? [{ debugName: "isUploading" }] : []));
|
|
@@ -3159,6 +3188,7 @@ class CideEleFileInputComponent {
|
|
|
3159
3188
|
previewUrls = signal([], ...(ngDevMode ? [{ debugName: "previewUrls" }] : []));
|
|
3160
3189
|
uploadNotificationId = signal(null, ...(ngDevMode ? [{ debugName: "uploadNotificationId" }] : []));
|
|
3161
3190
|
isDragOver = signal(false, ...(ngDevMode ? [{ debugName: "isDragOver" }] : []));
|
|
3191
|
+
groupId = signal(null, ...(ngDevMode ? [{ debugName: "groupId" }] : [])); // Group ID for multiple file uploads
|
|
3162
3192
|
// Computed signals for better relationships
|
|
3163
3193
|
hasFiles = computed(() => this.files() !== null && this.files().length > 0, ...(ngDevMode ? [{ debugName: "hasFiles" }] : []));
|
|
3164
3194
|
canUpload = computed(() => this.hasFiles() && !this.isUploading() && !this.disabledSignal(), ...(ngDevMode ? [{ debugName: "canUpload" }] : []));
|
|
@@ -3221,6 +3251,44 @@ class CideEleFileInputComponent {
|
|
|
3221
3251
|
this.placeholderIconSignal.set(this.placeholderIcon);
|
|
3222
3252
|
this.autoUploadSignal.set(this.autoUpload);
|
|
3223
3253
|
this.uploadDataSignal.set(this.uploadData);
|
|
3254
|
+
this.multipleFileUploadSignal.set(this.multipleFileUpload);
|
|
3255
|
+
}
|
|
3256
|
+
ngOnChanges(changes) {
|
|
3257
|
+
// Angular 20: Update signals when @Input() values change
|
|
3258
|
+
if (changes['label'])
|
|
3259
|
+
this.labelSignal.set(this.label);
|
|
3260
|
+
if (changes['accept'])
|
|
3261
|
+
this.acceptSignal.set(this.accept);
|
|
3262
|
+
if (changes['multiple'])
|
|
3263
|
+
this.multipleSignal.set(this.multiple);
|
|
3264
|
+
if (changes['disabled'])
|
|
3265
|
+
this.disabledSignal.set(this.disabled);
|
|
3266
|
+
if (changes['required'])
|
|
3267
|
+
this.requiredSignal.set(this.required);
|
|
3268
|
+
if (changes['helperText'])
|
|
3269
|
+
this.helperTextSignal.set(this.helperText);
|
|
3270
|
+
if (changes['errorText'])
|
|
3271
|
+
this.errorTextSignal.set(this.errorText);
|
|
3272
|
+
if (changes['showPreview'])
|
|
3273
|
+
this.showPreviewSignal.set(this.showPreview);
|
|
3274
|
+
if (changes['previewWidth'])
|
|
3275
|
+
this.previewWidthSignal.set(this.previewWidth);
|
|
3276
|
+
if (changes['previewHeight'])
|
|
3277
|
+
this.previewHeightSignal.set(this.previewHeight);
|
|
3278
|
+
if (changes['previewBoxMode'])
|
|
3279
|
+
this.previewBoxModeSignal.set(this.previewBoxMode);
|
|
3280
|
+
if (changes['showFileName'])
|
|
3281
|
+
this.showFileNameSignal.set(this.showFileName);
|
|
3282
|
+
if (changes['placeholderText'])
|
|
3283
|
+
this.placeholderTextSignal.set(this.placeholderText);
|
|
3284
|
+
if (changes['placeholderIcon'])
|
|
3285
|
+
this.placeholderIconSignal.set(this.placeholderIcon);
|
|
3286
|
+
if (changes['autoUpload'])
|
|
3287
|
+
this.autoUploadSignal.set(this.autoUpload);
|
|
3288
|
+
if (changes['uploadData'])
|
|
3289
|
+
this.uploadDataSignal.set(this.uploadData);
|
|
3290
|
+
if (changes['multipleFileUpload'])
|
|
3291
|
+
this.multipleFileUploadSignal.set(this.multipleFileUpload);
|
|
3224
3292
|
}
|
|
3225
3293
|
writeValue(value) {
|
|
3226
3294
|
console.log('📝 [FileInput] writeValue called with:', value);
|
|
@@ -3278,8 +3346,14 @@ class CideEleFileInputComponent {
|
|
|
3278
3346
|
this.onTouched();
|
|
3279
3347
|
// Auto upload if enabled
|
|
3280
3348
|
if (this.autoUploadSignal() && selectedFiles && selectedFiles.length > 0) {
|
|
3281
|
-
|
|
3282
|
-
|
|
3349
|
+
if (this.multipleFileUploadSignal() && this.multipleSignal()) {
|
|
3350
|
+
console.log('🚀 [FileInput] Auto upload enabled for multiple files:', selectedFiles.length);
|
|
3351
|
+
this.uploadMultipleFiles(Array.from(selectedFiles));
|
|
3352
|
+
}
|
|
3353
|
+
else {
|
|
3354
|
+
console.log('🚀 [FileInput] Auto upload enabled, starting upload for:', selectedFiles[0].name);
|
|
3355
|
+
this.uploadFile(selectedFiles[0]);
|
|
3356
|
+
}
|
|
3283
3357
|
}
|
|
3284
3358
|
else {
|
|
3285
3359
|
console.log('⏸️ [FileInput] Auto upload disabled or no files');
|
|
@@ -3410,6 +3484,136 @@ class CideEleFileInputComponent {
|
|
|
3410
3484
|
}
|
|
3411
3485
|
});
|
|
3412
3486
|
}
|
|
3487
|
+
/**
|
|
3488
|
+
* Upload multiple files with group ID support
|
|
3489
|
+
* Generates a group ID if not provided and uploads all files with the same group ID
|
|
3490
|
+
*/
|
|
3491
|
+
uploadMultipleFiles(files) {
|
|
3492
|
+
console.log('📤 [FileInput] uploadMultipleFiles called for:', files.length, 'files');
|
|
3493
|
+
// Set upload status to 'start' before starting upload
|
|
3494
|
+
this.uploadStatus.set('start');
|
|
3495
|
+
this.isUploading.set(true);
|
|
3496
|
+
this.uploadProgress.set(0);
|
|
3497
|
+
this.uploadProgressChange.emit(0);
|
|
3498
|
+
// Make form control invalid during upload
|
|
3499
|
+
this.onChange(null);
|
|
3500
|
+
// Show initial progress notification
|
|
3501
|
+
const notificationId = this.notificationService.showProgress('🔄 Preparing multiple file upload...', 0, { duration: 0 });
|
|
3502
|
+
this.uploadNotificationId.set(notificationId);
|
|
3503
|
+
// Check if we already have a group ID from uploadData
|
|
3504
|
+
const existingGroupId = this.uploadDataSignal().groupId;
|
|
3505
|
+
if (existingGroupId) {
|
|
3506
|
+
console.log('🆔 [FileInput] Using existing group ID:', existingGroupId);
|
|
3507
|
+
this.groupId.set(existingGroupId);
|
|
3508
|
+
this.startMultipleFileUpload(files, existingGroupId);
|
|
3509
|
+
}
|
|
3510
|
+
else {
|
|
3511
|
+
console.log('🆔 [FileInput] No group ID provided, generating new one...');
|
|
3512
|
+
// Generate group ID first
|
|
3513
|
+
this.fileManagerService.generateObjectId().subscribe({
|
|
3514
|
+
next: (response) => {
|
|
3515
|
+
const newGroupId = response.objectId;
|
|
3516
|
+
console.log('🆔 [FileInput] Generated new group ID:', newGroupId);
|
|
3517
|
+
this.groupId.set(newGroupId);
|
|
3518
|
+
this.startMultipleFileUpload(files, newGroupId);
|
|
3519
|
+
},
|
|
3520
|
+
error: (error) => {
|
|
3521
|
+
console.error('❌ [FileInput] Failed to generate group ID:', error);
|
|
3522
|
+
this.uploadError.emit('Failed to generate group ID');
|
|
3523
|
+
this.isUploading.set(false);
|
|
3524
|
+
this.uploadStatus.set('error');
|
|
3525
|
+
const notificationId = this.uploadNotificationId();
|
|
3526
|
+
if (notificationId) {
|
|
3527
|
+
this.notificationService.remove(notificationId);
|
|
3528
|
+
}
|
|
3529
|
+
this.notificationService.error('❌ Failed to generate group ID for multiple file upload', { duration: 0 });
|
|
3530
|
+
this.uploadNotificationId.set(null);
|
|
3531
|
+
}
|
|
3532
|
+
});
|
|
3533
|
+
}
|
|
3534
|
+
}
|
|
3535
|
+
/**
|
|
3536
|
+
* Start uploading multiple files with the provided group ID
|
|
3537
|
+
*/
|
|
3538
|
+
startMultipleFileUpload(files, groupId) {
|
|
3539
|
+
console.log('🚀 [FileInput] Starting upload for', files.length, 'files with group ID:', groupId);
|
|
3540
|
+
let completedUploads = 0;
|
|
3541
|
+
let failedUploads = 0;
|
|
3542
|
+
const totalFiles = files.length;
|
|
3543
|
+
// Update upload data with group ID
|
|
3544
|
+
const uploadDataWithGroupId = {
|
|
3545
|
+
...this.uploadDataSignal(),
|
|
3546
|
+
groupId: groupId
|
|
3547
|
+
};
|
|
3548
|
+
files.forEach((file, index) => {
|
|
3549
|
+
this.fileManagerService.uploadFile(file, uploadDataWithGroupId, (progress) => {
|
|
3550
|
+
// Calculate overall progress
|
|
3551
|
+
const fileProgress = progress / totalFiles;
|
|
3552
|
+
const overallProgress = ((completedUploads * 100) + fileProgress) / totalFiles;
|
|
3553
|
+
this.uploadProgress.set(overallProgress);
|
|
3554
|
+
this.uploadProgressChange.emit(overallProgress);
|
|
3555
|
+
// Update progress notification
|
|
3556
|
+
const notificationId = this.uploadNotificationId();
|
|
3557
|
+
if (notificationId) {
|
|
3558
|
+
const progressMessage = `🔄 Uploading file ${index + 1} of ${totalFiles}...`;
|
|
3559
|
+
this.notificationService.updateProgress(notificationId, overallProgress, progressMessage);
|
|
3560
|
+
}
|
|
3561
|
+
}).pipe(takeUntilDestroyed(this.destroyRef)).subscribe({
|
|
3562
|
+
next: (response) => {
|
|
3563
|
+
completedUploads++;
|
|
3564
|
+
console.log(`✅ [FileInput] File ${index + 1}/${totalFiles} uploaded successfully`);
|
|
3565
|
+
// Check if all files are completed
|
|
3566
|
+
if (completedUploads + failedUploads === totalFiles) {
|
|
3567
|
+
this.handleMultipleUploadComplete(completedUploads, failedUploads, totalFiles, groupId);
|
|
3568
|
+
}
|
|
3569
|
+
},
|
|
3570
|
+
error: (error) => {
|
|
3571
|
+
failedUploads++;
|
|
3572
|
+
console.error(`❌ [FileInput] File ${index + 1}/${totalFiles} upload failed:`, error);
|
|
3573
|
+
// Check if all files are completed
|
|
3574
|
+
if (completedUploads + failedUploads === totalFiles) {
|
|
3575
|
+
this.handleMultipleUploadComplete(completedUploads, failedUploads, totalFiles, groupId);
|
|
3576
|
+
}
|
|
3577
|
+
}
|
|
3578
|
+
});
|
|
3579
|
+
});
|
|
3580
|
+
}
|
|
3581
|
+
/**
|
|
3582
|
+
* Handle completion of multiple file upload
|
|
3583
|
+
*/
|
|
3584
|
+
handleMultipleUploadComplete(completed, failed, total, groupId) {
|
|
3585
|
+
console.log(`📊 [FileInput] Multiple upload complete: ${completed}/${total} successful, ${failed} failed`);
|
|
3586
|
+
this.isUploading.set(false);
|
|
3587
|
+
this.uploadProgress.set(100);
|
|
3588
|
+
this.uploadProgressChange.emit(100);
|
|
3589
|
+
// Remove progress notification
|
|
3590
|
+
const notificationId = this.uploadNotificationId();
|
|
3591
|
+
if (notificationId) {
|
|
3592
|
+
this.notificationService.remove(notificationId);
|
|
3593
|
+
}
|
|
3594
|
+
this.uploadNotificationId.set(null);
|
|
3595
|
+
if (failed === 0) {
|
|
3596
|
+
// All files uploaded successfully
|
|
3597
|
+
this.uploadStatus.set('success');
|
|
3598
|
+
this.notificationService.success(`✅ All ${total} files uploaded successfully!`, { duration: 0 });
|
|
3599
|
+
// For multiple file upload, return the group ID as the form value
|
|
3600
|
+
this.onChange(groupId);
|
|
3601
|
+
this.uploadSuccess.emit(groupId);
|
|
3602
|
+
console.log('📝 [FileInput] Form control value set to group ID:', groupId);
|
|
3603
|
+
}
|
|
3604
|
+
else if (completed > 0) {
|
|
3605
|
+
// Some files uploaded successfully
|
|
3606
|
+
this.uploadStatus.set('error');
|
|
3607
|
+
this.notificationService.warning(`⚠️ ${completed}/${total} files uploaded. ${failed} failed.`, { duration: 0 });
|
|
3608
|
+
this.uploadError.emit(`${failed} out of ${total} files failed to upload`);
|
|
3609
|
+
}
|
|
3610
|
+
else {
|
|
3611
|
+
// All files failed
|
|
3612
|
+
this.uploadStatus.set('error');
|
|
3613
|
+
this.notificationService.error(`❌ All ${total} files failed to upload.`, { duration: 0 });
|
|
3614
|
+
this.uploadError.emit('All files failed to upload');
|
|
3615
|
+
}
|
|
3616
|
+
}
|
|
3413
3617
|
generatePreviews() {
|
|
3414
3618
|
// Clear existing previews
|
|
3415
3619
|
this.clearPreviews();
|
|
@@ -3717,7 +3921,7 @@ class CideEleFileInputComponent {
|
|
|
3717
3921
|
return null; // No validation errors
|
|
3718
3922
|
}
|
|
3719
3923
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: CideEleFileInputComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
3720
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.1.7", type: CideEleFileInputComponent, isStandalone: true, selector: "cide-ele-file-input", inputs: { label: "label", accept: "accept", multiple: "multiple", disabled: "disabled", required: "required", helperText: "helperText", errorText: "errorText", showPreview: "showPreview", previewWidth: "previewWidth", previewHeight: "previewHeight", previewBoxMode: "previewBoxMode", showFileName: "showFileName", placeholderText: "placeholderText", placeholderIcon: "placeholderIcon", autoUpload: "autoUpload", uploadData: "uploadData" }, outputs: { fileChange: "fileChange", uploadSuccess: "uploadSuccess", uploadError: "uploadError", uploadProgressChange: "uploadProgressChange" }, providers: [
|
|
3924
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.1.7", type: CideEleFileInputComponent, isStandalone: true, selector: "cide-ele-file-input", inputs: { label: "label", accept: "accept", multiple: "multiple", disabled: "disabled", required: "required", helperText: "helperText", errorText: "errorText", showPreview: "showPreview", previewWidth: "previewWidth", previewHeight: "previewHeight", previewBoxMode: "previewBoxMode", showFileName: "showFileName", placeholderText: "placeholderText", placeholderIcon: "placeholderIcon", autoUpload: "autoUpload", uploadData: "uploadData", multipleFileUpload: "multipleFileUpload" }, outputs: { fileChange: "fileChange", uploadSuccess: "uploadSuccess", uploadError: "uploadError", uploadProgressChange: "uploadProgressChange" }, providers: [
|
|
3721
3925
|
{
|
|
3722
3926
|
provide: NG_VALUE_ACCESSOR,
|
|
3723
3927
|
useExisting: CideEleFileInputComponent,
|
|
@@ -3728,7 +3932,7 @@ class CideEleFileInputComponent {
|
|
|
3728
3932
|
useExisting: CideEleFileInputComponent,
|
|
3729
3933
|
multi: true
|
|
3730
3934
|
}
|
|
3731
|
-
], ngImport: i0, template: "<div class=\"cide-file-input\">\n <!-- Label (shown when not in preview box mode or when preview box mode but no label override) -->\n @if (labelSignal() && !isPreviewBoxMode()) {\n <label class=\"cide-file-input-label\" [attr.for]=\"'cide-file-input-' + id()\">\n {{ labelSignal() }}@if (requiredSignal()) {<span class=\"cide-file-input-required\"> *</span>}\n </label>\n }\n \n <!-- Preview Box Mode -->\n @if (isPreviewBoxMode()) {\n <div class=\"cide-file-input-preview-box-container\">\n <!-- Hidden file input -->\n <input\n type=\"file\"\n [attr.id]=\"'cide-file-input-' + id()\"\n [attr.accept]=\"acceptSignal()\"\n [attr.multiple]=\"multipleSignal() ? true : null\"\n [disabled]=\"disabledSignal()\"\n (change)=\"onFileSelected($event)\"\n class=\"cide-file-input-hidden\"\n />\n \n <!-- Preview Box -->\n <div \n class=\"cide-file-input-preview-box\"\n [class.cide-file-input-preview-box-disabled]=\"disabledSignal()\"\n [class.cide-file-input-preview-box-has-image]=\"hasImages()\"\n [class.cide-file-input-preview-box-drag-over]=\"isDragOver()\"\n [style.width]=\"previewWidthSignal()\"\n [style.height]=\"previewHeightSignal()\"\n (click)=\"triggerFileSelect()\"\n (dragover)=\"onDragOver($event)\"\n (dragenter)=\"onDragEnter($event)\"\n (dragleave)=\"onDragLeave($event)\"\n (drop)=\"onDrop($event)\"\n [attr.title]=\"disabledSignal() ? 'File selection disabled' : placeholderTextSignal()\">\n \n <!-- No Image State -->\n @if (!hasImages()) {\n <div class=\"cide-file-input-preview-box-placeholder\">\n <div class=\"cide-file-input-preview-box-icon\">\n <cide-ele-icon>{{ isDragOver() ? '\uD83D\uDCC1' : placeholderIconSignal() }}</cide-ele-icon>\n </div>\n <div class=\"cide-file-input-preview-box-text\">\n {{ isDragOver() ? 'Drop files here...' : placeholderTextSignal() }}\n </div>\n </div>\n }\n \n <!-- Image Preview State -->\n @if (hasImages()) {\n <div class=\"cide-file-input-preview-box-content\">\n <img \n [src]=\"previewUrls()[0]\" \n [alt]=\"fileNames()[0] || 'Preview image'\"\n class=\"cide-file-input-preview-box-image\">\n <div class=\"cide-file-input-preview-box-overlay\">\n <div class=\"cide-file-input-preview-box-overlay-text\">Click to change</div>\n </div>\n @if (!disabledSignal()) {\n <button \n type=\"button\" \n class=\"cide-file-input-preview-box-remove\"\n (click)=\"clearFiles(); $event.stopPropagation()\"\n title=\"Remove image\">\n \u00D7\n </button>\n }\n </div>\n }\n </div>\n \n <!-- File name display for preview box mode -->\n @if (hasImages() && fileNames().length && showFileNameSignal()) {\n <div class=\"cide-file-input-preview-box-filename\">\n {{ fileNames()[0] }}\n </div>\n }\n </div>\n }\n\n <!-- Standard Mode -->\n @if (!isPreviewBoxMode()) {\n <div \n class=\"cide-file-input-wrapper\"\n [class.cide-file-input-drag-over]=\"isDragOver()\"\n (dragover)=\"onDragOver($event)\"\n (dragenter)=\"onDragEnter($event)\"\n (dragleave)=\"onDragLeave($event)\"\n (drop)=\"onDrop($event)\">\n <input\n type=\"file\"\n [attr.id]=\"'cide-file-input-' + id()\"\n [attr.accept]=\"acceptSignal()\"\n [attr.multiple]=\"multipleSignal() ? true : null\"\n [disabled]=\"disabledSignal()\"\n (change)=\"onFileSelected($event)\"\n class=\"cide-file-input-element\"\n />\n @if (hasFiles()) {\n <button type=\"button\" class=\"cide-file-input-clear\" (click)=\"clearFiles()\">\n Clear\n </button>\n }\n </div>\n @if (hasFiles() && !isPreviewBoxMode()) {\n <div class=\"cide-file-input-files\">\n @for (name of fileNames(); track name) {\n <span>{{ name }}</span>\n }\n <!-- Angular 20: Display file size using new computed values -->\n @if (totalFileSize() > 0) {\n <div class=\"cide-file-input-size\">\n Total size: {{ fileSizeInMB() }} MB\n </div>\n }\n </div>\n }\n }\n \n <!-- Image Preview Section (only for standard mode) -->\n @if (isImagePreviewAvailable() && !isPreviewBoxMode()) {\n <div class=\"cide-file-input-preview\">\n <div class=\"cide-file-input-preview-label\">Preview:</div>\n <div class=\"cide-file-input-preview-container\">\n @for (previewUrl of previewUrls(); track previewUrl; let i = $index) {\n <div \n class=\"cide-file-input-preview-item\"\n [style.width]=\"previewWidthSignal()\"\n [style.height]=\"previewHeightSignal()\">\n <button \n type=\"button\" \n class=\"cide-file-input-preview-remove\"\n (click)=\"removePreview(i)\"\n title=\"Remove image\">\n \u00D7\n </button>\n <img \n [src]=\"previewUrl\" \n [alt]=\"fileNames()[i] || 'Preview image'\"\n class=\"cide-file-input-preview-image\"\n loading=\"lazy\">\n <div class=\"cide-file-input-preview-filename\">{{ fileNames()[i] }}</div>\n </div>\n }\n </div>\n </div>\n }\n \n @if (errorTextSignal()) {\n <div class=\"cide-file-input-error\">{{ errorTextSignal() }}</div>\n }\n @if (helperTextSignal() && !errorTextSignal()) {\n <div class=\"cide-file-input-helper\">{{ helperTextSignal() }}</div>\n }\n</div> ", styles: [".cide-file-input{display:flex;flex-direction:column;gap:.5rem}.cide-file-input-label{font-weight:500;margin-bottom:.25rem}.cide-file-input-required{color:#d32f2f;font-weight:700}.cide-file-input-wrapper{display:flex;align-items:center;gap:.5rem;border:2px dashed transparent;border-radius:.5rem;padding:.5rem;transition:all .2s ease-in-out}.cide-file-input-wrapper.cide-file-input-drag-over{border-color:#3b82f6;background-color:#eff6ff;transform:scale(1.02)}.cide-file-input-element{flex:1}.cide-file-input-clear{background:none;border:none;color:#d32f2f;cursor:pointer;font-size:.9rem}.cide-file-input-files{font-size:.95rem;color:#333;margin-top:.25rem}.cide-file-input-size{margin-top:.5rem;padding:.25rem .5rem;background-color:#f3f4f6;border-radius:.25rem;font-size:.75rem;color:#4b5563;font-weight:500}.cide-file-input-error{color:#d32f2f;font-size:.9rem}.cide-file-input-helper{color:#666;font-size:.9rem}.cide-file-input-preview{margin-top:.75rem;padding:.75rem;background-color:#f8f9fa;border:1px solid #e1e5e9;border-radius:.375rem}.cide-file-input-preview-label{font-weight:500;margin-bottom:.5rem;color:#374151;font-size:.875rem}.cide-file-input-preview-container{display:flex;flex-wrap:wrap;gap:.75rem}.cide-file-input-preview-item{position:relative;display:flex;flex-direction:column;border:1px solid #d1d5db;border-radius:.5rem;overflow:hidden;background-color:#fff;box-shadow:0 1px 3px #0000001a;transition:box-shadow .2s ease-in-out}.cide-file-input-preview-item:hover{box-shadow:0 4px 6px -1px #0000001a}.cide-file-input-preview-image{width:100%;height:calc(100% - 2rem);object-fit:cover;object-position:center;background-color:#f3f4f6}.cide-file-input-preview-filename{padding:.375rem .5rem;background-color:#f9fafbf2;border-top:1px solid #e5e7eb;font-size:.75rem;color:#374151;text-align:center;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;min-height:2rem;display:flex;align-items:center;justify-content:center}.cide-file-input-preview-remove{position:absolute;top:.25rem;right:.25rem;width:1.5rem;height:1.5rem;background-color:#ef4444e6;color:#fff;border:none;border-radius:50%;font-size:1rem;font-weight:700;line-height:1;cursor:pointer;display:flex;align-items:center;justify-content:center;z-index:10;transition:all .2s ease-in-out}.cide-file-input-preview-remove:hover{background-color:#dc2626f2;transform:scale(1.1)}.cide-file-input-preview-remove:focus{outline:2px solid #3b82f6;outline-offset:2px}.cide-file-input-hidden{display:none}.cide-file-input-preview-box-container{display:flex;flex-direction:column;gap:.5rem}.cide-file-input-preview-box{position:relative;border:2px dashed #d1d5db;border-radius:.5rem;cursor:pointer;background-color:#f9fafb;display:flex;align-items:center;justify-content:center;overflow:hidden;transition:all .2s ease-in-out}.cide-file-input-preview-box:hover{border-color:#3b82f6;background-color:#eff6ff}.cide-file-input-preview-box.cide-file-input-preview-box-disabled{cursor:not-allowed;opacity:.6;background-color:#f3f4f6}.cide-file-input-preview-box.cide-file-input-preview-box-disabled:hover{border-color:#d1d5db;background-color:#f3f4f6}.cide-file-input-preview-box.cide-file-input-preview-box-has-image{border-style:solid;border-color:#e5e7eb;padding:0}.cide-file-input-preview-box.cide-file-input-preview-box-has-image:hover{border-color:#3b82f6}.cide-file-input-preview-box.cide-file-input-preview-box-has-image:hover .cide-file-input-preview-box-overlay{opacity:1}.cide-file-input-preview-box.cide-file-input-preview-box-drag-over{border-color:#3b82f6!important;background-color:#eff6ff!important;transform:scale(1.02);box-shadow:0 0 0 4px #3b82f61a}.cide-file-input-preview-box.cide-file-input-preview-box-drag-over .cide-file-input-preview-box-placeholder .cide-file-input-preview-box-icon{color:#3b82f6;transform:scale(1.1)}.cide-file-input-preview-box.cide-file-input-preview-box-drag-over .cide-file-input-preview-box-placeholder .cide-file-input-preview-box-text{color:#3b82f6;font-weight:600}.cide-file-input-preview-box-placeholder{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:.5rem;padding:1rem;text-align:center}.cide-file-input-preview-box-icon{font-size:2rem;color:#6b7280}.cide-file-input-preview-box-text{font-size:.875rem;color:#6b7280;font-weight:500}.cide-file-input-preview-box-content{position:relative;width:100%;height:100%;display:flex;align-items:center;justify-content:center}.cide-file-input-preview-box-image{width:100%;height:100%;object-fit:cover;object-position:center}.cide-file-input-preview-box-overlay{position:absolute;inset:0;background-color:#0009;display:flex;align-items:center;justify-content:center;opacity:0;transition:opacity .2s ease-in-out}.cide-file-input-preview-box-overlay-text{color:#fff;font-size:.875rem;font-weight:500;text-align:center}.cide-file-input-preview-box-remove{position:absolute;top:.375rem;right:.375rem;width:1.5rem;height:1.5rem;background-color:#ef4444e6;color:#fff;border:none;border-radius:50%;font-size:1rem;font-weight:700;line-height:1;cursor:pointer;display:flex;align-items:center;justify-content:center;z-index:20;transition:all .2s ease-in-out}.cide-file-input-preview-box-remove:hover{background-color:#dc2626f2;transform:scale(1.1)}.cide-file-input-preview-box-remove:focus{outline:2px solid #3b82f6;outline-offset:2px}.cide-file-input-preview-box-filename{font-size:.75rem;color:#374151;text-align:center;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;padding:.25rem .5rem;background-color:#f3f4f6;border-radius:.25rem;margin-top:.25rem}@media (max-width: 640px){.cide-file-input-preview-container{justify-content:center}.cide-file-input-preview-item{min-width:120px;max-width:150px}.cide-file-input-preview-box-icon{font-size:1.5rem}.cide-file-input-preview-box-text{font-size:.75rem}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "component", type: CideIconComponent, selector: "cide-ele-icon", inputs: ["size", "type", "toolTip"] }] });
|
|
3935
|
+
], usesOnChanges: true, ngImport: i0, template: "<div class=\"cide-file-input\">\n <!-- Label (shown when not in preview box mode or when preview box mode but no label override) -->\n @if (labelSignal() && !isPreviewBoxMode()) {\n <label class=\"cide-file-input-label\" [attr.for]=\"'cide-file-input-' + id()\">\n {{ labelSignal() }}@if (requiredSignal()) {<span class=\"cide-file-input-required\"> *</span>}\n </label>\n }\n \n <!-- Preview Box Mode -->\n @if (isPreviewBoxMode()) {\n <div class=\"cide-file-input-preview-box-container\">\n <!-- Hidden file input -->\n <input\n type=\"file\"\n [attr.id]=\"'cide-file-input-' + id()\"\n [attr.accept]=\"acceptSignal()\"\n [attr.multiple]=\"multipleSignal() ? true : null\"\n [disabled]=\"disabledSignal()\"\n (change)=\"onFileSelected($event)\"\n class=\"cide-file-input-hidden\"\n />\n \n <!-- Preview Box -->\n <div \n class=\"cide-file-input-preview-box\"\n [class.cide-file-input-preview-box-disabled]=\"disabledSignal()\"\n [class.cide-file-input-preview-box-has-image]=\"hasImages()\"\n [class.cide-file-input-preview-box-drag-over]=\"isDragOver()\"\n [style.width]=\"previewWidthSignal()\"\n [style.height]=\"previewHeightSignal()\"\n (click)=\"triggerFileSelect()\"\n (dragover)=\"onDragOver($event)\"\n (dragenter)=\"onDragEnter($event)\"\n (dragleave)=\"onDragLeave($event)\"\n (drop)=\"onDrop($event)\"\n [attr.title]=\"disabledSignal() ? 'File selection disabled' : placeholderTextSignal()\">\n \n <!-- No Image State -->\n @if (!hasImages()) {\n <div class=\"cide-file-input-preview-box-placeholder\">\n <div class=\"cide-file-input-preview-box-icon\">\n <cide-ele-icon>{{ isDragOver() ? '\uD83D\uDCC1' : placeholderIconSignal() }}</cide-ele-icon>\n </div>\n <div class=\"cide-file-input-preview-box-text\">\n {{ isDragOver() ? 'Drop files here...' : placeholderTextSignal() }}\n </div>\n </div>\n }\n \n <!-- Image Preview State -->\n @if (hasImages()) {\n <div class=\"cide-file-input-preview-box-content\">\n <img \n [src]=\"previewUrls()[0]\" \n [alt]=\"fileNames()[0] || 'Preview image'\"\n class=\"cide-file-input-preview-box-image\">\n <div class=\"cide-file-input-preview-box-overlay\">\n <div class=\"cide-file-input-preview-box-overlay-text\">Click to change</div>\n </div>\n @if (!disabledSignal()) {\n <button \n type=\"button\" \n class=\"cide-file-input-preview-box-remove\"\n (click)=\"clearFiles(); $event.stopPropagation()\"\n title=\"Remove image\">\n \u00D7\n </button>\n }\n </div>\n }\n </div>\n \n <!-- File name display for preview box mode -->\n @if (hasImages() && fileNames().length && showFileNameSignal()) {\n <div class=\"cide-file-input-preview-box-filename\">\n {{ fileNames()[0] }}\n </div>\n }\n </div>\n }\n\n <!-- Standard Mode -->\n @if (!isPreviewBoxMode()) {\n <div \n class=\"cide-file-input-wrapper\"\n [class.cide-file-input-drag-over]=\"isDragOver()\"\n (dragover)=\"onDragOver($event)\"\n (dragenter)=\"onDragEnter($event)\"\n (dragleave)=\"onDragLeave($event)\"\n (drop)=\"onDrop($event)\">\n <input\n type=\"file\"\n [attr.id]=\"'cide-file-input-' + id()\"\n [attr.accept]=\"acceptSignal()\"\n [attr.multiple]=\"multipleSignal() ? true : null\"\n [disabled]=\"disabledSignal()\"\n (change)=\"onFileSelected($event)\"\n class=\"cide-file-input-element\"\n />\n @if (hasFiles()) {\n <button type=\"button\" class=\"cide-file-input-clear\" (click)=\"clearFiles()\">\n Clear\n </button>\n }\n </div>\n @if (hasFiles() && !isPreviewBoxMode()) {\n <div class=\"cide-file-input-files\">\n @for (name of fileNames(); track name) {\n <span>{{ name }}</span>\n }\n <!-- Angular 20: Display file size using new computed values -->\n @if (totalFileSize() > 0) {\n <div class=\"cide-file-input-size\">\n Total size: {{ fileSizeInMB() }} MB\n </div>\n }\n </div>\n }\n }\n \n <!-- Image Preview Section (only for standard mode) -->\n @if (isImagePreviewAvailable() && !isPreviewBoxMode()) {\n <div class=\"cide-file-input-preview\">\n <div class=\"cide-file-input-preview-label\">Preview:</div>\n <div class=\"cide-file-input-preview-container\">\n @for (previewUrl of previewUrls(); track previewUrl; let i = $index) {\n <div \n class=\"cide-file-input-preview-item\"\n [style.width]=\"previewWidthSignal()\"\n [style.height]=\"previewHeightSignal()\">\n <button \n type=\"button\" \n class=\"cide-file-input-preview-remove\"\n (click)=\"removePreview(i)\"\n title=\"Remove image\">\n \u00D7\n </button>\n <img \n [src]=\"previewUrl\" \n [alt]=\"fileNames()[i] || 'Preview image'\"\n class=\"cide-file-input-preview-image\"\n loading=\"lazy\">\n <div class=\"cide-file-input-preview-filename\">{{ fileNames()[i] }}</div>\n </div>\n }\n </div>\n </div>\n }\n \n @if (errorTextSignal()) {\n <div class=\"cide-file-input-error\">{{ errorTextSignal() }}</div>\n }\n @if (helperTextSignal() && !errorTextSignal()) {\n <div class=\"cide-file-input-helper\">{{ helperTextSignal() }}</div>\n }\n</div> ", styles: [".cide-file-input{display:flex;flex-direction:column;gap:.5rem}.cide-file-input-label{font-weight:500;margin-bottom:.25rem}.cide-file-input-required{color:#d32f2f;font-weight:700}.cide-file-input-wrapper{display:flex;align-items:center;gap:.5rem;border:2px dashed transparent;border-radius:.5rem;padding:.5rem;transition:all .2s ease-in-out}.cide-file-input-wrapper.cide-file-input-drag-over{border-color:#3b82f6;background-color:#eff6ff;transform:scale(1.02)}.cide-file-input-element{flex:1}.cide-file-input-clear{background:none;border:none;color:#d32f2f;cursor:pointer;font-size:.9rem}.cide-file-input-files{font-size:.95rem;color:#333;margin-top:.25rem}.cide-file-input-size{margin-top:.5rem;padding:.25rem .5rem;background-color:#f3f4f6;border-radius:.25rem;font-size:.75rem;color:#4b5563;font-weight:500}.cide-file-input-error{color:#d32f2f;font-size:.9rem}.cide-file-input-helper{color:#666;font-size:.9rem}.cide-file-input-preview{margin-top:.75rem;padding:.75rem;background-color:#f8f9fa;border:1px solid #e1e5e9;border-radius:.375rem}.cide-file-input-preview-label{font-weight:500;margin-bottom:.5rem;color:#374151;font-size:.875rem}.cide-file-input-preview-container{display:flex;flex-wrap:wrap;gap:.75rem}.cide-file-input-preview-item{position:relative;display:flex;flex-direction:column;border:1px solid #d1d5db;border-radius:.5rem;overflow:hidden;background-color:#fff;box-shadow:0 1px 3px #0000001a;transition:box-shadow .2s ease-in-out}.cide-file-input-preview-item:hover{box-shadow:0 4px 6px -1px #0000001a}.cide-file-input-preview-image{width:100%;height:calc(100% - 2rem);object-fit:cover;object-position:center;background-color:#f3f4f6}.cide-file-input-preview-filename{padding:.375rem .5rem;background-color:#f9fafbf2;border-top:1px solid #e5e7eb;font-size:.75rem;color:#374151;text-align:center;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;min-height:2rem;display:flex;align-items:center;justify-content:center}.cide-file-input-preview-remove{position:absolute;top:.25rem;right:.25rem;width:1.5rem;height:1.5rem;background-color:#ef4444e6;color:#fff;border:none;border-radius:50%;font-size:1rem;font-weight:700;line-height:1;cursor:pointer;display:flex;align-items:center;justify-content:center;z-index:10;transition:all .2s ease-in-out}.cide-file-input-preview-remove:hover{background-color:#dc2626f2;transform:scale(1.1)}.cide-file-input-preview-remove:focus{outline:2px solid #3b82f6;outline-offset:2px}.cide-file-input-hidden{display:none}.cide-file-input-preview-box-container{display:flex;flex-direction:column;gap:.5rem}.cide-file-input-preview-box{position:relative;border:2px dashed #d1d5db;border-radius:.5rem;cursor:pointer;background-color:#f9fafb;display:flex;align-items:center;justify-content:center;overflow:hidden;transition:all .2s ease-in-out}.cide-file-input-preview-box:hover{border-color:#3b82f6;background-color:#eff6ff}.cide-file-input-preview-box.cide-file-input-preview-box-disabled{cursor:not-allowed;opacity:.6;background-color:#f3f4f6}.cide-file-input-preview-box.cide-file-input-preview-box-disabled:hover{border-color:#d1d5db;background-color:#f3f4f6}.cide-file-input-preview-box.cide-file-input-preview-box-has-image{border-style:solid;border-color:#e5e7eb;padding:0}.cide-file-input-preview-box.cide-file-input-preview-box-has-image:hover{border-color:#3b82f6}.cide-file-input-preview-box.cide-file-input-preview-box-has-image:hover .cide-file-input-preview-box-overlay{opacity:1}.cide-file-input-preview-box.cide-file-input-preview-box-drag-over{border-color:#3b82f6!important;background-color:#eff6ff!important;transform:scale(1.02);box-shadow:0 0 0 4px #3b82f61a}.cide-file-input-preview-box.cide-file-input-preview-box-drag-over .cide-file-input-preview-box-placeholder .cide-file-input-preview-box-icon{color:#3b82f6;transform:scale(1.1)}.cide-file-input-preview-box.cide-file-input-preview-box-drag-over .cide-file-input-preview-box-placeholder .cide-file-input-preview-box-text{color:#3b82f6;font-weight:600}.cide-file-input-preview-box-placeholder{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:.5rem;padding:1rem;text-align:center}.cide-file-input-preview-box-icon{font-size:2rem;color:#6b7280}.cide-file-input-preview-box-text{font-size:.875rem;color:#6b7280;font-weight:500}.cide-file-input-preview-box-content{position:relative;width:100%;height:100%;display:flex;align-items:center;justify-content:center}.cide-file-input-preview-box-image{width:100%;height:100%;object-fit:cover;object-position:center}.cide-file-input-preview-box-overlay{position:absolute;inset:0;background-color:#0009;display:flex;align-items:center;justify-content:center;opacity:0;transition:opacity .2s ease-in-out}.cide-file-input-preview-box-overlay-text{color:#fff;font-size:.875rem;font-weight:500;text-align:center}.cide-file-input-preview-box-remove{position:absolute;top:.375rem;right:.375rem;width:1.5rem;height:1.5rem;background-color:#ef4444e6;color:#fff;border:none;border-radius:50%;font-size:1rem;font-weight:700;line-height:1;cursor:pointer;display:flex;align-items:center;justify-content:center;z-index:20;transition:all .2s ease-in-out}.cide-file-input-preview-box-remove:hover{background-color:#dc2626f2;transform:scale(1.1)}.cide-file-input-preview-box-remove:focus{outline:2px solid #3b82f6;outline-offset:2px}.cide-file-input-preview-box-filename{font-size:.75rem;color:#374151;text-align:center;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;padding:.25rem .5rem;background-color:#f3f4f6;border-radius:.25rem;margin-top:.25rem}@media (max-width: 640px){.cide-file-input-preview-container{justify-content:center}.cide-file-input-preview-item{min-width:120px;max-width:150px}.cide-file-input-preview-box-icon{font-size:1.5rem}.cide-file-input-preview-box-text{font-size:.75rem}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "component", type: CideIconComponent, selector: "cide-ele-icon", inputs: ["size", "type", "toolTip"] }] });
|
|
3732
3936
|
}
|
|
3733
3937
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: CideEleFileInputComponent, decorators: [{
|
|
3734
3938
|
type: Component,
|
|
@@ -3776,6 +3980,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.7", ngImpor
|
|
|
3776
3980
|
type: Input
|
|
3777
3981
|
}], uploadData: [{
|
|
3778
3982
|
type: Input
|
|
3983
|
+
}], multipleFileUpload: [{
|
|
3984
|
+
type: Input
|
|
3779
3985
|
}], fileChange: [{
|
|
3780
3986
|
type: Output
|
|
3781
3987
|
}], uploadSuccess: [{
|
|
@@ -4811,11 +5017,13 @@ class CideEleDataGridComponent {
|
|
|
4811
5017
|
if (this.isDragDropEnabled()) {
|
|
4812
5018
|
// Get the full dataset from the config (not just displayedData)
|
|
4813
5019
|
const fullData = this.mergedConfig().data || [];
|
|
5020
|
+
// Flatten the data to include all items (parents and children) for hierarchical structures
|
|
5021
|
+
const flattenedData = this.flattenAllDataForOrderTracking(fullData);
|
|
4814
5022
|
// Completely build the order tracking from current data
|
|
4815
5023
|
this.rowOrderMap.clear();
|
|
4816
5024
|
this.initialDataOrderIds = [];
|
|
4817
|
-
// Build the order tracking with
|
|
4818
|
-
|
|
5025
|
+
// Build the order tracking with flattened data
|
|
5026
|
+
flattenedData.forEach((item, index) => {
|
|
4819
5027
|
const itemId = this.getItemId(item);
|
|
4820
5028
|
if (itemId) {
|
|
4821
5029
|
const actualOrder = this.getItemOrder(item);
|
|
@@ -4828,7 +5036,7 @@ class CideEleDataGridComponent {
|
|
|
4828
5036
|
});
|
|
4829
5037
|
// Clear any existing local reordered data
|
|
4830
5038
|
this.localReorderedData = [];
|
|
4831
|
-
console.log('🔍 Initial order tracking built from
|
|
5039
|
+
console.log('🔍 Initial order tracking built from flattened dataset:', this.initialDataOrderIds.length, 'items (including children)');
|
|
4832
5040
|
console.log('🔍 Initial order map created with actual order values:', Array.from(this.rowOrderMap.entries()));
|
|
4833
5041
|
}
|
|
4834
5042
|
}
|
|
@@ -4839,11 +5047,13 @@ class CideEleDataGridComponent {
|
|
|
4839
5047
|
if (this.isDragDropEnabled()) {
|
|
4840
5048
|
// Get the current full dataset
|
|
4841
5049
|
const fullData = this.mergedConfig().data || [];
|
|
5050
|
+
// Flatten the data to include all items (parents and children) for hierarchical structures
|
|
5051
|
+
const flattenedData = this.flattenAllDataForOrderTracking(fullData);
|
|
4842
5052
|
// Completely rebuild the order tracking from current data
|
|
4843
5053
|
this.rowOrderMap.clear();
|
|
4844
5054
|
this.initialDataOrderIds = [];
|
|
4845
|
-
// Rebuild the order tracking with
|
|
4846
|
-
|
|
5055
|
+
// Rebuild the order tracking with flattened data
|
|
5056
|
+
flattenedData.forEach((item, index) => {
|
|
4847
5057
|
const itemId = this.getItemId(item);
|
|
4848
5058
|
if (itemId) {
|
|
4849
5059
|
const actualOrder = this.getItemOrder(item);
|
|
@@ -5663,15 +5873,18 @@ class CideEleDataGridComponent {
|
|
|
5663
5873
|
}
|
|
5664
5874
|
/**
|
|
5665
5875
|
* Reset the row order map to original positions (for reset action)
|
|
5876
|
+
* Includes all items from hierarchical structure (parents and children)
|
|
5666
5877
|
*/
|
|
5667
5878
|
resetRowOrderMap() {
|
|
5668
5879
|
// Get the current full dataset from the config (not cached data)
|
|
5669
5880
|
const fullData = this.mergedConfig().data || [];
|
|
5881
|
+
// Flatten the data to include all items (parents and children) for hierarchical structures
|
|
5882
|
+
const flattenedData = this.flattenAllDataForOrderTracking(fullData);
|
|
5670
5883
|
// Completely rebuild the order tracking from current data
|
|
5671
5884
|
this.rowOrderMap.clear();
|
|
5672
5885
|
this.initialDataOrderIds = [];
|
|
5673
|
-
// Rebuild the order tracking with
|
|
5674
|
-
|
|
5886
|
+
// Rebuild the order tracking with flattened data
|
|
5887
|
+
flattenedData.forEach((item, index) => {
|
|
5675
5888
|
const itemId = this.getItemId(item);
|
|
5676
5889
|
if (itemId) {
|
|
5677
5890
|
const actualOrder = this.getItemOrder(item);
|
|
@@ -5685,19 +5898,22 @@ class CideEleDataGridComponent {
|
|
|
5685
5898
|
// Clear any local reordered data
|
|
5686
5899
|
this.localReorderedData = [];
|
|
5687
5900
|
this.hasOrderChanged.set(false);
|
|
5688
|
-
console.log('🔍 Row order map completely rebuilt from
|
|
5901
|
+
console.log('🔍 Row order map completely rebuilt from flattened data:', this.initialDataOrderIds.length, 'items (including children)');
|
|
5689
5902
|
}
|
|
5690
5903
|
/**
|
|
5691
5904
|
* Update the row order map baseline to current positions (for save action)
|
|
5905
|
+
* Includes all items from hierarchical structure (parents and children)
|
|
5692
5906
|
*/
|
|
5693
5907
|
updateRowOrderMapBaseline() {
|
|
5694
5908
|
// Get the current full dataset from the config
|
|
5695
5909
|
const fullData = this.mergedConfig().data || [];
|
|
5910
|
+
// Flatten the data to include all items (parents and children) for hierarchical structures
|
|
5911
|
+
const flattenedData = this.flattenAllDataForOrderTracking(fullData);
|
|
5696
5912
|
// Completely rebuild the order tracking from current data
|
|
5697
5913
|
this.rowOrderMap.clear();
|
|
5698
5914
|
this.initialDataOrderIds = [];
|
|
5699
|
-
// Rebuild the order tracking with
|
|
5700
|
-
|
|
5915
|
+
// Rebuild the order tracking with flattened data
|
|
5916
|
+
flattenedData.forEach((item, index) => {
|
|
5701
5917
|
const itemId = this.getItemId(item);
|
|
5702
5918
|
if (itemId) {
|
|
5703
5919
|
const actualOrder = this.getItemOrder(item);
|
|
@@ -5708,18 +5924,21 @@ class CideEleDataGridComponent {
|
|
|
5708
5924
|
});
|
|
5709
5925
|
}
|
|
5710
5926
|
});
|
|
5711
|
-
console.log('🔍 Row order map baseline completely rebuilt from
|
|
5927
|
+
console.log('🔍 Row order map baseline completely rebuilt from flattened data:', this.initialDataOrderIds.length, 'items (including children)');
|
|
5712
5928
|
}
|
|
5713
5929
|
/**
|
|
5714
5930
|
* Get the current order array from the row order map
|
|
5931
|
+
* Includes all items from hierarchical structure (parents and children)
|
|
5715
5932
|
*/
|
|
5716
5933
|
getCurrentOrderFromMap() {
|
|
5717
5934
|
const orderedItems = [];
|
|
5718
5935
|
// Get the full dataset from the config (not just displayedData)
|
|
5719
5936
|
const fullData = this.mergedConfig().data || [];
|
|
5720
|
-
//
|
|
5937
|
+
// Flatten the data to include all items (parents and children) for hierarchical structures
|
|
5938
|
+
const flattenedData = this.flattenAllDataForOrderTracking(fullData);
|
|
5939
|
+
// Collect all items with their new positions from the flattened dataset
|
|
5721
5940
|
this.rowOrderMap.forEach((orderInfo, itemId) => {
|
|
5722
|
-
const item =
|
|
5941
|
+
const item = flattenedData.find(dataItem => this.getItemId(dataItem) === itemId);
|
|
5723
5942
|
if (item) {
|
|
5724
5943
|
orderedItems.push({ item, newPosition: orderInfo.newPosition });
|
|
5725
5944
|
}
|
|
@@ -5731,14 +5950,17 @@ class CideEleDataGridComponent {
|
|
|
5731
5950
|
}
|
|
5732
5951
|
/**
|
|
5733
5952
|
* Get only the items that have actually changed order
|
|
5953
|
+
* Includes all items from hierarchical structure (parents and children)
|
|
5734
5954
|
*/
|
|
5735
5955
|
getChangedOrders() {
|
|
5736
5956
|
const changedItems = [];
|
|
5737
5957
|
// Get the full dataset from the config
|
|
5738
5958
|
const fullData = this.mergedConfig().data || [];
|
|
5959
|
+
// Flatten the data to include all items (parents and children) for hierarchical structures
|
|
5960
|
+
const flattenedData = this.flattenAllDataForOrderTracking(fullData);
|
|
5739
5961
|
// Check each item to see if its position has changed
|
|
5740
5962
|
this.rowOrderMap.forEach((orderInfo, itemId) => {
|
|
5741
|
-
const item =
|
|
5963
|
+
const item = flattenedData.find(dataItem => this.getItemId(dataItem) === itemId);
|
|
5742
5964
|
if (item && orderInfo.oldPosition !== orderInfo.newPosition) {
|
|
5743
5965
|
changedItems.push(item);
|
|
5744
5966
|
console.log('🔍 Item changed order:', itemId, 'from', orderInfo.oldPosition, 'to', orderInfo.newPosition);
|
|
@@ -5746,6 +5968,30 @@ class CideEleDataGridComponent {
|
|
|
5746
5968
|
});
|
|
5747
5969
|
return changedItems;
|
|
5748
5970
|
}
|
|
5971
|
+
/**
|
|
5972
|
+
* Flatten all data for order tracking (includes all hierarchical children)
|
|
5973
|
+
* This method ensures that all items (parents and children) are included in order tracking
|
|
5974
|
+
*/
|
|
5975
|
+
flattenAllDataForOrderTracking(data) {
|
|
5976
|
+
const flattenedItems = [];
|
|
5977
|
+
const flattenItems = (items) => {
|
|
5978
|
+
items.forEach(item => {
|
|
5979
|
+
flattenedItems.push(item);
|
|
5980
|
+
// Check if item has children (for hierarchical data)
|
|
5981
|
+
const treeConfig = this.mergedConfig().tree;
|
|
5982
|
+
if (treeConfig?.enabled) {
|
|
5983
|
+
const childrenKey = treeConfig.childrenKey || 'children';
|
|
5984
|
+
const children = this.getNestedValue(item, childrenKey) || [];
|
|
5985
|
+
if (children.length > 0) {
|
|
5986
|
+
flattenItems(children);
|
|
5987
|
+
}
|
|
5988
|
+
}
|
|
5989
|
+
});
|
|
5990
|
+
};
|
|
5991
|
+
flattenItems(data);
|
|
5992
|
+
console.log('🔍 Flattened data for order tracking:', flattenedItems.length, 'items (including children)');
|
|
5993
|
+
return flattenedItems;
|
|
5994
|
+
}
|
|
5749
5995
|
/**
|
|
5750
5996
|
* Update local data order for visual reordering (LOCAL ONLY)
|
|
5751
5997
|
*/
|