| @ -11,10 +11,10 @@ | ||||
|     <!-- Activity info. --> | ||||
|     <core-course-module-info [module]="module" [description]="description" [component]="component" [componentId]="componentId" | ||||
|         [courseId]="courseId" [hasDataToSync]="hasOffline" (completionChanged)="onCompletionChange()"> | ||||
|         <ion-list inset="true" description *ngIf="assign && assign.introattachments?.length && !assign.submissionattachments"> | ||||
|         <div description *ngIf="assign && assign.introattachments?.length && !assign.submissionattachments"> | ||||
|             <core-file *ngFor="let file of assign.introattachments" [file]="file" [component]="component" [componentId]="componentId"> | ||||
|             </core-file> | ||||
|         </ion-list> | ||||
|         </div> | ||||
|     </core-course-module-info> | ||||
| 
 | ||||
|     <!-- User can view all submissions (teacher). --> | ||||
|  | ||||
| @ -15,7 +15,7 @@ | ||||
| 
 | ||||
|     <ion-list *ngIf="contents && (contents.files.length + contents.folders.length > 0)"> | ||||
|         <ng-container *ngFor="let folder of contents.folders"> | ||||
|             <ion-item class="item-file" (click)="openFolder(folder)" detail="true" button> | ||||
|             <ion-item class="ion-text-wrap item-file item-directory" (click)="openFolder(folder)" detail="true" button> | ||||
|                 <ion-icon name="fas-folder" slot="start" [attr.aria-label]="'core.folder' | translate"></ion-icon> | ||||
|                 <ion-label> | ||||
|                     <p class="item-heading">{{folder.filename}}</p> | ||||
|  | ||||
| @ -54,6 +54,7 @@ export class AddonModFolderIndexComponent extends CoreCourseModuleMainResourceCo | ||||
|         if (this.subfolder) { | ||||
|             this.description = this.folderInstance ? this.folderInstance.intro : this.module.description; | ||||
|             this.contents = this.subfolder; | ||||
|             this.sortFilesAndFolders(); | ||||
| 
 | ||||
|             this.showLoading = false; | ||||
| 
 | ||||
| @ -88,6 +89,30 @@ export class AddonModFolderIndexComponent extends CoreCourseModuleMainResourceCo | ||||
| 
 | ||||
|         this.description = this.folderInstance ? this.folderInstance.intro : this.module.description; | ||||
|         this.contents = AddonModFolderHelper.formatContents(contents); | ||||
|         this.sortFilesAndFolders(); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Sort files and folders alphabetically. | ||||
|      */ | ||||
|     protected sortFilesAndFolders(): void { | ||||
|         if (!this.contents) { | ||||
|             return; | ||||
|         } | ||||
| 
 | ||||
|         this.contents.folders.sort((a, b) => { | ||||
|             const compareA = a.filename.toLowerCase(); | ||||
|             const compareB = b.filename.toLowerCase(); | ||||
| 
 | ||||
|             return compareA.localeCompare(compareB); | ||||
|         }); | ||||
| 
 | ||||
|         this.contents.files.sort((a, b) => { | ||||
|             const compareA = a.filename.toLowerCase(); | ||||
|             const compareB = b.filename.toLowerCase(); | ||||
| 
 | ||||
|             return compareA.localeCompare(compareB); | ||||
|         }); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|  | ||||
| @ -40,6 +40,8 @@ ion-item { | ||||
|     div.core-notification-icon, | ||||
|     core-mod-icon.core-notification-icon { | ||||
|         padding: 8px; | ||||
|         max-width: var(--core-avatar-size); | ||||
|         max-height:  var(--core-avatar-size); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -37,10 +37,8 @@ | ||||
|         <!-- List of files. --> | ||||
|         <ion-list *ngIf="files && files.length > 0"> | ||||
|             <ng-container *ngFor="let file of files"> | ||||
|                 <ion-item button *ngIf="file.isdir" class="item-file" (click)="openFolder(file)" detail="true"> | ||||
|                     <ion-thumbnail slot="start"> | ||||
|                         <img [src]="file.imgPath" alt="" role="presentation"> | ||||
|                     </ion-thumbnail> | ||||
|                 <ion-item button *ngIf="file.isdir" class="ion-text-wrap item-file item-directory" (click)="openFolder(file)" detail="true"> | ||||
|                     <ion-icon name="fas-folder" slot="start" [attr.aria-label]="'core.folder' | translate"></ion-icon> | ||||
|                     <ion-label>{{file.filename}}</ion-label> | ||||
|                 </ion-item> | ||||
|                 <core-file *ngIf="!file.isdir" [file]="file" [component]="component" [componentId]="file.contextid"></core-file> | ||||
|  | ||||
| Before Width: | Height: | Size: 3.8 KiB | 
							
								
								
									
										
											BIN
										
									
								
								src/assets/img/files/archive.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 1.2 KiB | 
| Before Width: | Height: | Size: 4.5 KiB | 
							
								
								
									
										
											BIN
										
									
								
								src/assets/img/files/audio.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 1.4 KiB | 
| Before Width: | Height: | Size: 4.6 KiB | 
							
								
								
									
										
											BIN
										
									
								
								src/assets/img/files/avi.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 1.3 KiB | 
| Before Width: | Height: | Size: 4.0 KiB | 
							
								
								
									
										
											BIN
										
									
								
								src/assets/img/files/base.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 1.2 KiB | 
| Before Width: | Height: | Size: 4.2 KiB | 
							
								
								
									
										
											BIN
										
									
								
								src/assets/img/files/bmp.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 1.3 KiB | 
| Before Width: | Height: | Size: 3.4 KiB | 
							
								
								
									
										
											BIN
										
									
								
								src/assets/img/files/calc.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 1.2 KiB | 
| Before Width: | Height: | Size: 3.3 KiB | 
							
								
								
									
										
											BIN
										
									
								
								src/assets/img/files/chart.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 1.1 KiB | 
| Before Width: | Height: | Size: 4.8 KiB | 
							
								
								
									
										
											BIN
										
									
								
								src/assets/img/files/database.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 1.4 KiB | 
| Before Width: | Height: | Size: 4.8 KiB | 
							
								
								
									
										
											BIN
										
									
								
								src/assets/img/files/document.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 1.4 KiB | 
| Before Width: | Height: | Size: 3.4 KiB | 
							
								
								
									
										
											BIN
										
									
								
								src/assets/img/files/draw.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 1.1 KiB | 
| Before Width: | Height: | Size: 3.6 KiB | 
							
								
								
									
										
											BIN
										
									
								
								src/assets/img/files/eps.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 1.2 KiB | 
| Before Width: | Height: | Size: 3.7 KiB | 
							
								
								
									
										
											BIN
										
									
								
								src/assets/img/files/epub.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 1.3 KiB | 
| Before Width: | Height: | Size: 3.7 KiB | 
							
								
								
									
										
											BIN
										
									
								
								src/assets/img/files/flash.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 1.2 KiB | 
| Before Width: | Height: | Size: 1.1 KiB | 
| Before Width: | Height: | Size: 1.2 KiB | 
							
								
								
									
										
											BIN
										
									
								
								src/assets/img/files/folder-open.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 539 B | 
							
								
								
									
										
											BIN
										
									
								
								src/assets/img/files/folder.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 543 B | 
| Before Width: | Height: | Size: 4.4 KiB | 
							
								
								
									
										
											BIN
										
									
								
								src/assets/img/files/gif.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 1.4 KiB | 
| Before Width: | Height: | Size: 2.8 KiB | 
							
								
								
									
										
											BIN
										
									
								
								src/assets/img/files/h5p.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 1.2 KiB | 
| Before Width: | Height: | Size: 2.1 KiB | 
							
								
								
									
										
											BIN
										
									
								
								src/assets/img/files/html.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 888 B | 
| Before Width: | Height: | Size: 5.7 KiB | 
							
								
								
									
										
											BIN
										
									
								
								src/assets/img/files/image.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 1.2 KiB | 
| Before Width: | Height: | Size: 3.2 KiB | 
							
								
								
									
										
											BIN
										
									
								
								src/assets/img/files/impress.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 1.1 KiB | 
| Before Width: | Height: | Size: 3.4 KiB | 
							
								
								
									
										
											BIN
										
									
								
								src/assets/img/files/isf.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 1.2 KiB | 
| Before Width: | Height: | Size: 4.4 KiB | 
							
								
								
									
										
											BIN
										
									
								
								src/assets/img/files/jpeg.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 1.3 KiB | 
| Before Width: | Height: | Size: 4.1 KiB | 
							
								
								
									
										
											BIN
										
									
								
								src/assets/img/files/markup.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 1.3 KiB | 
| Before Width: | Height: | Size: 3.1 KiB | 
							
								
								
									
										
											BIN
										
									
								
								src/assets/img/files/math.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 1.1 KiB | 
| Before Width: | Height: | Size: 3.5 KiB | 
							
								
								
									
										
											BIN
										
									
								
								src/assets/img/files/moodle.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 1.2 KiB | 
| Before Width: | Height: | Size: 4.2 KiB | 
							
								
								
									
										
											BIN
										
									
								
								src/assets/img/files/mp3.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 1.3 KiB | 
| Before Width: | Height: | Size: 5.2 KiB | 
							
								
								
									
										
											BIN
										
									
								
								src/assets/img/files/mpeg.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 1.4 KiB | 
| Before Width: | Height: | Size: 3.6 KiB | 
							
								
								
									
										
											BIN
										
									
								
								src/assets/img/files/oth.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 1.1 KiB | 
| Before Width: | Height: | Size: 4.1 KiB | 
							
								
								
									
										
											BIN
										
									
								
								src/assets/img/files/pdf.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 1.3 KiB | 
| Before Width: | Height: | Size: 4.4 KiB | 
							
								
								
									
										
											BIN
										
									
								
								src/assets/img/files/png.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 1.2 KiB | 
| Before Width: | Height: | Size: 4.5 KiB | 
							
								
								
									
										
											BIN
										
									
								
								src/assets/img/files/powerpoint.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 1.3 KiB | 
| Before Width: | Height: | Size: 3.9 KiB | 
							
								
								
									
										
											BIN
										
									
								
								src/assets/img/files/psd.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 1.3 KiB | 
| Before Width: | Height: | Size: 4.9 KiB | 
							
								
								
									
										
											BIN
										
									
								
								src/assets/img/files/publisher.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 1.4 KiB | 
| Before Width: | Height: | Size: 4.6 KiB | 
							
								
								
									
										
											BIN
										
									
								
								src/assets/img/files/quicktime.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 1.4 KiB | 
| Before Width: | Height: | Size: 4.2 KiB | 
							
								
								
									
										
											BIN
										
									
								
								src/assets/img/files/sourcecode.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 1.3 KiB | 
| Before Width: | Height: | Size: 5.2 KiB | 
							
								
								
									
										
											BIN
										
									
								
								src/assets/img/files/spreadsheet.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 1.4 KiB | 
| Before Width: | Height: | Size: 3.6 KiB | 
							
								
								
									
										
											BIN
										
									
								
								src/assets/img/files/text.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 1.1 KiB | 
| Before Width: | Height: | Size: 4.6 KiB | 
							
								
								
									
										
											BIN
										
									
								
								src/assets/img/files/tiff.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 1.4 KiB | 
| Before Width: | Height: | Size: 2.1 KiB | 
							
								
								
									
										
											BIN
										
									
								
								src/assets/img/files/unknown.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 888 B | 
| Before Width: | Height: | Size: 4.1 KiB | 
							
								
								
									
										
											BIN
										
									
								
								src/assets/img/files/video.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 1.2 KiB | 
| Before Width: | Height: | Size: 5.3 KiB | 
							
								
								
									
										
											BIN
										
									
								
								src/assets/img/files/wav.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 1.4 KiB | 
| Before Width: | Height: | Size: 4.1 KiB | 
							
								
								
									
										
											BIN
										
									
								
								src/assets/img/files/wmv.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 1.2 KiB | 
| Before Width: | Height: | Size: 2.8 KiB | 
							
								
								
									
										
											BIN
										
									
								
								src/assets/img/files/writer.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 1.1 KiB | 
| @ -1,24 +1,29 @@ | ||||
| <ion-item *ngIf="file" button class="ion-text-wrap item-file" (click)="download($event, true)" detail="false"> | ||||
|     <ion-thumbnail slot="start"> | ||||
|         <img [src]="fileIcon" alt="" role="presentation" /> | ||||
|     </ion-thumbnail> | ||||
|     <ion-label> | ||||
|         <p class="item-heading">{{fileName}}</p> | ||||
|         <p *ngIf="fileSizeReadable">{{ fileSizeReadable }}</p> | ||||
|         <p *ngIf="showTime">{{ timemodified * 1000 | coreFormatDate }}</p> | ||||
|     </ion-label> | ||||
|     <div slot="end" class="flex-row"> | ||||
|         <core-download-refresh [status]="state" [enabled]="canDownload" [loading]="isDownloading" [canTrustDownload]="!alwaysDownload" | ||||
|             (action)="download()"> | ||||
|         </core-download-refresh> | ||||
| <ion-card class="card-file"> | ||||
|     <ion-item *ngIf="file" button class="ion-text-wrap item-file" (click)="download($event, true)" detail="false"> | ||||
|         <ion-thumbnail slot="start"> | ||||
|             <img [src]="fileIcon" alt="" role="presentation" /> | ||||
|         </ion-thumbnail> | ||||
|         <ion-label> | ||||
|             <p class="item-heading">{{fileName}}</p> | ||||
|             <p *ngIf="fileSizeReadable || showTime"> | ||||
|                 <ng-container *ngIf="fileSizeReadable">{{ fileSizeReadable }}</ng-container> | ||||
|                 <ng-container *ngIf="fileSizeReadable && showTime"> · </ng-container> | ||||
|                 <ng-container *ngIf="showTime">{{ timemodified * 1000 | coreFormatDate }}</ng-container> | ||||
|             </p> | ||||
|         </ion-label> | ||||
|         <div slot="end" class="flex-row"> | ||||
|             <core-download-refresh [status]="state" [enabled]="canDownload" [loading]="isDownloading" [canTrustDownload]="!alwaysDownload" | ||||
|                 (action)="download()"> | ||||
|             </core-download-refresh> | ||||
| 
 | ||||
|         <ion-button fill="clear" *ngIf="isDownloaded && isIOS" (click)="openFile($event, true)" [title]="openButtonLabel | translate"> | ||||
|             <ion-icon slot="icon-only" [name]="openButtonIcon" aria-hidden="true"></ion-icon> | ||||
|         </ion-button> | ||||
|             <ion-button fill="clear" *ngIf="isDownloaded && isIOS" (click)="openFile($event, true)" [title]="openButtonLabel | translate"> | ||||
|                 <ion-icon slot="icon-only" [name]="openButtonIcon" aria-hidden="true"></ion-icon> | ||||
|             </ion-button> | ||||
| 
 | ||||
|         <ion-button fill="clear" *ngIf="!isDownloading && canDelete" (click)="delete($event)" [attr.aria-label]="'core.delete' | translate" | ||||
|             color="danger"> | ||||
|             <ion-icon slot="icon-only" name="fas-trash" aria-hidden="true"></ion-icon> | ||||
|         </ion-button> | ||||
|     </div> | ||||
| </ion-item> | ||||
|             <ion-button fill="clear" *ngIf="!isDownloading && canDelete" (click)="delete($event)" | ||||
|                 [attr.aria-label]="'core.delete' | translate" color="danger"> | ||||
|                 <ion-icon slot="icon-only" name="fas-trash" aria-hidden="true"></ion-icon> | ||||
|             </ion-button> | ||||
|         </div> | ||||
|     </ion-item> | ||||
| </ion-card> | ||||
|  | ||||
| @ -1,41 +1,48 @@ | ||||
| <form (ngSubmit)="changeName(newFileName, $event)" #nameForm> | ||||
|     <ion-item class="ion-text-wrap item-file" (click)="openFile($event)" button detail="false"> | ||||
|         <ion-thumbnail slot="start"> | ||||
|             <img [src]="fileIcon" [alt]="fileExtension" role="presentation" /> | ||||
|         </ion-thumbnail> | ||||
|     <ion-card class="card-file"> | ||||
|         <ion-item class="ion-text-wrap item-file" (click)="openFile($event)" button detail="false"> | ||||
|             <ion-thumbnail slot="start"> | ||||
|                 <img [src]="fileIcon" [alt]="fileExtension" role="presentation" /> | ||||
|             </ion-thumbnail> | ||||
| 
 | ||||
|         <ion-label> | ||||
|             <!-- File name and edit button (if editable). --> | ||||
|             <p class="item-heading" *ngIf="!editMode">{{fileName}}</p> | ||||
|             <!-- More data about the file. --> | ||||
|             <p *ngIf="size && !editMode">{{ size }}</p> | ||||
|             <p *ngIf="timemodified && !editMode">{{ timemodified }}</p> | ||||
|         </ion-label> | ||||
|             <ion-label *ngIf="!editMode"> | ||||
|                 <!-- File name and edit button (if editable). --> | ||||
|                 <p class="item-heading">{{fileName}}</p> | ||||
|                 <!-- More data about the file. --> | ||||
|                 <p *ngIf="size || timemodified"> | ||||
|                     <ng-container *ngIf="size">{{ size }}</ng-container> | ||||
|                     <ng-container *ngIf="size && timemodified"> · </ng-container> | ||||
|                     <ng-container *ngIf="timemodified">{{ timemodified }}</ng-container> | ||||
|                 </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> | ||||
|             <!-- 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"> | ||||
|             <ion-button fill="clear" *ngIf="isIOS" (click)="openFile($event, true)" [attr.aria-label]="openButtonLabel | translate"> | ||||
|                 <ion-icon slot="icon-only" [name]="openButtonIcon" aria-hidden="true"></ion-icon> | ||||
|             </ion-button> | ||||
| 
 | ||||
|             <ng-container *ngIf="manage"> | ||||
|                 <ion-button *ngIf="!editMode" fill="clear" [core-suppress-events] (onClick)="activateEdit($event)" | ||||
|                     [attr.aria-label]="'core.edit' | translate"> | ||||
|                     <ion-icon name="fas-pen" slot="icon-only" aria-hidden="true"></ion-icon> | ||||
|             <div class="buttons" slot="end"> | ||||
|                 <ion-button fill="clear" *ngIf="isIOS" (click)="openFile($event, true)" [attr.aria-label]="openButtonLabel | translate"> | ||||
|                     <ion-icon slot="icon-only" [name]="openButtonIcon" aria-hidden="true"></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" aria-hidden="true"></ion-icon> | ||||
|                 </ion-button> | ||||
|                 <ng-container *ngIf="manage"> | ||||
|                     <ion-button *ngIf="editMode" fill="clear" [attr.aria-label]="'core.save' | translate" color="success" type="submit" | ||||
|                         (click)="changeName(newFileName, $event)"> | ||||
|                         <ion-icon name="fas-check" slot="icon-only" aria-hidden="true"></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" aria-hidden="true"></ion-icon> | ||||
|                 </ion-button> | ||||
|             </ng-container> | ||||
|         </div> | ||||
|     </ion-item> | ||||
|                     <ion-button *ngIf="!editMode" fill="clear" [core-suppress-events] (onClick)="activateEdit($event)" | ||||
|                         [attr.aria-label]="'core.edit' | translate"> | ||||
|                         <ion-icon name="fas-pen" slot="icon-only" aria-hidden="true"></ion-icon> | ||||
|                     </ion-button> | ||||
| 
 | ||||
|                     <ion-button *ngIf="!editMode" fill="clear" (click)="deleteFile($event)" [attr.aria-label]="'core.delete' | translate" | ||||
|                         color="danger"> | ||||
|                         <ion-icon name="fas-trash" slot="icon-only" aria-hidden="true"></ion-icon> | ||||
|                     </ion-button> | ||||
|                 </ng-container> | ||||
|             </div> | ||||
|         </ion-item> | ||||
|     </ion-card> | ||||
| </form> | ||||
|  | ||||
| @ -56,7 +56,7 @@ export class CoreLocalFileComponent implements OnInit { | ||||
|     timemodified?: string; | ||||
|     newFileName = ''; | ||||
|     editMode = false; | ||||
|     relativePath?: string; | ||||
|     relativePath = ''; | ||||
|     isIOS = false; | ||||
|     openButtonIcon = ''; | ||||
|     openButtonLabel = ''; | ||||
| @ -112,7 +112,7 @@ export class CoreLocalFileComponent implements OnInit { | ||||
|      * @param isOpenButton Whether the open button was clicked. | ||||
|      */ | ||||
|     async openFile(e: Event, isOpenButton = false): Promise<void> { | ||||
|         if (this.editMode) { | ||||
|         if (this.editMode || !this.file) { | ||||
|             return; | ||||
|         } | ||||
| 
 | ||||
| @ -125,7 +125,7 @@ export class CoreLocalFileComponent implements OnInit { | ||||
|             return; | ||||
|         } | ||||
| 
 | ||||
|         if (!CoreFileHelper.isOpenableInApp(this.file!)) { | ||||
|         if (!CoreFileHelper.isOpenableInApp(this.file)) { | ||||
|             try { | ||||
|                 await CoreFileHelper.showConfirmOpenUnsupportedFile(); | ||||
|             } catch (error) { | ||||
| @ -139,7 +139,7 @@ export class CoreLocalFileComponent implements OnInit { | ||||
|             options.iOSOpenFileAction = this.defaultIsOpenWithPicker ? OpenFileAction.OPEN : OpenFileAction.OPEN_WITH; | ||||
|         } | ||||
| 
 | ||||
|         CoreUtils.openFile(this.file!.toURL(), options); | ||||
|         CoreUtils.openFile(this.file.toURL(), options); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
| @ -148,11 +148,15 @@ export class CoreLocalFileComponent implements OnInit { | ||||
|      * @param e Click event. | ||||
|      */ | ||||
|     activateEdit(e: Event): void { | ||||
|         if (!this.file) { | ||||
|             return; | ||||
|         } | ||||
| 
 | ||||
|         e.preventDefault(); | ||||
|         e.stopPropagation(); | ||||
| 
 | ||||
|         this.editMode = true; | ||||
|         this.newFileName = this.file!.name; | ||||
|         this.newFileName = this.file.name; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
| @ -162,10 +166,14 @@ export class CoreLocalFileComponent implements OnInit { | ||||
|      * @param e Click event. | ||||
|      */ | ||||
|     async changeName(newName: string, e: Event): Promise<void> { | ||||
|         if (!this.file) { | ||||
|             return; | ||||
|         } | ||||
| 
 | ||||
|         e.preventDefault(); | ||||
|         e.stopPropagation(); | ||||
| 
 | ||||
|         if (newName == this.file!.name) { | ||||
|         if (newName == this.file.name) { | ||||
|             // Name hasn't changed, stop.
 | ||||
|             this.editMode = false; | ||||
|             CoreForms.triggerFormCancelledEvent(this.formElement, CoreSites.getCurrentSiteId()); | ||||
| @ -174,7 +182,7 @@ export class CoreLocalFileComponent implements OnInit { | ||||
|         } | ||||
| 
 | ||||
|         const modal = await CoreDomUtils.showModalLoading(); | ||||
|         const fileAndDir = CoreFile.getFileAndDirectoryFromPath(this.relativePath!); | ||||
|         const fileAndDir = CoreFile.getFileAndDirectoryFromPath(this.relativePath); | ||||
|         const newPath = CoreText.concatenatePaths(fileAndDir.directory, newName); | ||||
| 
 | ||||
|         try { | ||||
| @ -186,7 +194,7 @@ export class CoreLocalFileComponent implements OnInit { | ||||
|         } catch { | ||||
|             try { | ||||
|                 // File doesn't exist, move it.
 | ||||
|                 const fileEntry = await CoreFile.moveFile(this.relativePath!, newPath); | ||||
|                 const fileEntry = await CoreFile.moveFile(this.relativePath, newPath); | ||||
| 
 | ||||
|                 CoreForms.triggerFormSubmittedEvent(this.formElement, false, CoreSites.getCurrentSiteId()); | ||||
| 
 | ||||
| @ -219,7 +227,7 @@ export class CoreLocalFileComponent implements OnInit { | ||||
| 
 | ||||
|             modal = await CoreDomUtils.showModalLoading('core.deleting', true); | ||||
| 
 | ||||
|             await CoreFile.removeFile(this.relativePath!); | ||||
|             await CoreFile.removeFile(this.relativePath); | ||||
| 
 | ||||
|             this.onDelete.emit(); | ||||
|         } catch (error) { | ||||
|  | ||||
| @ -208,7 +208,11 @@ export class CoreCollapsibleHeaderDirective implements OnInit, OnChanges, OnDest | ||||
|         this.expandedHeader = this.page?.querySelector('ion-item[collapsible]') ?? undefined; | ||||
| 
 | ||||
|         if (!this.expandedHeader) { | ||||
|             this.enabled = false; | ||||
|             this.setEnabled(this.enabled); | ||||
| 
 | ||||
|             throw new Error('[collapsible-header] Couldn\'t initialize expanded header'); | ||||
| 
 | ||||
|         } | ||||
|         this.expandedHeader.classList.add('collapsible-header-expanded'); | ||||
| 
 | ||||
| @ -384,11 +388,11 @@ export class CoreCollapsibleHeaderDirective implements OnInit, OnChanges, OnDest | ||||
|      * @param enable True to enable, false otherwise | ||||
|      */ | ||||
|     async setEnabled(enable: boolean): Promise<void> { | ||||
|         if (!this.page || !this.content) { | ||||
|         if (!this.page) { | ||||
|             return; | ||||
|         } | ||||
| 
 | ||||
|         if (enable) { | ||||
|         if (enable && this.content) { | ||||
|             const contentScroll = await this.content.getScrollElement(); | ||||
| 
 | ||||
|             // Do nothing, since scroll has already started on the page.
 | ||||
|  | ||||
| @ -15,11 +15,14 @@ | ||||
| import { Directive, ElementRef, Input, OnDestroy, OnInit } from '@angular/core'; | ||||
| import { CoreCancellablePromise } from '@classes/cancellable-promise'; | ||||
| import { CoreLoadingComponent } from '@components/loading/loading'; | ||||
| import { CoreSettingsHelper } from '@features/settings/services/settings-helper'; | ||||
| import { CoreUtils } from '@services/utils/utils'; | ||||
| import { Translate } from '@singletons'; | ||||
| import { CoreColors } from '@singletons/colors'; | ||||
| import { CoreComponentsRegistry } from '@singletons/components-registry'; | ||||
| import { CoreDom } from '@singletons/dom'; | ||||
| import { CoreEventObserver } from '@singletons/events'; | ||||
| import { Subscription } from 'rxjs'; | ||||
| import { CoreFormatTextDirective } from './format-text'; | ||||
| 
 | ||||
| const defaultMaxHeight = 80; | ||||
| @ -50,6 +53,7 @@ export class CoreCollapsibleItemDirective implements OnInit, OnDestroy { | ||||
|     protected maxHeight = defaultMaxHeight; | ||||
|     protected expandedHeight = 0; | ||||
|     protected resizeListener?: CoreEventObserver; | ||||
|     protected darkModeListener?: Subscription; | ||||
|     protected domPromise?: CoreCancellablePromise<void>; | ||||
|     protected uniqueId: string; | ||||
| 
 | ||||
| @ -92,6 +96,10 @@ export class CoreCollapsibleItemDirective implements OnInit, OnDestroy { | ||||
|         this.resizeListener = CoreDom.onWindowResize(() => { | ||||
|             this.calculateHeight(); | ||||
|         }, 50); | ||||
| 
 | ||||
|         this.darkModeListener = CoreSettingsHelper.onDarkModeChange().subscribe(() => { | ||||
|             this.setGradientColor(); | ||||
|         }); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
| @ -135,7 +143,34 @@ export class CoreCollapsibleItemDirective implements OnInit, OnDestroy { | ||||
|         this.element.classList.remove('collapsible-loading-height'); | ||||
| 
 | ||||
|         // If cannot calculate height, shorten always.
 | ||||
|         this.setExpandButtonEnabled(!this.expandedHeight || this.expandedHeight >= this.maxHeight); | ||||
|         const enable = !this.expandedHeight || this.expandedHeight >= this.maxHeight; | ||||
|         this.setExpandButtonEnabled(enable); | ||||
|         this.setGradientColor(); | ||||
| 
 | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Sets the gradient color based on the background. | ||||
|      */ | ||||
|     protected setGradientColor(): void { | ||||
|         if (!this.toggleExpandEnabled) { | ||||
|             return; | ||||
|         } | ||||
| 
 | ||||
|         let coloredElement: HTMLElement | null = this.element; | ||||
|         let backgroundColor = [0, 0, 0, 0]; | ||||
|         let background = ''; | ||||
|         while (coloredElement && backgroundColor[3] === 0) { | ||||
|             background = getComputedStyle(coloredElement).backgroundColor; | ||||
|             backgroundColor = CoreColors.getColorRGBA(background); | ||||
|             coloredElement = coloredElement.parentElement; | ||||
|         } | ||||
| 
 | ||||
|         if (backgroundColor[3] !== 0) { | ||||
|             delete(backgroundColor[3]); | ||||
|             const bgList = backgroundColor.join(','); | ||||
|             this.element.style.setProperty('--background-gradient-rgb', `${bgList}`); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
| @ -241,6 +276,7 @@ export class CoreCollapsibleItemDirective implements OnInit, OnDestroy { | ||||
|      */ | ||||
|     ngOnDestroy(): void { | ||||
|         this.resizeListener?.off(); | ||||
|         this.darkModeListener?.unsubscribe(); | ||||
|         this.domPromise?.cancel(); | ||||
|     } | ||||
| 
 | ||||
|  | ||||
| @ -44,7 +44,7 @@ | ||||
| </core-dynamic-component> | ||||
| 
 | ||||
| 
 | ||||
| <core-block-side-blocks-button slot="fixed" *ngIf="loaded && course && displayBlocks && hasBlocks" contextlevel="course" | ||||
| <core-block-side-blocks-button slot="fixed" *ngIf="loaded && course && displayBlocks && hasBlocks" contextLevel="course" | ||||
|     [instanceId]="course.id"> | ||||
| </core-block-side-blocks-button> | ||||
| 
 | ||||
|  | ||||
| @ -14,43 +14,39 @@ | ||||
|     </ion-label> | ||||
| </ion-item> | ||||
| 
 | ||||
| <!-- Module completion. --> | ||||
| <ion-item class="ion-text-wrap" | ||||
|     *ngIf="showCompletion && module.completiondata && (module.completiondata.isautomatic || (showManualCompletion && module.uservisible))"> | ||||
|     <ion-label> | ||||
| <div class="core-module-info-box"> | ||||
|     <!-- Module completion. --> | ||||
|     <div class="core-module-info-completion core-module-info-box-section" *ngIf="showCompletion && | ||||
|             module.completiondata && (module.completiondata.isautomatic || (showManualCompletion && module.uservisible))"> | ||||
|         <core-course-module-completion [completion]="module.completiondata" [moduleName]="module.name" [moduleId]="module.id" | ||||
|             [showCompletionConditions]="true" [showManualCompletion]="showManualCompletion && module.uservisible" | ||||
|             (completionChanged)="completionChanged.emit($event)"> | ||||
|         </core-course-module-completion> | ||||
|     </ion-label> | ||||
| </ion-item> | ||||
|     </div> | ||||
| 
 | ||||
| <div class="core-module-dates-availabilityinfo" | ||||
|     *ngIf="(module.dates && module.dates.length) || (showAvailabilityInfo && module.availabilityinfo)"> | ||||
|     <!-- Activity dates. --> | ||||
|     <div *ngIf="module.dates && module.dates.length" class="core-module-dates"> | ||||
|     <div *ngIf="module.dates && module.dates.length" class="core-module-dates core-module-info-box-section"> | ||||
|         <p *ngFor="let date of module.dates"> | ||||
|             <ion-icon name="fas-calendar" aria-hidden="true"></ion-icon><strong>{{ date.label }}</strong> {{ date.timestamp | ||||
|             * | ||||
|             1000 | coreFormatDate:'strftimedatetime' }} | ||||
|         </p> | ||||
|     </div> | ||||
| 
 | ||||
|     <!-- Availability info space. --> | ||||
|     <div class="core-module-availabilityinfo" *ngIf="showAvailabilityInfo"> | ||||
|     <div class="core-module-availabilityinfo core-module-info-box-section" *ngIf="showAvailabilityInfo"> | ||||
|         <ion-icon name="fas-lock" [attr.aria-label]="'core.restricted' | translate"></ion-icon> | ||||
|         <core-format-text [text]="module.availabilityinfo" contextLevel="module" [contextInstanceId]="module.id" [courseId]="module.course"> | ||||
|         </core-format-text> | ||||
|     </div> | ||||
| </div> | ||||
| 
 | ||||
| <ion-item class="ion-text-wrap" *ngIf="description"> | ||||
|     <ion-label> | ||||
|     <div class="core-module-info-description core-module-info-box-section" *ngIf="description"> | ||||
|         <core-format-text [text]="description" [component]="component" [componentId]="componentId" contextLevel="module" | ||||
|             [contextInstanceId]="module.id" [courseId]="courseId" [collapsible-item]="expandDescription ? null : ''"> | ||||
|         </core-format-text> | ||||
|     </ion-label> | ||||
| </ion-item> | ||||
| <ng-content select="[description]"></ng-content> | ||||
|     </div> | ||||
|     <ng-content select="[description]"></ng-content> | ||||
| </div> | ||||
| 
 | ||||
| <ng-content></ng-content> | ||||
| 
 | ||||
|  | ||||
| @ -23,27 +23,46 @@ | ||||
| 
 | ||||
|     } | ||||
| 
 | ||||
|     .core-module-dates-availabilityinfo { | ||||
|     .core-module-info-box { | ||||
|         background: var(--light); | ||||
|         border-radius: var(--small-radius); | ||||
|         padding: 8px; | ||||
|         margin: 8px; | ||||
|         font-size: 90%; | ||||
|         ion-icon { | ||||
|             position: static; | ||||
|             @include margin-horizontal(null, 8px); | ||||
|         padding: 8px; | ||||
| 
 | ||||
|         ::ng-deep ion-item { | ||||
|             --ion-item-background: var(--light); | ||||
|             --background: var(--light); | ||||
|         } | ||||
| 
 | ||||
|         p, | ||||
|         ul { | ||||
|             margin-top: 4px; | ||||
|             margin-bottom: 4px; | ||||
|         ::ng-deep ion-card.card-file { | ||||
|             --ion-card-horizontal-margin: 0px; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     .core-module-dates + .core-module-availabilityinfo { | ||||
|         border-top: 1px solid var(--stroke); | ||||
|         padding-top: 8px; | ||||
|         .core-module-info-box-section + .core-module-info-box-section { | ||||
|             border-top: 1px solid var(--stroke); | ||||
|             margin-top: 8px; | ||||
|             padding-top: 8px; | ||||
|         } | ||||
| 
 | ||||
|         .core-module-dates ion-icon { | ||||
|             margin-left: 4px; | ||||
|             margin-right: 4px; | ||||
|         } | ||||
| 
 | ||||
|         .core-module-dates, | ||||
|         .core-module-availabilityinfo { | ||||
|             font-size: 90%; | ||||
|             ion-icon { | ||||
|                 position: static; | ||||
|                 @include margin-horizontal(null, 8px); | ||||
|             } | ||||
| 
 | ||||
|             p, | ||||
|             ul { | ||||
|                 margin-top: 4px; | ||||
|                 margin-bottom: 4px; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     core-course-module-completion ::ng-deep ion-button { | ||||
|  | ||||
| @ -21,6 +21,10 @@ | ||||
|         margin-top: var(--button-vertical-margin); | ||||
|         margin-bottom: var(--button-vertical-margin); | ||||
|     } | ||||
| 
 | ||||
|     &.empty { | ||||
|         display: none; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| :host-context(core-course-format.core-course-format-singleactivity) { | ||||
|  | ||||