diff --git a/src/app/app.scss b/src/app/app.scss
index 30520d667..e21adbc2e 100644
--- a/src/app/app.scss
+++ b/src/app/app.scss
@@ -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;
}
}
diff --git a/src/core/grades/components/course/course.html b/src/core/grades/components/course/course.html
index 033744660..ca54f693d 100644
--- a/src/core/grades/components/course/course.html
+++ b/src/core/grades/components/course/course.html
@@ -19,7 +19,7 @@
|
-
+ |
diff --git a/src/core/grades/components/course/course.scss b/src/core/grades/components/course/course.scss
index b02ce767b..a04232fb8 100644
--- a/src/core/grades/components/course/course.scss
+++ b/src/core/grades/components/course/course.scss
@@ -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 {
}
}
}
-}
\ No newline at end of file
+}
+
+.split-pane-side, .split-pane-main {
+ core-grades-course .core-grades-table .hidden-phone {
+ display: none;
+ opacity: 0;
+ }
+}
diff --git a/src/core/grades/components/course/course.ts b/src/core/grades/components/course/course.ts
index 0985d25e6..5913ac22c 100644
--- a/src/core/grades/components/course/course.ts
+++ b/src/core/grades/components/course/course.ts
@@ -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});
}
}
}
diff --git a/src/core/grades/pages/courses/courses.ts b/src/core/grades/pages/courses/courses.ts
index 4dd345cff..fd54a58d8 100644
--- a/src/core/grades/pages/courses/courses.ts
+++ b/src/core/grades/pages/courses/courses.ts
@@ -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 {
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) => {
diff --git a/src/core/grades/pages/coursesplit/coursesplit.html b/src/core/grades/pages/coursesplit/coursesplit.html
new file mode 100644
index 000000000..de279c1f7
--- /dev/null
+++ b/src/core/grades/pages/coursesplit/coursesplit.html
@@ -0,0 +1,10 @@
+
+
+ {{ 'core.grades.grades' | translate }}
+
+
+
+
+
+
+
diff --git a/src/core/grades/pages/coursesplit/coursesplit.module.ts b/src/core/grades/pages/coursesplit/coursesplit.module.ts
new file mode 100644
index 000000000..57b081e99
--- /dev/null
+++ b/src/core/grades/pages/coursesplit/coursesplit.module.ts
@@ -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 {}
diff --git a/src/core/grades/pages/coursesplit/coursesplit.ts b/src/core/grades/pages/coursesplit/coursesplit.ts
new file mode 100644
index 000000000..f759b72ca
--- /dev/null
+++ b/src/core/grades/pages/coursesplit/coursesplit.ts
@@ -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');
+ }
+}
diff --git a/src/core/grades/pages/grade/grade.html b/src/core/grades/pages/grade/grade.html
new file mode 100644
index 000000000..5f9268c9c
--- /dev/null
+++ b/src/core/grades/pages/grade/grade.html
@@ -0,0 +1,72 @@
+
+
+ {{ 'core.grades.grade' | translate }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ 'core.grades.weight' | translate}}
+
+
+
+
+ {{ 'core.grades.grade' | translate}}
+
+
+
+
+ {{ 'core.grades.range' | translate}}
+
+
+
+
+ {{ 'core.grades.percentage' | translate}}
+
+
+
+
+ {{ 'core.grades.lettergrade' | translate}}
+
+
+
+
+ {{ 'core.grades.rank' | translate}}
+
+
+
+
+ {{ 'core.grades.average' | translate}}
+
+
+
+
+ {{ 'core.grades.feedback' | translate}}
+
+
+
+
+ {{ 'core.grades.contributiontocoursetotal' | translate}}
+
+
+
+
+
diff --git a/src/core/grades/pages/grade/grade.module.ts b/src/core/grades/pages/grade/grade.module.ts
new file mode 100644
index 000000000..5b591fddd
--- /dev/null
+++ b/src/core/grades/pages/grade/grade.module.ts
@@ -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 {}
diff --git a/src/core/grades/pages/grade/grade.ts b/src/core/grades/pages/grade/grade.ts
new file mode 100644
index 000000000..8ef99c85d
--- /dev/null
+++ b/src/core/grades/pages/grade/grade.ts
@@ -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} Resolved when done.
+ */
+ fetchData(): Promise {
+ 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();
+ });
+ });
+ }
+}
diff --git a/src/core/grades/providers/grades.ts b/src/core/grades/providers/grades.ts
index 6b9f833aa..f4efc010b 100644
--- a/src/core/grades/providers/grades.ts
+++ b/src/core/grades/providers/grades.ts
@@ -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} Promise to be resolved when the grades are retrieved.
+ */
+ getGradeItems(courseId: number, userId?: number, groupId?: number, siteId?: string, ignoreCache: boolean = false):
+ Promise {
+ 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} Promise resolved when the data is invalidated.
+ */
+ invalidateCourseGradesItemsData(courseId: number, userId: number, groupId: number, siteId?: string): Promise {
+ 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.
*
diff --git a/src/core/grades/providers/helper.ts b/src/core/grades/providers/helper.ts
index a5e62a4d8..f0cb2d0f0 100644
--- a/src/core/grades/providers/helper.ts
+++ b/src/core/grades/providers/helper.ts
@@ -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, ' ');
+ }
+
+ 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, ' ');
+ }
+
+ 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, ' ');
- }
-
- 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} Promise to be resolved when the grades are retrieved.
+ */
+ getGradeItem(courseId: number, gradeId: number, userId?: number, siteId?: string, ignoreCache: boolean = false): Promise {
+
+ 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} Promise to be resolved when the grades are retrieved.
+ */
+ getGradeModuleItems(courseId: number, moduleId: number, userId?: number, groupId?: number, siteId?: string,
+ ignoreCache: boolean = false): Promise {
+
+ 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 {
+ 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;
- }
}
diff --git a/src/providers/app.ts b/src/providers/app.ts
index 86df6ce5d..054ef2467 100644
--- a/src/providers/app.ts
+++ b/src/providers/app.ts
@@ -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.
*
|