forked from EVOgeek/Vmeda.Online
		
	Merge pull request #2677 from dpalou/MOBILE-3651-2
MOBILE-3651 core: Implement attachments, files and local-file components
This commit is contained in:
		
						commit
						836a7bb812
					
				
							
								
								
									
										155
									
								
								src/core/components/attachments/attachments.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										155
									
								
								src/core/components/attachments/attachments.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,155 @@ | ||||
| // (C) Copyright 2015 Moodle Pty Ltd.
 | ||||
| //
 | ||||
| // Licensed under the Apache License, Version 2.0 (the "License");
 | ||||
| // you may not use this file except in compliance with the License.
 | ||||
| // You may obtain a copy of the License at
 | ||||
| //
 | ||||
| //     http://www.apache.org/licenses/LICENSE-2.0
 | ||||
| //
 | ||||
| // Unless required by applicable law or agreed to in writing, software
 | ||||
| // distributed under the License is distributed on an "AS IS" BASIS,
 | ||||
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | ||||
| // See the License for the specific language governing permissions and
 | ||||
| // limitations under the License.
 | ||||
| 
 | ||||
| import { Component, Input, OnInit } from '@angular/core'; | ||||
| import { FileEntry } from '@ionic-native/file/ngx'; | ||||
| 
 | ||||
| import { CoreFileUploader, CoreFileUploaderTypeList } from '@features/fileuploader/services/fileuploader'; | ||||
| import { CoreSites } from '@services/sites'; | ||||
| import { CoreTextUtils } from '@services/utils/text'; | ||||
| import { CoreWSExternalFile } from '@services/ws'; | ||||
| import { Translate } from '@singletons'; | ||||
| import { CoreApp } from '@services/app'; | ||||
| import { CoreDomUtils } from '@services/utils/dom'; | ||||
| import { CoreFileUploaderHelper } from '@features/fileuploader/services/fileuploader-helper'; | ||||
| 
 | ||||
