MOBILE-2326 grades: Course grade item page
parent
4903b31cb0
commit
38a9f019bb
|
@ -54,12 +54,14 @@
|
|||
@include media-breakpoint-down(md) {
|
||||
.hidden-phone {
|
||||
display: none !important;
|
||||
opacity: 0 !important;
|
||||
}
|
||||
}
|
||||
|
||||
@include media-breakpoint-up(md) {
|
||||
.hidden-tablet {
|
||||
display: none !important;
|
||||
opacity: 0 !important;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
<tr *ngFor="let row of gradesTable.rows" (click)="row.itemtype != 'category' && gotoGrade(row.id)" [class]="row.rowclass">
|
||||
<td *ngIf="row.itemtype == 'category'" class="core-grades-table-category" [attr.rowspan]="row.rowspan">
|
||||
</td>
|
||||
<th class="core-grades-table-gradeitem" [attr.colspan]="row.colspan">
|
||||
<th class="core-grades-table-gradeitem" [attr.colspan]="row.colspan" [class.core-split-item-selected]="gradeId == row.id">
|
||||
<ion-icon *ngIf="row.icon" name="{{row.icon}}" item-start></ion-icon>
|
||||
<img *ngIf="row.image" [src]="row.image" item-start/>
|
||||
<span [innerHTML]="row.gradeitem"></span>
|
||||
|
|
|
@ -53,12 +53,12 @@ core-grades-course {
|
|||
}
|
||||
|
||||
.odd {
|
||||
td, th {
|
||||
td, th, th.core-split-item-selected {
|
||||
background-color: $gray-lighter;
|
||||
}
|
||||
}
|
||||
.even {
|
||||
td, th {
|
||||
td, th, th.core-split-item-selected {
|
||||
background-color: $white;
|
||||
}
|
||||
}
|
||||
|
@ -69,4 +69,11 @@ core-grades-course {
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.split-pane-side, .split-pane-main {
|
||||
core-grades-course .core-grades-table .hidden-phone {
|
||||
display: none;
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,12 +12,14 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import { Component, ViewChild, Input } from '@angular/core';
|
||||
import { Component, ViewChild, Input, Optional } from '@angular/core';
|
||||
import { Content, NavParams, NavController } from 'ionic-angular';
|
||||
import { CoreGradesProvider } from '../../providers/grades';
|
||||
import { CoreSitesProvider } from '../../../../providers/sites';
|
||||
import { CoreDomUtilsProvider } from '../../../../providers/utils/dom';
|
||||
import { CoreGradesHelperProvider } from '../../providers/helper';
|
||||
import { CoreSplitViewComponent } from '../../../../components/split-view/split-view';
|
||||
import { CoreAppProvider } from '../../../../providers/app';
|
||||
|
||||
/**
|
||||
* Component that displays a course grades.
|
||||
|
@ -31,13 +33,15 @@ export class CoreGradesCourseComponent {
|
|||
|
||||
@Input() courseId: number;
|
||||
@Input() userId: number;
|
||||
@Input() gradeId?: number;
|
||||
|
||||
errorMessage: string;
|
||||
gradesLoaded = false;
|
||||
gradesTable: any;
|
||||
|
||||
constructor(private gradesProvider: CoreGradesProvider, private domUtils: CoreDomUtilsProvider, navParams: NavParams,
|
||||
private gradesHelper: CoreGradesHelperProvider, private sitesProvider: CoreSitesProvider, private navCtrl: NavController) {
|
||||
private gradesHelper: CoreGradesHelperProvider, private sitesProvider: CoreSitesProvider, private navCtrl: NavController,
|
||||
private appProvider: CoreAppProvider, @Optional() private svComponent: CoreSplitViewComponent) {
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -46,6 +50,11 @@ export class CoreGradesCourseComponent {
|
|||
ngOnInit(): void {
|
||||
// Get first participants.
|
||||
this.fetchData().then(() => {
|
||||
if (this.gradeId) {
|
||||
// There is the grade to load.
|
||||
this.gotoGrade(this.gradeId);
|
||||
}
|
||||
|
||||
// Add log in Moodle.
|
||||
return this.gradesProvider.logCourseGradesView(this.courseId, this.userId);
|
||||
}).finally(() => {
|
||||
|
@ -82,12 +91,37 @@ export class CoreGradesCourseComponent {
|
|||
}
|
||||
|
||||
/**
|
||||
* Navigate to the grades of the selected item.
|
||||
* Navigate to the grade of the selected item.
|
||||
* @param {number} gradeId Grade item ID where to navigate.
|
||||
*/
|
||||
gotoGrade(gradeId: number): void {
|
||||
if (gradeId) {
|
||||
this.navCtrl.push('CoreGradesGradePage', {courseId: this.courseId, userId: this.userId, gradeId: gradeId});
|
||||
this.gradeId = gradeId;
|
||||
let whereToPush, pageName;
|
||||
|
||||
if (this.svComponent) {
|
||||
if (this.svComponent.getMasterNav().getActive().component.name == 'CoreGradesCourseSplitPage') {
|
||||
// Table is on left side. Push on right.
|
||||
whereToPush = this.svComponent;
|
||||
pageName = 'CoreGradesGradePage';
|
||||
} else {
|
||||
// Table is on right side. Load new split view.
|
||||
whereToPush = this.svComponent.getMasterNav();
|
||||
pageName = 'CoreGradesCourseSplitPage';
|
||||
}
|
||||
} else {
|
||||
if (this.appProvider.isWide()) {
|
||||
// Table is full screen and large. Load here.
|
||||
whereToPush = this.navCtrl;
|
||||
pageName = 'CoreGradesCourseSplitPage';
|
||||
} else {
|
||||
// Table is full screen but on mobile. Load here.
|
||||
whereToPush = this.navCtrl;
|
||||
pageName = 'CoreGradesGradePage';
|
||||
}
|
||||
|
||||
}
|
||||
whereToPush.push(pageName, {courseId: this.courseId, userId: this.userId, gradeId: gradeId});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -37,7 +37,7 @@ export class CoreGradesCoursesPage {
|
|||
gradesLoaded = false;
|
||||
|
||||
constructor(private gradesProvider: CoreGradesProvider, private domUtils: CoreDomUtilsProvider,
|
||||
private courseHelper: CoreGradesHelperProvider) {
|
||||
private gradesHelper: CoreGradesHelperProvider) {
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -45,11 +45,10 @@ export class CoreGradesCoursesPage {
|
|||
*/
|
||||
ionViewDidLoad(): void {
|
||||
if (this.courseId) {
|
||||
// There is an event to load, open the event in a new state.
|
||||
// There is the course to load, open the course in a new state.
|
||||
this.gotoCourseGrades(this.courseId);
|
||||
}
|
||||
|
||||
// Get first participants.
|
||||
this.fetchData().then(() => {
|
||||
if (!this.courseId && this.splitviewCtrl.isOn() && this.grades.length > 0) {
|
||||
this.gotoCourseGrades(this.grades[0].courseid);
|
||||
|
@ -69,7 +68,7 @@ export class CoreGradesCoursesPage {
|
|||
*/
|
||||
fetchData(): Promise<any> {
|
||||
return this.gradesProvider.getCoursesGrades().then((grades) => {
|
||||
return this.courseHelper.getGradesCourseData(grades).then((grades) => {
|
||||
return this.gradesHelper.getGradesCourseData(grades).then((grades) => {
|
||||
this.grades = grades;
|
||||
});
|
||||
}).catch((error) => {
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
<ion-header>
|
||||
<ion-navbar>
|
||||
<ion-title>{{ 'core.grades.grades' | translate }}</ion-title>
|
||||
</ion-navbar>
|
||||
</ion-header>
|
||||
<core-split-view>
|
||||
<core-grades-course class="core-avoid-header" [courseId]="courseId" [userId]="userId" [gradeId]="gradeId"></core-grades-course>
|
||||
</core-split-view>
|
||||
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
// (C) Copyright 2015 Martin Dougiamas
|
||||
//
|
||||
// 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 { NgModule } from '@angular/core';
|
||||
import { IonicPageModule } from 'ionic-angular';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { CoreGradesCourseSplitPage } from './coursesplit';
|
||||
import { CoreComponentsModule } from '../../../../components/components.module';
|
||||
import { CoreDirectivesModule } from '../../../../directives/directives.module';
|
||||
import { CoreGradesComponentsModule } from '../../components/components.module';
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
CoreGradesCourseSplitPage
|
||||
],
|
||||
imports: [
|
||||
CoreGradesComponentsModule,
|
||||
CoreComponentsModule,
|
||||
CoreDirectivesModule,
|
||||
IonicPageModule.forChild(CoreGradesCourseSplitPage),
|
||||
TranslateModule.forChild()
|
||||
],
|
||||
})
|
||||
export class CoreGradesCourseSplitPageModule {}
|
|
@ -0,0 +1,38 @@
|
|||
// (C) Copyright 2015 Martin Dougiamas
|
||||
//
|
||||
// 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 } from '@angular/core';
|
||||
import { IonicPage, NavParams } from 'ionic-angular';
|
||||
import { CoreSitesProvider } from '../../../../providers/sites';
|
||||
|
||||
/**
|
||||
* Page that displays a course grades.
|
||||
*/
|
||||
@IonicPage({ segment: 'core-grades-course-split' })
|
||||
@Component({
|
||||
selector: 'page-core-grades-course-split',
|
||||
templateUrl: 'coursesplit.html',
|
||||
})
|
||||
export class CoreGradesCourseSplitPage {
|
||||
|
||||
courseId: number;
|
||||
userId: number;
|
||||
gradeId: number;
|
||||
|
||||
constructor(navParams: NavParams, sitesProvider: CoreSitesProvider) {
|
||||
this.courseId = navParams.get('courseId');
|
||||
this.userId = navParams.get('userId') || sitesProvider.getCurrentSiteUserId();
|
||||
this.gradeId = navParams.get('gradeId');
|
||||
}
|
||||
}
|
|
@ -0,0 +1,72 @@
|
|||
<ion-header>
|
||||
<ion-navbar>
|
||||
<ion-title>{{ 'core.grades.grade' | translate }}</ion-title>
|
||||
</ion-navbar>
|
||||
</ion-header>
|
||||
<ion-content>
|
||||
<ion-refresher [enabled]="gradeLoaded" (ionRefresh)="refreshGrade($event)">
|
||||
<ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}"></ion-refresher-content>
|
||||
</ion-refresher>
|
||||
<core-loading [hideUntil]="gradeLoaded">
|
||||
<core-empty-box *ngIf="!grade" icon="stats" [message]="errormessage"></core-empty-box>
|
||||
|
||||
<ion-list *ngIf="grade">
|
||||
<a ion-item *ngIf="grade.itemname && grade.link" text-wrap detail-push [href]="grade.link" core-link captureLink="true">
|
||||
<ion-icon *ngIf="grade.icon" name="{{grade.icon}}" item-start></ion-icon>
|
||||
<img *ngIf="grade.image" [src]="grade.image" item-start/>
|
||||
<h2><core-format-text [text]="grade.itemname"></core-format-text></h2>
|
||||
</a>
|
||||
|
||||
<ion-item *ngIf="grade.itemname && !grade.link" text-wrap >
|
||||
<ion-icon *ngIf="grade.icon" name="{{grade.icon}}" item-start></ion-icon>
|
||||
<img *ngIf="grade.image" [src]="grade.image" item-start/>
|
||||
<h2><core-format-text [text]="grade.itemname"></core-format-text></h2>
|
||||
</ion-item>
|
||||
|
||||
<ion-item text-wrap *ngIf="grade.weight">
|
||||
<h2>{{ 'core.grades.weight' | translate}}</h2>
|
||||
<p><core-format-text [text]="grade.weight"></core-format-text></p>
|
||||
</ion-item>
|
||||
|
||||
<ion-item text-wrap *ngIf="grade.grade">
|
||||
<h2>{{ 'core.grades.grade' | translate}}</h2>
|
||||
<p><core-format-text [text]="grade.grade"></core-format-text></p>
|
||||
</ion-item>
|
||||
|
||||
<ion-item text-wrap *ngIf="grade.range">
|
||||
<h2>{{ 'core.grades.range' | translate}}</h2>
|
||||
<p><core-format-text [text]="grade.range"></core-format-text></p>
|
||||
</ion-item>
|
||||
|
||||
<ion-item text-wrap *ngIf="grade.percentage">
|
||||
<h2>{{ 'core.grades.percentage' | translate}}</h2>
|
||||
<p><core-format-text [text]="grade.percentage"></core-format-text></p>
|
||||
</ion-item>
|
||||
|
||||
<ion-item text-wrap *ngIf="grade.lettergrade">
|
||||
<h2>{{ 'core.grades.lettergrade' | translate}}</h2>
|
||||
<p><core-format-text [text]="grade.lettergrade"></core-format-text></p>
|
||||
</ion-item>
|
||||
|
||||
<ion-item text-wrap *ngIf="grade.rank">
|
||||
<h2>{{ 'core.grades.rank' | translate}}</h2>
|
||||
<p><core-format-text [text]="grade.rank"></core-format-text></p>
|
||||
</ion-item>
|
||||
|
||||
<ion-item text-wrap *ngIf="grade.average">
|
||||
<h2>{{ 'core.grades.average' | translate}}</h2>
|
||||
<p><core-format-text [text]="grade.average"></core-format-text></p>
|
||||
</ion-item>
|
||||
|
||||
<ion-item text-wrap *ngIf="grade.feedback">
|
||||
<h2>{{ 'core.grades.feedback' | translate}}</h2>
|
||||
<p><core-format-text [fullTitle]="'core.grades.feedback' | translate" maxHeight="60" fullOnClick="true" [text]="grade.feedback"></core-format-text></p>
|
||||
</ion-item>
|
||||
|
||||
<ion-item text-wrap *ngIf="grade.contributiontocoursetotal">
|
||||
<h2>{{ 'core.grades.contributiontocoursetotal' | translate}}</h2>
|
||||
<p><core-format-text [text]="grade.contributiontocoursetotal"></core-format-text></p>
|
||||
</ion-item>
|
||||
</ion-list>
|
||||
</core-loading>
|
||||
</ion-content>
|
|
@ -0,0 +1,33 @@
|
|||
// (C) Copyright 2015 Martin Dougiamas
|
||||
//
|
||||
// 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 { NgModule } from '@angular/core';
|
||||
import { IonicPageModule } from 'ionic-angular';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { CoreGradesGradePage } from './grade';
|
||||
import { CoreComponentsModule } from '../../../../components/components.module';
|
||||
import { CoreDirectivesModule } from '../../../../directives/directives.module';
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
CoreGradesGradePage
|
||||
],
|
||||
imports: [
|
||||
CoreComponentsModule,
|
||||
CoreDirectivesModule,
|
||||
IonicPageModule.forChild(CoreGradesGradePage),
|
||||
TranslateModule.forChild()
|
||||
],
|
||||
})
|
||||
export class CoreGradesGradePageModule {}
|
|
@ -0,0 +1,84 @@
|
|||
// (C) Copyright 2015 Martin Dougiamas
|
||||
//
|
||||
// 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, ViewChild } from '@angular/core';
|
||||
import { IonicPage, Content, NavParams } from 'ionic-angular';
|
||||
import { CoreGradesProvider } from '../../providers/grades';
|
||||
import { CoreDomUtilsProvider } from '../../../../providers/utils/dom';
|
||||
import { CoreSplitViewComponent } from '../../../../components/split-view/split-view';
|
||||
import { CoreGradesHelperProvider } from '../../providers/helper';
|
||||
import { CoreSitesProvider } from '../../../../providers/sites';
|
||||
|
||||
/**
|
||||
* Page that displays activity grade.
|
||||
*/
|
||||
@IonicPage({ segment: 'core-grades-grade' })
|
||||
@Component({
|
||||
selector: 'page-core-grades-grade',
|
||||
templateUrl: 'grade.html',
|
||||
})
|
||||
export class CoreGradesGradePage {
|
||||
@ViewChild(Content) content: Content;
|
||||
|
||||
grade: any;
|
||||
courseId: number;
|
||||
userId: number;
|
||||
gradeId: number;
|
||||
errormessage: string;
|
||||
gradeLoaded = false;
|
||||
|
||||
constructor(private gradesProvider: CoreGradesProvider, private domUtils: CoreDomUtilsProvider,
|
||||
private gradesHelper: CoreGradesHelperProvider, navParams: NavParams, sitesProvider: CoreSitesProvider) {
|
||||
|
||||
this.courseId = navParams.get('courseId');
|
||||
this.userId = navParams.get('userId') || sitesProvider.getCurrentSiteUserId();
|
||||
this.gradeId = navParams.get('gradeId');
|
||||
}
|
||||
|
||||
/**
|
||||
* View loaded.
|
||||
*/
|
||||
ionViewDidLoad(): void {
|
||||
this.fetchData().finally(() => {
|
||||
this.gradeLoaded = true;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch all the data required for the view.
|
||||
*
|
||||
* @return {Promise<any>} Resolved when done.
|
||||
*/
|
||||
fetchData(): Promise<any> {
|
||||
return this.gradesHelper.getGradeItem(this.courseId, this.gradeId, this.userId).then((grade) => {
|
||||
this.grade = grade;
|
||||
}).catch((error) => {
|
||||
this.domUtils.showErrorModalDefault(error, 'Error loading grade item');
|
||||
this.errormessage = error || 'Grade not found';
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Refresh data.
|
||||
*
|
||||
* @param {any} refresher Refresher.
|
||||
*/
|
||||
refreshGrade(refresher: any): void {
|
||||
this.gradesProvider.invalidateCourseGradesData(this.courseId, this.userId).finally(() => {
|
||||
this.fetchData().finally(() => {
|
||||
refresher.complete();
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
|
@ -45,7 +45,7 @@ export class CoreGradesProvider {
|
|||
}
|
||||
|
||||
/**
|
||||
* Get cache key for grade table data WS calls.
|
||||
* Get cache key for grade items data WS calls.
|
||||
*
|
||||
* @param {number} courseId ID of the course to get the grades from.
|
||||
* @param {number} userId ID of the user to get the grades from.
|
||||
|
@ -77,6 +77,37 @@ export class CoreGradesProvider {
|
|||
return this.ROOT_CACHE_KEY + 'coursesgrades';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the grade items for a certain module. Keep in mind that may have more than one item to include outcomes and scales.
|
||||
* Fallback function only used if 'gradereport_user_get_grade_items' WS is not avalaible Moodle < 3.2.
|
||||
*
|
||||
* @param {number} courseId ID of the course to get the grades from.
|
||||
* @param {number} [userId] ID of the user to get the grades from. If not defined use site's current user.
|
||||
* @param {number} [groupId] ID of the group to get the grades from. Not used for old gradebook table.
|
||||
* @param {string} [siteId] Site ID. If not defined, current site.
|
||||
* @param {boolean} [ignoreCache=false] True if it should ignore cached data (it will always fail in offline or server down).
|
||||
* @return {Promise<any>} Promise to be resolved when the grades are retrieved.
|
||||
*/
|
||||
getGradeItems(courseId: number, userId?: number, groupId?: number, siteId?: string, ignoreCache: boolean = false):
|
||||
Promise<any> {
|
||||
siteId = siteId || this.sitesProvider.getCurrentSiteId();
|
||||
|
||||
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||
userId = userId || site.getUserId();
|
||||
|
||||
return this.isGradeItemsAvalaible(siteId).then((enabled) => {
|
||||
if (enabled) {
|
||||
return this.getCourseGradesItems(courseId, userId, groupId, siteId, ignoreCache).catch(() => {
|
||||
// FallBack while solving MDL-57255.
|
||||
return this.getCourseGradesTable(courseId, userId, siteId, ignoreCache);
|
||||
});
|
||||
} else {
|
||||
return this.getCourseGradesTable(courseId, userId, siteId, ignoreCache);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the grade items for a certain course.
|
||||
*
|
||||
|
@ -210,6 +241,21 @@ export class CoreGradesProvider {
|
|||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Invalidates courses grade items data WS calls.
|
||||
*
|
||||
* @param {number} courseId ID of the course to get the grades from.
|
||||
* @param {number} userId ID of the user to get the grades from.
|
||||
* @param {number} [groupId] ID of the group to get the grades from. Default: 0.
|
||||
* @param {string} [siteId] Site id (empty for current site).
|
||||
* @return {Promise<any>} Promise resolved when the data is invalidated.
|
||||
*/
|
||||
invalidateCourseGradesItemsData(courseId: number, userId: number, groupId: number, siteId?: string): Promise<any> {
|
||||
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||
return site.invalidateWsCacheForKey(this.getCourseGradesItemsCacheKey(courseId, userId, groupId));
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether or not the plugin is enabled for a certain site.
|
||||
*
|
||||
|
|
|
@ -20,6 +20,7 @@ import { CoreCoursesProvider } from '../../courses/providers/courses';
|
|||
import { CoreCourseProvider } from '../../course/providers/course';
|
||||
import { CoreGradesProvider } from './grades';
|
||||
import { CoreTextUtilsProvider } from '../../../providers/utils/text';
|
||||
import { CoreUrlUtilsProvider } from '../../../providers/utils/url';
|
||||
import { CoreDomUtilsProvider } from '../../../providers/utils/dom';
|
||||
|
||||
/**
|
||||
|
@ -32,10 +33,103 @@ export class CoreGradesHelperProvider {
|
|||
constructor(logger: CoreLoggerProvider, private coursesProvider: CoreCoursesProvider,
|
||||
private gradesProvider: CoreGradesProvider, private sitesProvider: CoreSitesProvider,
|
||||
private textUtils: CoreTextUtilsProvider, private courseProvider: CoreCourseProvider,
|
||||
private domUtils: CoreDomUtilsProvider, private translate: TranslateService) {
|
||||
private domUtils: CoreDomUtilsProvider, private translate: TranslateService,
|
||||
private urlUtils: CoreUrlUtilsProvider) {
|
||||
this.logger = logger.getInstance('CoreGradesHelperProvider');
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats a row from the grades table te be rendered in a page.
|
||||
*
|
||||
* @param {any} tableRow JSON object representing row of grades table data.
|
||||
* @return {any} Formatted row object.
|
||||
*/
|
||||
protected formatGradeRow(tableRow: any): any {
|
||||
const row = {};
|
||||
for (const name in tableRow) {
|
||||
if (typeof(tableRow[name].content) != 'undefined') {
|
||||
let content = tableRow[name].content;
|
||||
|
||||
if (name == 'itemname') {
|
||||
this.setRowIcon(row, content);
|
||||
row['link'] = this.getModuleLink(content);
|
||||
row['rowclass'] += tableRow[name].class.indexOf('hidden') >= 0 ? ' hidden' : '';
|
||||
row['rowclass'] += tableRow[name].class.indexOf('dimmed_text') >= 0 ? ' dimmed_text' : '';
|
||||
|
||||
content = content.replace(/<\/span>/gi, '\n');
|
||||
content = this.textUtils.cleanTags(content);
|
||||
} else {
|
||||
content = this.textUtils.replaceNewLines(content, '<br>');
|
||||
}
|
||||
|
||||
if (content == ' ') {
|
||||
content = '';
|
||||
}
|
||||
|
||||
row[name] = content.trim();
|
||||
}
|
||||
}
|
||||
|
||||
return row;
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats a row from the grades table to be rendered in one table.
|
||||
*
|
||||
* @param {any} tableRow JSON object representing row of grades table data.
|
||||
* @return {any} Formatted row object.
|
||||
*/
|
||||
protected formatGradeRowForTable(tableRow: any): any {
|
||||
const row = {};
|
||||
for (let name in tableRow) {
|
||||
if (typeof(tableRow[name].content) != 'undefined') {
|
||||
let content = tableRow[name].content;
|
||||
|
||||
if (name == 'itemname') {
|
||||
this.setRowIcon(row, content);
|
||||
row['rowclass'] = tableRow[name].class.indexOf('leveleven') < 0 ? 'odd' : 'even';
|
||||
row['rowclass'] += tableRow[name].class.indexOf('hidden') >= 0 ? ' hidden' : '';
|
||||
row['rowclass'] += tableRow[name].class.indexOf('dimmed_text') >= 0 ? ' dimmed_text' : '';
|
||||
|
||||
content = content.replace(/<\/span>/gi, '\n');
|
||||
content = this.textUtils.cleanTags(content);
|
||||
|
||||
row['id'] = parseInt(tableRow[name].id.split('_')[1], 10);
|
||||
row['colspan'] = tableRow[name].colspan;
|
||||
row['rowspan'] = (tableRow['leader'] && tableRow['leader'].rowspan) || 1;
|
||||
name = 'gradeitem';
|
||||
} else {
|
||||
content = this.textUtils.replaceNewLines(content, '<br>');
|
||||
}
|
||||
|
||||
if (content == ' ') {
|
||||
content = '';
|
||||
}
|
||||
|
||||
row[name] = content.trim();
|
||||
}
|
||||
}
|
||||
|
||||
return row;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes suffix formatted to compatibilize data from table and items.
|
||||
*
|
||||
* @param {any} item Grade item to format.
|
||||
* @return {any} Grade item formatted.
|
||||
*/
|
||||
protected formatGradeItem(item: any): any {
|
||||
for (const name in item) {
|
||||
let index = name.indexOf('formatted');
|
||||
if (index > 0) {
|
||||
item[name.substr(0, index)] = item[name];
|
||||
}
|
||||
}
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats the response of gradereport_user_get_grades_table to be rendered.
|
||||
*
|
||||
|
@ -62,7 +156,7 @@ export class CoreGradesHelperProvider {
|
|||
contributiontocoursetotal: false
|
||||
};
|
||||
formatted.rows = table.tabledata.map((row: any) => {
|
||||
return this.getGradeRow(row);
|
||||
return this.formatGradeRowForTable(row);
|
||||
}).filter((row: any) => {
|
||||
return typeof row.gradeitem !== 'undefined';
|
||||
});
|
||||
|
@ -97,47 +191,6 @@ export class CoreGradesHelperProvider {
|
|||
return formatted;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a row from the grades table.
|
||||
*
|
||||
* @param {any} tableRow JSON object representing row of grades table data.
|
||||
* @return {any} Formatted row object.
|
||||
*/
|
||||
getGradeRow(tableRow: any): any {
|
||||
const row = {};
|
||||
for (let name in tableRow) {
|
||||
if (typeof(tableRow[name].content) != 'undefined') {
|
||||
let content = tableRow[name].content;
|
||||
|
||||
if (name == 'itemname') {
|
||||
this.setRowIcon(row, content);
|
||||
row['link'] = this.getModuleLink(content);
|
||||
row['rowclass'] = tableRow[name].class.indexOf('leveleven') < 0 ? 'odd' : 'even';
|
||||
row['rowclass'] += tableRow[name].class.indexOf('hidden') >= 0 ? ' hidden' : '';
|
||||
row['rowclass'] += tableRow[name].class.indexOf('dimmed_text') >= 0 ? ' dimmed_text' : '';
|
||||
|
||||
content = content.replace(/<\/span>/gi, '\n');
|
||||
content = this.textUtils.cleanTags(content);
|
||||
|
||||
row['id'] = parseInt(tableRow[name].id.split('_')[1], 10);
|
||||
row['colspan'] = tableRow[name].colspan;
|
||||
row['rowspan'] = (tableRow['leader'] && tableRow['leader'].rowspan) || 1;
|
||||
name = 'gradeitem';
|
||||
} else {
|
||||
content = this.textUtils.replaceNewLines(content, '<br>');
|
||||
}
|
||||
|
||||
if (content == ' ') {
|
||||
content = '';
|
||||
}
|
||||
|
||||
row[name] = content.trim();
|
||||
}
|
||||
}
|
||||
|
||||
return row;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get course data for grades since they only have courseid.
|
||||
*
|
||||
|
@ -162,6 +215,156 @@ export class CoreGradesHelperProvider {
|
|||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an specific grade item.
|
||||
*
|
||||
* @param {number} courseId ID of the course to get the grades from.
|
||||
* @param {number} gradeId Grade ID.
|
||||
* @param {number} [userId] ID of the user to get the grades from. If not defined use site's current user.
|
||||
* @param {string} [siteId] Site ID. If not defined, current site.
|
||||
* @param {boolean} [ignoreCache=false] True if it should ignore cached data (it will always fail in offline or server down).
|
||||
* @return {Promise<any>} Promise to be resolved when the grades are retrieved.
|
||||
*/
|
||||
getGradeItem(courseId: number, gradeId: number, userId?: number, siteId?: string, ignoreCache: boolean = false): Promise<any> {
|
||||
|
||||
return this.gradesProvider.getCourseGradesTable(courseId, userId, siteId, ignoreCache).then((grades) => {
|
||||
if (grades) {
|
||||
return this.getGradesTableRow(grades, gradeId);
|
||||
}
|
||||
|
||||
return Promise.reject(null);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the grade items for a certain module. Keep in mind that may have more than one item to include outcomes and scales.
|
||||
*
|
||||
* @param {number} courseId ID of the course to get the grades from.
|
||||
* @param {number} moduleId Module ID.
|
||||
* @param {number} [userId] ID of the user to get the grades from. If not defined use site's current user.
|
||||
* @param {number} [groupId] ID of the group to get the grades from. Not used for old gradebook table.
|
||||
* @param {string} [siteId] Site ID. If not defined, current site.
|
||||
* @param {boolean} [ignoreCache=false] True if it should ignore cached data (it will always fail in offline or server down).
|
||||
* @return {Promise<any>} Promise to be resolved when the grades are retrieved.
|
||||
*/
|
||||
getGradeModuleItems(courseId: number, moduleId: number, userId?: number, groupId?: number, siteId?: string,
|
||||
ignoreCache: boolean = false): Promise<any> {
|
||||
|
||||
return this.gradesProvider.getGradeItems(courseId, userId, groupId, siteId, ignoreCache).then((grades) => {
|
||||
if (grades) {
|
||||
if (typeof grades.tabledata != 'undefined') {
|
||||
// Table format.
|
||||
return this.getModuleGradesTableRows(grades, moduleId);
|
||||
} else {
|
||||
return grades.filter((item) => {
|
||||
return item.cmid == moduleId;
|
||||
}).map((item) => {
|
||||
return this.formatGradeItem(item);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return Promise.reject(null);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the link to the module for the selected grade.
|
||||
*
|
||||
* @param {string} text HTML where the link is present.
|
||||
* @return {string | false} URL linking to the module.
|
||||
*/
|
||||
protected getModuleLink(text: string): string | false {
|
||||
const el = this.domUtils.toDom(text)[0],
|
||||
link = el.attributes['href'] ? el.attributes['href'].value : false;
|
||||
|
||||
if (!link || link.indexOf('/mod/') < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return link;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a row from the grades table.
|
||||
*
|
||||
* @param {any} table JSON object representing a table with data.
|
||||
* @param {number} gradeId Grade Object identifier.
|
||||
* @return {any} Formatted HTML table.
|
||||
*/
|
||||
getGradesTableRow(table: any, gradeId: number): any {
|
||||
if (table.tabledata) {
|
||||
const selectedRow = table.tabledata.find((row) => {
|
||||
return row.itemname && row.itemname.id && row.itemname.id.substr(0, 3) == 'row' &&
|
||||
parseInt(row.itemname.id.split('_')[1], 10) == gradeId;
|
||||
});
|
||||
|
||||
if (selectedRow) {
|
||||
return this.formatGradeRow(selectedRow);
|
||||
}
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the rows related to a module from the grades table.
|
||||
*
|
||||
* @param {any} table JSON object representing a table with data.
|
||||
* @param {number} moduleId Grade Object identifier.
|
||||
* @return {any} Formatted HTML table.
|
||||
*/
|
||||
getModuleGradesTableRows(table: any, moduleId: number): any {
|
||||
|
||||
if (table.tabledata) {
|
||||
// Find href containing "/mod/xxx/xxx.php".
|
||||
const regex = /href="([^"]*\/mod\/[^"|^\/]*\/[^"|^\.]*\.php[^"]*)/;
|
||||
|
||||
return table.tabledata.filter((row) => {
|
||||
if (row.itemname && row.itemname.content) {
|
||||
const matches = row.itemname.content.match(regex);
|
||||
|
||||
if (matches && matches.length) {
|
||||
const hrefParams = this.urlUtils.extractUrlParams(matches[1]);
|
||||
|
||||
return hrefParams && hrefParams.id == moduleId;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}).map((row) => {
|
||||
return this.formatGradeRow(row);
|
||||
});
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Invalidate the grade items for a certain module.
|
||||
*
|
||||
* @param {number} courseId ID of the course to invalidate the grades.
|
||||
* @param {number} [userId] ID of the user to invalidate. If not defined use site's current user.
|
||||
* @param {number} [groupId] ID of the group to invalidate. Not used for old gradebook table.
|
||||
* @param {string} [siteId] Site ID. If not defined, current site.
|
||||
* @return {Promise} Promise to be resolved when the grades are invalidated.
|
||||
*/
|
||||
invalidateGradeModuleItems(courseId: number, userId?: number, groupId?: number, siteId?: string): Promise<any> {
|
||||
siteId = siteId || this.sitesProvider.getCurrentSiteId();
|
||||
|
||||
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||
userId = userId || site.getUserId();
|
||||
|
||||
return this.gradesProvider.isGradeItemsAvalaible(siteId).then((enabled) => {
|
||||
if (enabled) {
|
||||
return this.gradesProvider.invalidateCourseGradesItemsData(courseId, userId, groupId, siteId);
|
||||
} else {
|
||||
return this.gradesProvider.invalidateCourseGradesData(courseId, userId, siteId);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the image and sets it to the row.
|
||||
*
|
||||
|
@ -201,21 +404,4 @@ export class CoreGradesHelperProvider {
|
|||
|
||||
return row;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the link to the module for the selected grade.
|
||||
*
|
||||
* @param {string} text HTML where the link is present.
|
||||
* @return {string | false} URL linking to the module.
|
||||
*/
|
||||
protected getModuleLink(text: string): string | false {
|
||||
const el = this.domUtils.toDom(text)[0],
|
||||
link = el.attributes['href'] ? el.attributes['href'].value : false;
|
||||
|
||||
if (!link || link.indexOf('/mod/') < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return link;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -191,6 +191,15 @@ export class CoreAppProvider {
|
|||
return this.platform.is('cordova');
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the current window is wider than a mobile.
|
||||
*
|
||||
* @return {boolean} Whether the app the current window is wider than a mobile.
|
||||
*/
|
||||
isWide(): boolean {
|
||||
return this.platform.width() > 768;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether we are online.
|
||||
*
|
||||
|
|
Loading…
Reference in New Issue