forked from EVOgeek/Vmeda.Online
		
	MOBILE-4176 grades: Fix 4.1 layout
Fixes some breaking changes introduced in MDL-75513. The fixes included here are not exhaustive but should take care of the basic scenarios covered by e2e tests. Subsequent fixes will be provided to handle other edge-cases.
This commit is contained in:
		
							parent
							
								
									d0e3ad6ee8
								
							
						
					
					
						commit
						49e0491428
					
				| @ -27,13 +27,18 @@ | |||||||
|                 </thead> |                 </thead> | ||||||
|                 <tbody> |                 <tbody> | ||||||
|                     <ng-container *ngFor="let row of rows"> |                     <ng-container *ngFor="let row of rows"> | ||||||
|  |                         <tr *ngIf="!useLegacyLayout && row.itemtype === 'leader'"> | ||||||
|  |                             <td [attr.rowspan]="row.rowspan" class="core-grades-table-leader"></td> | ||||||
|  |                         </tr> | ||||||
|                         <tr [attr.role]="row.expandable && showSummary ? 'button row' : 'row'" |                         <tr [attr.role]="row.expandable && showSummary ? 'button row' : 'row'" | ||||||
|                             [attr.tabindex]="row.expandable && showSummary && 0" [attr.aria-expanded]="row.expanded" |                             [attr.tabindex]="row.expandable && showSummary && 0" [attr.aria-expanded]="row.expanded" | ||||||
|                             [attr.aria-label]="rowAriaLabel(row)" [attr.aria-controls]="row.detailsid" |                             [attr.aria-label]="rowAriaLabel(row)" [attr.aria-controls]="row.detailsid" | ||||||
|                             (ariaButtonClick)="row.expandable && showSummary && toggleRow(row)" [class]="row.rowclass" |                             (ariaButtonClick)="row.expandable && showSummary && toggleRow(row)" [class]="row.rowclass" | ||||||
|                             [class.core-grades-grade-clickable]="row.expandable && showSummary" [id]="'grade-'+row.id"> |                             [class.core-grades-grade-clickable]="row.expandable && showSummary" [id]="'grade-'+row.id" | ||||||
|  |                             *ngIf="useLegacyLayout || row.itemtype !== 'leader'"> | ||||||
|                             <ng-container *ngIf="row.itemtype"> |                             <ng-container *ngIf="row.itemtype"> | ||||||
|                                 <td *ngIf="row.itemtype == 'category'" class="core-grades-table-category" [attr.rowspan]="row.rowspan"> |                                 <td *ngIf="!useLegacyLayout && row.itemtype == 'category'" class="core-grades-table-category" | ||||||
|  |                                     [attr.rowspan]="row.rowspan"> | ||||||
|                                 </td> |                                 </td> | ||||||
|                                 <th class="core-grades-table-gradeitem ion-text-start" [attr.colspan]="row.colspan"> |                                 <th class="core-grades-table-gradeitem ion-text-start" [attr.colspan]="row.colspan"> | ||||||
|                                     <ion-icon *ngIf="row.expandable && showSummary" aria-hidden="true" slot="start" name="fas-chevron-right" |                                     <ion-icon *ngIf="row.expandable && showSummary" aria-hidden="true" slot="start" name="fas-chevron-right" | ||||||
| @ -48,6 +53,7 @@ | |||||||
|                                     </core-mod-icon> |                                     </core-mod-icon> | ||||||
|                                     <span [innerHTML]="row.gradeitem"></span> |                                     <span [innerHTML]="row.gradeitem"></span> | ||||||
|                                 </th> |                                 </th> | ||||||
|  |                                 <ng-container *ngIf="row.itemtype !== 'category'"> | ||||||
|                                     <ng-container *ngFor="let column of columns"> |                                     <ng-container *ngFor="let column of columns"> | ||||||
|                                         <td *ngIf="column.name !== 'gradeitem' && column.name !== 'feedback' && column.name !== 'grade' && |                                         <td *ngIf="column.name !== 'gradeitem' && column.name !== 'feedback' && column.name !== 'grade' && | ||||||
|                                         row[column.name] != undefined" [class]="'ion-text-start core-grades-table-' + column.name" |                                         row[column.name] != undefined" [class]="'ion-text-start core-grades-table-' + column.name" | ||||||
| @ -67,6 +73,7 @@ | |||||||
|                                         </td> |                                         </td> | ||||||
|                                     </ng-container> |                                     </ng-container> | ||||||
|                                 </ng-container> |                                 </ng-container> | ||||||
|  |                             </ng-container> | ||||||
|                         </tr> |                         </tr> | ||||||
|                         <tr *ngIf="row.expandable" [id]="row.detailsid" [class]="row.rowclass" [hidden]="!row.expanded"> |                         <tr *ngIf="row.expandable" [id]="row.detailsid" [class]="row.rowclass" [hidden]="!row.expanded"> | ||||||
|                             <td [attr.colspan]="totalColumnsSpan"> |                             <td [attr.colspan]="totalColumnsSpan"> | ||||||
|  | |||||||
| @ -54,6 +54,7 @@ export class CoreGradesCoursePage implements AfterViewInit, OnDestroy { | |||||||
|     rows?: CoreGradesFormattedTableRow[]; |     rows?: CoreGradesFormattedTableRow[]; | ||||||
|     totalColumnsSpan?: number; |     totalColumnsSpan?: number; | ||||||
|     withinSplitView?: boolean; |     withinSplitView?: boolean; | ||||||
|  |     useLegacyLayout?: boolean; // Whether to use the layout before 4.1.
 | ||||||
| 
 | 
 | ||||||
|     protected fetchSuccess = false; |     protected fetchSuccess = false; | ||||||
| 
 | 
 | ||||||
| @ -68,6 +69,7 @@ export class CoreGradesCoursePage implements AfterViewInit, OnDestroy { | |||||||
| 
 | 
 | ||||||
|             this.expandLabel = Translate.instant('core.expand'); |             this.expandLabel = Translate.instant('core.expand'); | ||||||
|             this.collapseLabel = Translate.instant('core.collapse'); |             this.collapseLabel = Translate.instant('core.collapse'); | ||||||
|  |             this.useLegacyLayout = !CoreSites.getRequiredCurrentSite().isVersionGreaterEqualThan('4.1'); | ||||||
| 
 | 
 | ||||||
|             if (route.snapshot.data.swipeEnabled ?? true) { |             if (route.snapshot.data.swipeEnabled ?? true) { | ||||||
|                 const source = CoreRoutedItemsManagerSourcesTracker.getOrCreateSource(CoreGradesCoursesSource, []); |                 const source = CoreRoutedItemsManagerSourcesTracker.getOrCreateSource(CoreGradesCoursesSource, []); | ||||||
| @ -133,11 +135,22 @@ export class CoreGradesCoursePage implements AfterViewInit, OnDestroy { | |||||||
| 
 | 
 | ||||||
|         row.expanded = expand ?? !row.expanded; |         row.expanded = expand ?? !row.expanded; | ||||||
| 
 | 
 | ||||||
|         let colspan: number = this.columns.length + (row.colspan ?? 0) - 1; |         let colspan: number = this.columns.length + (row.colspan ?? 0); | ||||||
|  | 
 | ||||||
|  |         if (this.useLegacyLayout) { | ||||||
|  |             colspan--; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|         for (let i = this.rows.indexOf(row) - 1; i >= 0; i--) { |         for (let i = this.rows.indexOf(row) - 1; i >= 0; i--) { | ||||||
|             const previousRow = this.rows[i]; |             const previousRow = this.rows[i]; | ||||||
| 
 | 
 | ||||||
|             if (previousRow.expandable || !previousRow.colspan || !previousRow.rowspan || previousRow.colspan !== colspan) { |             if ( | ||||||
|  |                 !previousRow.rowspan || | ||||||
|  |                 !previousRow.colspan || | ||||||
|  |                 previousRow.colspan !== colspan || | ||||||
|  |                 (!this.useLegacyLayout && previousRow.itemtype !== 'leader') || | ||||||
|  |                 (this.useLegacyLayout && previousRow.expandable) | ||||||
|  |             ) { | ||||||
|                 continue; |                 continue; | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -124,6 +124,14 @@ | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     .core-grades-table-leader { | ||||||
|  |         width: 0; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     .ion-no-border { | ||||||
|  |         border: 0 !important; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     .dimmed_text, |     .dimmed_text, | ||||||
|     .hidden { |     .hidden { | ||||||
|         opacity: .7; |         opacity: .7; | ||||||
|  | |||||||
| @ -25,6 +25,7 @@ import { | |||||||
|     CoreGradesTable, |     CoreGradesTable, | ||||||
|     CoreGradesTableColumn, |     CoreGradesTableColumn, | ||||||
|     CoreGradesTableItemNameColumn, |     CoreGradesTableItemNameColumn, | ||||||
|  |     CoreGradesTableLeaderColumn, | ||||||
|     CoreGradesTableRow, |     CoreGradesTableRow, | ||||||
| } from '@features/grades/services/grades'; | } from '@features/grades/services/grades'; | ||||||
| import { CoreTextUtils } from '@services/utils/text'; | import { CoreTextUtils } from '@services/utils/text'; | ||||||
| @ -71,7 +72,8 @@ export class CoreGradesHelperProvider { | |||||||
|             let content = String(column.content); |             let content = String(column.content); | ||||||
| 
 | 
 | ||||||
|             if (name == 'itemname') { |             if (name == 'itemname') { | ||||||
|                 await this.setRowIcon(row, content); |                 this.setRowIconAndType(row, content); | ||||||
|  | 
 | ||||||
|                 row.link = this.getModuleLink(content); |                 row.link = this.getModuleLink(content); | ||||||
|                 row.rowclass += column.class.indexOf('hidden') >= 0 ? ' hidden' : ''; |                 row.rowclass += column.class.indexOf('hidden') >= 0 ? ' hidden' : ''; | ||||||
|                 row.rowclass += column.class.indexOf('dimmed_text') >= 0 ? ' dimmed_text' : ''; |                 row.rowclass += column.class.indexOf('dimmed_text') >= 0 ? ' dimmed_text' : ''; | ||||||
| @ -96,10 +98,23 @@ export class CoreGradesHelperProvider { | |||||||
|      * Formats a row from the grades table to be rendered in one table. |      * Formats a row from the grades table to be rendered in one table. | ||||||
|      * |      * | ||||||
|      * @param tableRow JSON object representing row of grades table data. |      * @param tableRow JSON object representing row of grades table data. | ||||||
|  |      * @param useLegacyLayout Whether to use the layout before 4.1. | ||||||
|      * @return Formatted row object. |      * @return Formatted row object. | ||||||
|      */ |      */ | ||||||
|     protected formatGradeRowForTable(tableRow: CoreGradesTableRow): CoreGradesFormattedTableRow { |     protected formatGradeRowForTable(tableRow: CoreGradesTableRow, useLegacyLayout: boolean): CoreGradesFormattedTableRow { | ||||||
|         const row: CoreGradesFormattedTableRow = {}; |         const row: CoreGradesFormattedTableRow = {}; | ||||||
|  | 
 | ||||||
|  |         if (!useLegacyLayout && 'leader' in tableRow) { | ||||||
|  |             const row = { | ||||||
|  |                 itemtype: 'leader', | ||||||
|  |                 rowspan: tableRow.leader?.rowspan, | ||||||
|  |             }; | ||||||
|  | 
 | ||||||
|  |             this.setRowEvenOddClass(row, (tableRow.leader as CoreGradesTableLeaderColumn).class); | ||||||
|  | 
 | ||||||
|  |             return row; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|         for (let name in tableRow) { |         for (let name in tableRow) { | ||||||
|             const column: CoreGradesTableColumn = tableRow[name]; |             const column: CoreGradesTableColumn = tableRow[name]; | ||||||
| 
 | 
 | ||||||
| @ -116,13 +131,13 @@ export class CoreGradesHelperProvider { | |||||||
|                 row.colspan = itemNameColumn.colspan; |                 row.colspan = itemNameColumn.colspan; | ||||||
|                 row.rowspan = tableRow.leader?.rowspan || 1; |                 row.rowspan = tableRow.leader?.rowspan || 1; | ||||||
| 
 | 
 | ||||||
|                 this.setRowIcon(row, content); |                 this.setRowIconAndType(row, content); | ||||||
|                 row.rowclass = itemNameColumn.class.indexOf('leveleven') < 0 ? 'odd' : 'even'; |                 this.setRowEvenOddClass(row, itemNameColumn.class); | ||||||
|                 row.rowclass += itemNameColumn.class.indexOf('hidden') >= 0 ? ' hidden' : ''; |                 row.rowclass += itemNameColumn.class.indexOf('hidden') >= 0 ? ' hidden' : ''; | ||||||
|                 row.rowclass += itemNameColumn.class.indexOf('dimmed_text') >= 0 ? ' dimmed_text' : ''; |                 row.rowclass += itemNameColumn.class.indexOf('dimmed_text') >= 0 ? ' dimmed_text' : ''; | ||||||
| 
 | 
 | ||||||
|                 content = content.replace(/<\/span>/gi, '\n'); |                 content = content.replace(/<\/span>/gi, '\n'); | ||||||
|                 content = CoreTextUtils.cleanTags(content); |                 content = CoreTextUtils.cleanTags(content, true); | ||||||
|                 name = 'gradeitem'; |                 name = 'gradeitem'; | ||||||
|             } else if (name === 'grade') { |             } else if (name === 'grade') { | ||||||
|                 // Add the pass/fail class if present.
 |                 // Add the pass/fail class if present.
 | ||||||
| @ -202,7 +217,7 @@ export class CoreGradesHelperProvider { | |||||||
|             feedback: false, |             feedback: false, | ||||||
|             contributiontocoursetotal: false, |             contributiontocoursetotal: false, | ||||||
|         }; |         }; | ||||||
|         formatted.rows = table.tabledata.map(row => this.formatGradeRowForTable(row)); |         formatted.rows = this.formatGradesTableRows(table.tabledata); | ||||||
| 
 | 
 | ||||||
|         // Get a row with some info.
 |         // Get a row with some info.
 | ||||||
|         let normalRow = formatted.rows.find( |         let normalRow = formatted.rows.find( | ||||||
| @ -234,6 +249,33 @@ export class CoreGradesHelperProvider { | |||||||
|         return formatted; |         return formatted; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     /** | ||||||
|  |      * Format table rows. | ||||||
|  |      * | ||||||
|  |      * @param rows Unformatted rows. | ||||||
|  |      * @returns Formatted rows. | ||||||
|  |      */ | ||||||
|  |     protected formatGradesTableRows(rows: CoreGradesTableRow[]): CoreGradesFormattedTableRow[] { | ||||||
|  |         const useLegacyLayout = !CoreSites.getRequiredCurrentSite().isVersionGreaterEqualThan('4.1'); | ||||||
|  |         const formattedRows = rows.map(row => this.formatGradeRowForTable(row, useLegacyLayout)); | ||||||
|  | 
 | ||||||
|  |         if (!useLegacyLayout) { | ||||||
|  |             for (let index = 0; index < formattedRows.length - 1; index++) { | ||||||
|  |                 const row = formattedRows[index]; | ||||||
|  |                 const previousRow = formattedRows[index - 1] ?? null; | ||||||
|  | 
 | ||||||
|  |                 if (row.itemtype !== 'leader') { | ||||||
|  |                     continue; | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |                 row.colspan = previousRow.colspan; | ||||||
|  |                 previousRow.rowclass = `${previousRow.rowclass ?? ''} ion-no-border`.trim(); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         return formattedRows; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     /** |     /** | ||||||
|      * Get course data for grades since they only have courseid. |      * Get course data for grades since they only have courseid. | ||||||
|      * |      * | ||||||
| @ -474,7 +516,7 @@ export class CoreGradesHelperProvider { | |||||||
|         // Find href containing "/mod/xxx/xxx.php".
 |         // Find href containing "/mod/xxx/xxx.php".
 | ||||||
|         const regex = /href="([^"]*\/mod\/[^"|^/]*\/[^"|^.]*\.php[^"]*)/; |         const regex = /href="([^"]*\/mod\/[^"|^/]*\/[^"|^.]*\.php[^"]*)/; | ||||||
| 
 | 
 | ||||||
|         return table.tabledata.filter((row) => { |         return this.formatGradesTableRows(table.tabledata.filter((row) => { | ||||||
|             if (row.itemname && row.itemname.content) { |             if (row.itemname && row.itemname.content) { | ||||||
|                 const matches = row.itemname.content.match(regex); |                 const matches = row.itemname.content.match(regex); | ||||||
| 
 | 
 | ||||||
| @ -486,7 +528,7 @@ export class CoreGradesHelperProvider { | |||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             return false; |             return false; | ||||||
|         }).map((row) => this.formatGradeRowForTable(row)); |         })); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
| @ -582,14 +624,25 @@ export class CoreGradesHelperProvider { | |||||||
|         return CoreGrades.invalidateCourseGradesItemsData(courseId, userId, groupId, siteId); |         return CoreGrades.invalidateCourseGradesItemsData(courseId, userId, groupId, siteId); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     /** | ||||||
|  |      * Set 'odd' or 'even' classes into a row. | ||||||
|  |      * | ||||||
|  |      * @param row Row. | ||||||
|  |      * @param classes Existing row classes. | ||||||
|  |      */ | ||||||
|  |     protected setRowEvenOddClass(row: CoreGradesFormattedTableRow, classes: string): void { | ||||||
|  |         const level = parseInt(classes.match(/(?:^|\s)level(\d+)(?:$|\s)/)?.[1] ?? '0'); | ||||||
|  | 
 | ||||||
|  |         row.rowclass = `${row.rowclass ?? ''} ${level % 2 === 0 ? 'even' : 'odd'}`.trim(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     /** |     /** | ||||||
|      * Parses the image and sets it to the row. |      * Parses the image and sets it to the row. | ||||||
|      * |      * | ||||||
|      * @param row Formatted grade row object. |      * @param row Row. | ||||||
|      * @param text HTML where the image will be rendered. |      * @param text Row content. | ||||||
|      * @return Row object with the image. |  | ||||||
|      */ |      */ | ||||||
|     protected setRowIcon<T extends CoreGradesFormattedRowCommonData>(row: T, text: string): T { |     protected setRowIconAndType(row: CoreGradesFormattedRowCommonData, text: string): void { | ||||||
|         text = text.replace('%2F', '/').replace('%2f', '/'); |         text = text.replace('%2F', '/').replace('%2f', '/'); | ||||||
|         if (text.indexOf('/agg_mean') > -1) { |         if (text.indexOf('/agg_mean') > -1) { | ||||||
|             row.itemtype = 'agg_mean'; |             row.itemtype = 'agg_mean'; | ||||||
| @ -603,7 +656,7 @@ export class CoreGradesHelperProvider { | |||||||
|             row.itemtype = 'outcome'; |             row.itemtype = 'outcome'; | ||||||
|             row.icon = 'fas-tasks'; |             row.icon = 'fas-tasks'; | ||||||
|             row.iconAlt = Translate.instant('core.grades.outcome'); |             row.iconAlt = Translate.instant('core.grades.outcome'); | ||||||
|         } else if (text.indexOf('i/folder') > -1 || text.indexOf('fa-folder') > -1) { |         } else if (text.indexOf('i/folder') > -1 || text.indexOf('fa-folder') > -1 || text.indexOf('category-content') > -1) { | ||||||
|             row.itemtype = 'category'; |             row.itemtype = 'category'; | ||||||
|             row.icon = 'fas-folder'; |             row.icon = 'fas-folder'; | ||||||
|             row.iconAlt = Translate.instant('core.grades.category'); |             row.iconAlt = Translate.instant('core.grades.category'); | ||||||
| @ -643,8 +696,6 @@ export class CoreGradesHelperProvider { | |||||||
|                 row.iconAlt = Translate.instant('core.unknown'); |                 row.iconAlt = Translate.instant('core.unknown'); | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| 
 |  | ||||||
|         return row; |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user