| /** | ||||
|  * Component to render attachments, allow adding more and delete the current ones. | ||||
|  * | ||||
|  * All the changes done will be applied to the "files" input array, no file will be uploaded. The component using this | ||||
|  * component should be the one uploading and moving the files. | ||||
|  * | ||||
|  * All the files added will be copied to the app temporary folder, so they should be deleted after uploading them | ||||
|  * or if the user cancels the action. | ||||
|  * | ||||
|  * <core-attachments [files]="files" [maxSize]="configs.maxsubmissionsizebytes" [maxSubmissions]="configs.maxfilesubmissions" | ||||
|  *     [component]="component" [componentId]="assign.cmid" [acceptedTypes]="configs.filetypeslist" [allowOffline]="allowOffline"> | ||||
|  * </core-attachments> | ||||
|  */ | ||||
| @Component({ | ||||
|     selector: 'core-attachments', | ||||
|     templateUrl: 'core-attachments.html', | ||||
| }) | ||||
| export class CoreAttachmentsComponent implements OnInit { | ||||
| 
 | ||||
|     @Input() files?: (CoreWSExternalFile | FileEntry)[]; // List of attachments. New attachments will be added to this array.
 | ||||
|     @Input() maxSize?: number; // Max size for attachments. -1 means unlimited, 0 means user max size, not defined means unknown.
 | ||||
|     @Input() maxSubmissions?: number; // Max number of attachments. -1 means unlimited, not defined means unknown limit.
 | ||||
|     @Input() component?: string; // Component the downloaded files will be linked to.
 | ||||
|     @Input() componentId?: string | number; // Component ID.
 | ||||
|     @Input() allowOffline?: boolean | string; // Whether to allow selecting files in offline.
 | ||||
|     @Input() acceptedTypes?: string; // List of supported filetypes. If undefined, all types supported.
 | ||||
|     @Input() required?: boolean; // Whether to display the required mark.
 | ||||
| 
 | ||||
|     maxSizeReadable?: string; | ||||
|     maxSubmissionsReadable?: string; | ||||
|     unlimitedFiles?: boolean; | ||||
|     fileTypes?: CoreFileUploaderTypeList; | ||||
| 
 | ||||
|     /** | ||||
|      * Component being initialized. | ||||
|      */ | ||||
|     ngOnInit(): void { | ||||
|         this.files = this.files || []; | ||||
|         this.maxSize = this.maxSize !== null ? Number(this.maxSize) : NaN; | ||||
| 
 | ||||
|         if (this.maxSize === 0) { | ||||
|             const currentSite = CoreSites.instance.getCurrentSite(); | ||||
|             const siteInfo = currentSite?.getInfo(); | ||||
| 
 | ||||
|             if (siteInfo?.usermaxuploadfilesize) { | ||||
|                 this.maxSize = siteInfo.usermaxuploadfilesize; | ||||
|                 this.maxSizeReadable = CoreTextUtils.instance.bytesToSize(this.maxSize, 2); | ||||
|             } else { | ||||
|                 this.maxSizeReadable = Translate.instance.instant('core.unknown'); | ||||
|             } | ||||
|         } else if (this.maxSize > 0) { | ||||
|             this.maxSizeReadable = CoreTextUtils.instance.bytesToSize(this.maxSize, 2); | ||||
|         } else if (this.maxSize === -1) { | ||||
|             this.maxSizeReadable = Translate.instance.instant('core.unlimited'); | ||||
|         } else { | ||||
|             this.maxSizeReadable = Translate.instance.instant('core.unknown'); | ||||
|         } | ||||
| 
 | ||||
|         if (this.maxSubmissions === undefined || this.maxSubmissions < 0) { | ||||
|             this.maxSubmissionsReadable = this.maxSubmissions === undefined ? | ||||
|                 Translate.instance.instant('core.unknown') : undefined; | ||||
|             this.unlimitedFiles = true; | ||||
|         } else { | ||||
|             this.maxSubmissionsReadable = String(this.maxSubmissions); | ||||
|         } | ||||
| 
 | ||||
|         this.acceptedTypes = this.acceptedTypes?.trim(); | ||||
| 
 | ||||
|         if (this.acceptedTypes && this.acceptedTypes != '*') { | ||||
|             this.fileTypes = CoreFileUploader.instance.prepareFiletypeList(this.acceptedTypes); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Add a new attachment. | ||||
|      */ | ||||
|     async add(): Promise<void> { | ||||
|         const allowOffline = !!this.allowOffline && this.allowOffline !== 'false'; | ||||
| 
 | ||||
|         if (!allowOffline && !CoreApp.instance.isOnline()) { | ||||
|             CoreDomUtils.instance.showErrorModal('core.fileuploader.errormustbeonlinetoupload', true); | ||||
| 
 | ||||
|             return; | ||||
|         } | ||||
| 
 | ||||
|         const mimetypes = this.fileTypes && this.fileTypes.mimetypes; | ||||
| 
 | ||||
|         try { | ||||
|             const result = await CoreFileUploaderHelper.instance.selectFile(this.maxSize, allowOffline, undefined, mimetypes); | ||||
| 
 | ||||
|             this.files?.push(result); | ||||
|         } catch (error) { | ||||
|             CoreDomUtils.instance.showErrorModalDefault(error, 'Error selecting file.'); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Delete a file from the list. | ||||
|      * | ||||
|      * @param index The index of the file. | ||||
|      * @param askConfirm Whether to ask confirm. | ||||
|      */ | ||||
|     async delete(index: number, askConfirm?: boolean): Promise<void> { | ||||
| 
 | ||||
| 
 | ||||
|         if (askConfirm) { | ||||
|             try { | ||||
|                 await CoreDomUtils.instance.showDeleteConfirm('core.confirmdeletefile'); | ||||
|             } catch { | ||||
|                 // User cancelled.
 | ||||
|                 return; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         // Remove the file from the list.
 | ||||
|         this.files?.splice(index, 1); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * A file was renamed. | ||||
|      * | ||||
|      * @param index Index of the file. | ||||
|      * @param data The data received. | ||||
|      */ | ||||
|     renamed(index: number, data: { file: FileEntry }): void { | ||||
|         this.files![index] = data.file; | ||||
|     } | ||||
| 
 | ||||
| } | ||||
							
								
								
									
										38
									
								
								src/core/components/attachments/core-attachments.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								src/core/components/attachments/core-attachments.html
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,38 @@ | ||||
| <ion-item class="ion-text-wrap"> | ||||
|     <ion-label> | ||||
|         <span *ngIf="maxSubmissionsReadable"> | ||||
|             {{ 'core.maxsizeandattachments' | translate:{$a: {size: maxSizeReadable, attachments: maxSubmissionsReadable} } }} | ||||
|         </span> | ||||
|         <span *ngIf="!maxSubmissionsReadable">{{ 'core.maxfilesize' | translate:{$a: maxSizeReadable} }}</span> | ||||
|         <span [core-mark-required]="required" class="core-mark-required"></span> | ||||
|     </ion-label> | ||||
| </ion-item> | ||||
| <ion-item class="ion-text-wrap" *ngIf="fileTypes && fileTypes.mimetypes && fileTypes.mimetypes.length"> | ||||
|     <ion-label> | ||||
|         <p>{{ 'core.fileuploader.filesofthesetypes' | translate }}</p> | ||||
|         <ul class="list-with-style"> | ||||
|             <li *ngFor="let typeInfo of fileTypes.info"> | ||||
|                 <strong *ngIf="typeInfo.name">{{typeInfo.name}} </strong>{{typeInfo.extlist}} | ||||
|             </li> | ||||
|         </ul> | ||||
|     </ion-label> | ||||
| </ion-item> | ||||
| <div *ngFor="let file of files; let index=index"> | ||||
|     <!-- Files already attached to the submission, either in online or in offline. --> | ||||
|     <core-file *ngIf="!file.name" [file]="file" [component]="component" [componentId]="componentId" | ||||
|         [canDelete]="true" (onDelete)="delete(index, true)" [canDownload]="!file.offline"> | ||||
|     </core-file> | ||||
| 
 | ||||
|     <!-- Files added to draft but not attached to submission yet. --> | ||||
|     <core-local-file *ngIf="file.name" [file]="file" [manage]="true" (onDelete)="delete(index, false)" | ||||
|         (onRename)="renamed(index, $event)"> | ||||
|     </core-local-file> | ||||
| </div> | ||||
| 
 | ||||
| <!-- Button to add more files. --> | ||||
| <ion-button expand="block" | ||||
|     *ngIf="unlimitedFiles || (maxSubmissions !== undefined && maxSubmissions >= 0 && files && files.length < maxSubmissions)" | ||||
|     class="ion-text-wrap ion-margin" (click)="add()"> | ||||
|     <ion-icon name="fas-plus" slot="start"></ion-icon> | ||||
|     {{ 'core.fileuploader.addfiletext' | translate }} | ||||
| </ion-button> | ||||
| @ -48,6 +48,9 @@ import { CoreNavigationBarComponent } from './navigation-bar/navigation-bar'; | ||||
| 
 | ||||
| import { CoreDirectivesModule } from '@directives/directives.module'; | ||||
| import { CorePipesModule } from '@pipes/pipes.module'; | ||||
| import { CoreAttachmentsComponent } from './attachments/attachments'; | ||||
| import { CoreFilesComponent } from './files/files'; | ||||
| import { CoreLocalFileComponent } from './local-file/local-file'; | ||||
| 
 | ||||
| @NgModule({ | ||||
|     declarations: [ | ||||
| @ -78,6 +81,9 @@ import { CorePipesModule } from '@pipes/pipes.module'; | ||||
|         CoreSendMessageFormComponent, | ||||
|         CoreTimerComponent, | ||||
|         CoreNavigationBarComponent, | ||||
|         CoreAttachmentsComponent, | ||||
|         CoreFilesComponent, | ||||
|         CoreLocalFileComponent, | ||||
|     ], | ||||
|     imports: [ | ||||
|         CommonModule, | ||||
| @ -115,6 +121,9 @@ import { CorePipesModule } from '@pipes/pipes.module'; | ||||
|         CoreSendMessageFormComponent, | ||||
|         CoreTimerComponent, | ||||
|         CoreNavigationBarComponent, | ||||
|         CoreAttachmentsComponent, | ||||
|         CoreFilesComponent, | ||||
|         CoreLocalFileComponent, | ||||
|     ], | ||||
| }) | ||||
| export class CoreComponentsModule {} | ||||
|  | ||||
							
								
								
									
										12
									
								
								src/core/components/files/core-files.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								src/core/components/files/core-files.html
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,12 @@ | ||||
| <ng-container *ngIf="showInline && contentText"> | ||||
|     <core-format-text [text]="contentText" [filter]="false"></core-format-text> | ||||
| </ng-container> | ||||
| <ng-container *ngFor="let file of files"> | ||||
|     <!-- Files already attached to the filearea. --> | ||||
|     <core-file *ngIf="!file.name && !file.embedType" [file]="file" [component]="component" [componentId]="componentId" | ||||
|         [alwaysDownload]="alwaysDownload" [canDownload]="canDownload" [showSize]="showSize" [showTime]="showTime"> | ||||
|     </core-file> | ||||
| 
 | ||||
|     <!-- Files stored in offline to be sent later. --> | ||||
|     <core-local-file *ngIf="file.name && !file.embedType" [file]="file"></core-local-file> | ||||
| </ng-container> | ||||
							
								
								
									
										85
									
								
								src/core/components/files/files.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										85
									
								
								src/core/components/files/files.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,85 @@ | ||||
| // (C) Copyright 2015 Moodle Pty Ltd.
 | ||||
| //
 | ||||
| // Licensed under the Apache License, Version 2.0 (the "License");
 | ||||
| // you may not use this file except in compliance with the License.
 | ||||
| // You may obtain a copy of the License at
 | ||||
| //
 | ||||
| //     http://www.apache.org/licenses/LICENSE-2.0
 | ||||
| //
 | ||||
| // Unless required by applicable law or agreed to in writing, software
 | ||||
| // distributed under the License is distributed on an "AS IS" BASIS,
 | ||||
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | ||||
| // See the License for the specific language governing permissions and
 | ||||
| // limitations under the License.
 | ||||
| 
 | ||||
| import { Component, Input, OnInit, DoCheck, KeyValueDiffers } from '@angular/core'; | ||||
| import { FileEntry } from '@ionic-native/file/ngx'; | ||||
| 
 | ||||
| import { CoreMimetypeUtils } from '@services/utils/mimetype'; | ||||
| import { CoreUtils } from '@services/utils/utils'; | ||||
| import { CoreWSExternalFile } from '@services/ws'; | ||||
| 
 | ||||
| /** | ||||
|  * Component to render a file list. | ||||
|  * | ||||
|  * <core-files [files]="files" [component]="component" [componentId]="assign.cmid"> | ||||
|  * </core-files> | ||||
|  */ | ||||
| @Component({ | ||||
|     selector: 'core-files', | ||||
|     templateUrl: 'core-files.html', | ||||
| }) | ||||
| export class CoreFilesComponent implements OnInit, DoCheck { | ||||
| 
 | ||||
|     @Input() files?: (CoreWSExternalFile | FileEntry)[]; // List of files.
 | ||||
|     @Input() component?: string; // Component the downloaded files will be linked to.
 | ||||
|     @Input() componentId?: string | number; // Component ID.
 | ||||
|     @Input() alwaysDownload?: boolean | string; // Whether it should always display the refresh button when the file is downloaded.
 | ||||
|     @Input() canDownload?: boolean | string = true; // Whether file can be downloaded.
 | ||||
|     @Input() showSize?: boolean | string = true; // Whether show filesize.
 | ||||
|     @Input() showTime?: boolean | string = true; // Whether show file time modified.
 | ||||
|     @Input() showInline = false; // If true, it will reorder and try to show inline files first.
 | ||||
| 
 | ||||
|     contentText?: string; | ||||
| 
 | ||||
|     // eslint-disable-next-line @typescript-eslint/no-explicit-any
 | ||||
|     protected differ: any; // To detect changes in the data input.
 | ||||
| 
 | ||||
|     constructor(differs: KeyValueDiffers) { | ||||
|         this.differ = differs.find([]).create(); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Component being initialized. | ||||
|      */ | ||||
|     ngOnInit(): void { | ||||
|         if (CoreUtils.instance.isTrueOrOne(this.showInline) && this.files) { | ||||
|             this.renderInlineFiles(); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Detect and act upon changes that Angular can’t or won’t detect on its own (objects and arrays). | ||||
|      */ | ||||
|     ngDoCheck(): void { | ||||
|         if (CoreUtils.instance.isTrueOrOne(this.showInline) && this.files) { | ||||
|             // Check if there's any change in the files array.
 | ||||
|             const changes = this.differ.diff(this.files); | ||||
|             if (changes) { | ||||
|                 this.renderInlineFiles(); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Calculate contentText based on fils that can be rendered inline. | ||||
|      */ | ||||
|     protected renderInlineFiles(): void { | ||||
|         this.contentText = this.files!.reduce((previous, file) => { | ||||
|             const text = CoreMimetypeUtils.instance.getEmbeddedHtml(file); | ||||
| 
 | ||||
|             return text ? previous + '<br>' + text : previous; | ||||
|         }, ''); | ||||
|     } | ||||
| 
 | ||||
| } | ||||
							
								
								
									
										33
									
								
								src/core/components/local-file/core-local-file.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								src/core/components/local-file/core-local-file.html
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,33 @@ | ||||
| <form (ngSubmit)="changeName(newFileName, $event)" #nameForm> | ||||
|     <ion-item class="ion-text-wrap item-media" (click)="fileClicked($event)"> <!-- [class.item-input]="editMode" --> | ||||
|         <img [src]="fileIcon" alt="{{fileExtension}}" role="presentation" slot="start" /> | ||||
| 
 | ||||
|         <ion-label> | ||||
|             <!-- File name and edit button (if editable). --> | ||||
|             <h3 *ngIf="!editMode">{{fileName}}</h3> | ||||
|             <!-- More data about the file. --> | ||||
|             <p *ngIf="size && !editMode">{{ size }}</p> | ||||
|             <p *ngIf="timemodified && !editMode">{{ timemodified }}</p> | ||||
|         </ion-label> | ||||
| 
 | ||||
|         <!-- Form to edit the file's name. --> | ||||
|         <ion-input type="text" name="filename" [placeholder]="'core.filename' | translate" autocapitalize="none" autocorrect="off" | ||||
|             (click)="$event.stopPropagation()" [core-auto-focus] [(ngModel)]="newFileName" *ngIf="editMode"> | ||||
|         </ion-input> | ||||
| 
 | ||||
|         <div class="buttons" slot="end" *ngIf="manage"> | ||||
|             <ion-button *ngIf="!editMode" fill="clear" [core-suppress-events] (onClick)="activateEdit($event)" | ||||
|                 [attr.aria-label]="'core.edit' | translate" color="dark"> | ||||
|                 <ion-icon name="fas-pen" slot="icon-only"></ion-icon> | ||||
|             </ion-button> | ||||
| 
 | ||||
|             <ion-button *ngIf="editMode" fill="clear" [attr.aria-label]="'core.save' | translate" color="success" type="submit"> | ||||
|                 <ion-icon name="fas-check" slot="icon-only"></ion-icon> | ||||
|             </ion-button> | ||||
| 
 | ||||
|             <ion-button fill="clear" (click)="deleteFile($event)" [attr.aria-label]="'core.delete' | translate" color="danger"> | ||||
|                 <ion-icon name="fas-trash" slot="icon-only"></ion-icon> | ||||
|             </ion-button> | ||||
|         </div> | ||||
|     </ion-item> | ||||
| </form> | ||||
							
								
								
									
										213
									
								
								src/core/components/local-file/local-file.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										213
									
								
								src/core/components/local-file/local-file.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,213 @@ | ||||
| // (C) Copyright 2015 Moodle Pty Ltd.
 | ||||
| //
 | ||||
| // Licensed under the Apache License, Version 2.0 (the "License");
 | ||||
| // you may not use this file except in compliance with the License.
 | ||||
| // You may obtain a copy of the License at
 | ||||
| //
 | ||||
| //     http://www.apache.org/licenses/LICENSE-2.0
 | ||||
| //
 | ||||
| // Unless required by applicable law or agreed to in writing, software
 | ||||
| // distributed under the License is distributed on an "AS IS" BASIS,
 | ||||
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | ||||
| // See the License for the specific language governing permissions and
 | ||||
| // limitations under the License.
 | ||||
| 
 | ||||
| import { Component, Input, Output, OnInit, EventEmitter, ViewChild, ElementRef } from '@angular/core'; | ||||
| import { FileEntry } from '@ionic-native/file/ngx'; | ||||
| 
 | ||||
| import { CoreIonLoadingElement } from '@classes/ion-loading'; | ||||
| import { CoreFile } from '@services/file'; | ||||
| import { CoreFileHelper } from '@services/file-helper'; | ||||
| import { CoreSites } from '@services/sites'; | ||||
| import { CoreDomUtils } from '@services/utils/dom'; | ||||
| import { CoreMimetypeUtils } from '@services/utils/mimetype'; | ||||
| import { CoreTextUtils } from '@services/utils/text'; | ||||
| import { CoreTimeUtils } from '@services/utils/time'; | ||||
| import { CoreUtils } from '@services/utils/utils'; | ||||
| 
 | ||||
| /** | ||||
|  * Component to handle a local file. Only files inside the app folder can be managed. | ||||
|  * | ||||
|  * Shows the file name, icon (depending on extension), size and time modified. | ||||
|  * Also, if managing is enabled it will also show buttons to rename and delete the file. | ||||
|  */ | ||||
| @Component({ | ||||
|     selector: 'core-local-file', | ||||
|     templateUrl: 'core-local-file.html', | ||||
| }) | ||||
| export class CoreLocalFileComponent implements OnInit { | ||||
| 
 | ||||
|     @Input() file?: FileEntry; // A fileEntry retrieved using CoreFileProvider.getFile or similar.
 | ||||
|     @Input() manage?: boolean | string; // Whether the user can manage the file (edit and delete).
 | ||||
|     @Input() overrideClick?: boolean | string; // Whether the default item click should be overridden.
 | ||||
|     @Output() onDelete = new EventEmitter<void>(); // Will notify when the file is deleted.
 | ||||
|     @Output() onRename = new EventEmitter<{ file: FileEntry }>(); // Will notify when the file is renamed.
 | ||||
|     @Output() onClick = new EventEmitter<void>(); // Will notify when the file is clicked. Only if overrideClick is true.
 | ||||
| 
 | ||||
|     @ViewChild('nameForm') formElement?: ElementRef; | ||||
| 
 | ||||
|     fileName?: string; | ||||
|     fileIcon?: string; | ||||
|     fileExtension?: string; | ||||
|     size?: string; | ||||
|     timemodified?: string; | ||||
|     newFileName = ''; | ||||
|     editMode = false; | ||||
|     relativePath?: string; | ||||
| 
 | ||||
|     /** | ||||
|      * Component being initialized. | ||||
|      */ | ||||
|     async ngOnInit(): Promise<void> { | ||||
|         this.manage = CoreUtils.instance.isTrueOrOne(this.manage); | ||||
| 
 | ||||
|         if (!this.file) { | ||||
|             return; | ||||
|         } | ||||
| 
 | ||||
|         this.loadFileBasicData(this.file); | ||||
| 
 | ||||
|         // Get the size and timemodified.
 | ||||
|         const metadata = await CoreFile.instance.getMetadata(this.file); | ||||
|         if (metadata.size >= 0) { | ||||
|             this.size = CoreTextUtils.instance.bytesToSize(metadata.size, 2); | ||||
|         } | ||||
| 
 | ||||
|         this.timemodified = CoreTimeUtils.instance.userDate(metadata.modificationTime.getTime(), 'core.strftimedatetimeshort'); | ||||
| 
 | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Load the basic data for the file. | ||||
|      */ | ||||
|     protected loadFileBasicData(file: FileEntry): void { | ||||
|         this.fileName = file.name; | ||||
|         this.fileIcon = CoreMimetypeUtils.instance.getFileIcon(file.name); | ||||
|         this.fileExtension = CoreMimetypeUtils.instance.getFileExtension(file.name); | ||||
| 
 | ||||
|         // Let's calculate the relative path for the file.
 | ||||
|         this.relativePath = CoreFile.instance.removeBasePath(file.toURL()); | ||||
|         if (!this.relativePath) { | ||||
|             // Didn't find basePath, use fullPath but if the user tries to manage the file it'll probably fail.
 | ||||
|             this.relativePath = file.fullPath; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * File clicked. | ||||
|      * | ||||
|      * @param e Click event. | ||||
|      */ | ||||
|     async fileClicked(e: Event): Promise<void> { | ||||
|         if (this.editMode) { | ||||
|             return; | ||||
|         } | ||||
| 
 | ||||
|         e.preventDefault(); | ||||
|         e.stopPropagation(); | ||||
| 
 | ||||
|         if (CoreUtils.instance.isTrueOrOne(this.overrideClick) && this.onClick.observers.length) { | ||||
|             this.onClick.emit(); | ||||
| 
 | ||||
|             return; | ||||
|         } | ||||
| 
 | ||||
|         if (!CoreFileHelper.instance.isOpenableInApp(this.file!)) { | ||||
|             try { | ||||
|                 await CoreFileHelper.instance.showConfirmOpenUnsupportedFile(); | ||||
|             } catch (error) { | ||||
|                 return; // Cancelled, stop.
 | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         CoreUtils.instance.openFile(this.file!.toURL()); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Activate the edit mode. | ||||
|      * | ||||
|      * @param e Click event. | ||||
|      */ | ||||
|     activateEdit(e: Event): void { | ||||
|         e.preventDefault(); | ||||
|         e.stopPropagation(); | ||||
| 
 | ||||
|         this.editMode = true; | ||||
|         this.newFileName = this.file!.name; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Rename the file. | ||||
|      * | ||||
|      * @param newName New name. | ||||
|      * @param e Click event. | ||||
|      */ | ||||
|     async changeName(newName: string, e: Event): Promise<void> { | ||||
|         e.preventDefault(); | ||||
|         e.stopPropagation(); | ||||
| 
 | ||||
|         if (newName == this.file!.name) { | ||||
|             // Name hasn't changed, stop.
 | ||||
|             this.editMode = false; | ||||
|             CoreDomUtils.instance.triggerFormCancelledEvent(this.formElement, CoreSites.instance.getCurrentSiteId()); | ||||
| 
 | ||||
|             return; | ||||
|         } | ||||
| 
 | ||||
|         const modal = await CoreDomUtils.instance.showModalLoading(); | ||||
|         const fileAndDir = CoreFile.instance.getFileAndDirectoryFromPath(this.relativePath!); | ||||
|         const newPath = CoreTextUtils.instance.concatenatePaths(fileAndDir.directory, newName); | ||||
| 
 | ||||
|         try { | ||||
|             // Check if there's a file with this name.
 | ||||
|             await CoreFile.instance.getFile(newPath); | ||||
| 
 | ||||
|             // There's a file with this name, show error and stop.
 | ||||
|             CoreDomUtils.instance.showErrorModal('core.errorfileexistssamename', true); | ||||
|         } catch { | ||||
|             try { | ||||
|                 // File doesn't exist, move it.
 | ||||
|                 const fileEntry = await CoreFile.instance.moveFile(this.relativePath!, newPath); | ||||
| 
 | ||||
|                 CoreDomUtils.instance.triggerFormSubmittedEvent(this.formElement, false, CoreSites.instance.getCurrentSiteId()); | ||||
| 
 | ||||
|                 this.editMode = false; | ||||
|                 this.file = fileEntry; | ||||
|                 this.loadFileBasicData(this.file); | ||||
|                 this.onRename.emit({ file: this.file }); | ||||
|             } catch (error) { | ||||
|                 CoreDomUtils.instance.showErrorModalDefault(error, 'core.errorrenamefile', true); | ||||
|             } | ||||
|         } finally { | ||||
|             modal.dismiss(); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Delete the file. | ||||
|      * | ||||
|      * @param e Click event. | ||||
|      */ | ||||
|     async deleteFile(e: Event): Promise<void> { | ||||
|         e.preventDefault(); | ||||
|         e.stopPropagation(); | ||||
| 
 | ||||
|         let modal: CoreIonLoadingElement | undefined; | ||||
| 
 | ||||
|         try { | ||||
|             // Ask confirmation.
 | ||||
|             await CoreDomUtils.instance.showDeleteConfirm('core.confirmdeletefile'); | ||||
| 
 | ||||
|             modal = await CoreDomUtils.instance.showModalLoading('core.deleting', true); | ||||
| 
 | ||||
|             await CoreFile.instance.removeFile(this.relativePath!); | ||||
| 
 | ||||
|             this.onDelete.emit(); | ||||
|         } catch (error) { | ||||
|             CoreDomUtils.instance.showErrorModalDefault(error, 'core.errordeletefile', true); | ||||
|         } finally { | ||||
|             modal?.dismiss(); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| } | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user