Merge pull request from albertgasset/MOBILE-2323

Mobile 2323
This commit is contained in:
Juan Leyva 2018-03-14 16:23:25 +01:00 committed by GitHub
commit bf16815e68
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
53 changed files with 2300 additions and 42 deletions

@ -26,7 +26,8 @@
"lint": "ionic-app-scripts lint", "lint": "ionic-app-scripts lint",
"ionic:build": "ionic-app-scripts build", "ionic:build": "ionic-app-scripts build",
"ionic:serve": "gulp watch | ionic-app-scripts serve", "ionic:serve": "gulp watch | ionic-app-scripts serve",
"ionic:build:before": "gulp" "ionic:build:before": "gulp",
"ionic:watch:before": "gulp"
}, },
"dependencies": { "dependencies": {
"@angular/animations": "^5.2.5", "@angular/animations": "^5.2.5",

@ -0,0 +1,67 @@
// (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 { AddonCompetencyProvider } from './providers/competency';
import { AddonCompetencyHelperProvider } from './providers/helper';
import { AddonCompetencyCourseOptionHandler } from './providers/course-option-handler';
import { AddonCompetencyMainMenuHandler } from './providers/mainmenu-handler';
import { AddonCompetencyUserHandler } from './providers/user-handler';
import { AddonCompetencyComponentsModule } from './components/components.module';
import { CoreCourseOptionsDelegate } from '@core/course/providers/options-delegate';
import { CoreMainMenuDelegate } from '@core/mainmenu/providers/delegate';
import { CoreUserDelegate } from '@core/user/providers/user-delegate';
import { CoreUserProvider } from '@core/user/providers/user';
import { CoreEventsProvider } from '@providers/events';
import { CoreSitesProvider } from '@providers/sites';
import { CoreCoursesProvider } from '@core/courses/providers/courses';
@NgModule({
declarations: [
],
imports: [
AddonCompetencyComponentsModule
],
providers: [
AddonCompetencyProvider,
AddonCompetencyHelperProvider,
AddonCompetencyCourseOptionHandler,
AddonCompetencyMainMenuHandler,
AddonCompetencyUserHandler
]
})
export class AddonCompetencyModule {
constructor(mainMenuDelegate: CoreMainMenuDelegate, mainMenuHandler: AddonCompetencyMainMenuHandler,
courseOptionsDelegate: CoreCourseOptionsDelegate, courseOptionHandler: AddonCompetencyCourseOptionHandler,
userDelegate: CoreUserDelegate, userHandler: AddonCompetencyUserHandler,
eventsProvider: CoreEventsProvider, sitesProvider: CoreSitesProvider) {
mainMenuDelegate.registerHandler(mainMenuHandler);
courseOptionsDelegate.registerHandler(courseOptionHandler);
userDelegate.registerHandler(userHandler);
eventsProvider.on(CoreEventsProvider.LOGOUT, () => {
courseOptionHandler.clearCoursesNavCache();
userHandler.clearUsersNavCache();
}, sitesProvider.getCurrentSiteId());
eventsProvider.on(CoreCoursesProvider.EVENT_MY_COURSES_REFRESHED, () => {
courseOptionHandler.clearCoursesNavCache();
}, sitesProvider.getCurrentSiteId());
eventsProvider.on(CoreUserProvider.PROFILE_REFRESHED, () => {
userHandler.clearUsersNavCache();
}, sitesProvider.getCurrentSiteId());
}
}

@ -0,0 +1,45 @@
// (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 { CommonModule } from '@angular/common';
import { IonicModule } from 'ionic-angular';
import { TranslateModule } from '@ngx-translate/core';
import { CoreComponentsModule } from '@components/components.module';
import { CoreDirectivesModule } from '@directives/directives.module';
import { CorePipesModule } from '@pipes/pipes.module';
import { AddonCompetencyCourseComponent } from './course/course';
@NgModule({
declarations: [
AddonCompetencyCourseComponent
],
imports: [
CommonModule,
IonicModule,
TranslateModule.forChild(),
CoreComponentsModule,
CoreDirectivesModule,
CorePipesModule
],
providers: [
],
exports: [
AddonCompetencyCourseComponent
],
entryComponents: [
AddonCompetencyCourseComponent
]
})
export class AddonCompetencyComponentsModule {}

@ -0,0 +1,73 @@
<ion-content>
<ion-refresher [enabled]="competenciesLoaded" (ionRefresh)="refreshCourseCompetencies($event)">
<ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}"></ion-refresher-content>
</ion-refresher>
<core-loading [hideUntil]="competenciesLoaded">
<ion-card *ngIf="!user && competencies && competencies.statistics.competencycount > 0">
<ion-item text-wrap *ngIf="competencies.settings.pushratingstouserplans">
{{ 'addon.competency.coursecompetencyratingsarepushedtouserplans' | translate }}
</ion-item>
<ion-item text-wrap *ngIf="!competencies.settings.pushratingstouserplans">
{{ 'addon.competency.coursecompetencyratingsarenotpushedtouserplans' | translate }}
</ion-item>
<ion-item text-wrap>
<strong>{{ 'addon.competency.progress' | translate }}</strong>:
{{ 'addon.competency.xcompetenciesproficientoutofyincourse' | translate:{$a: {x: competencies.statistics.proficientcompetencycount, y: competencies.statistics.competencycount} } }} ({{ competencies.statistics.proficientcompetencypercentageformatted }}%)
<core-progress-bar [progress]="competencies.statistics.proficientcompetencypercentage"></core-progress-bar>
</ion-item>
<ion-item text-wrap *ngIf="competencies.statistics.leastproficientcount > 0">
<strong>{{ 'addon.competency.competenciesmostoftennotproficientincourse' | translate }}</strong>:
<p *ngFor="let comp of competencies.statistics.leastproficient">
<a (click)="openCompetencySummary(comp.id)">
{{ comp.shortname }} - {{ comp.idnumber }}
</a>
</p>
</ion-item>
</ion-card>
<h3 margin-horizontal *ngIf="competencies && competencies.statistics.competencycount > 0">{{ 'addon.competency.competencies' | translate }}</h3>
<ion-card *ngIf="user">
<ion-item text-wrap>
<ion-avatar *ngIf="user.profileimageurl && user.profileimageurl !== true" item-start>
<img [src]="user.profileimageurl" [alt]="'core.pictureof' | translate:{$a: user.fullname}" core-external-content>
</ion-avatar>
<span *ngIf="user.profileimageurl === true" item-start>
<ion-icon name="person"></ion-icon>
</span>
<h2><core-format-text [text]="user.fullname"></core-format-text></h2>
</ion-item>
</ion-card>
<core-empty-box *ngIf="competencies && competencies.statistics.competencycount == 0" icon="ribbon" message="{{ 'addon.competency.nocompetencies' | translate }}"></core-empty-box>
<div *ngIf="competencies">
<ion-card *ngFor="let competency of competencies.competencies">
<a ion-item text-wrap (click)="openCompetency(competency.competency.id)" [title]="competency.competency.shortname">
{{competency.competency.shortname}} <small>{{competency.competency.idnumber}}</small>
<ion-badge item-end *ngIf="competency.usercompetencycourse && competency.usercompetencycourse.gradename" [color]="competency.usercompetencycourse.proficiency ? 'success' : 'danger'">{{ competency.usercompetencycourse.gradename }}</ion-badge>
</a>
<ion-item text-wrap>
<div *ngIf="competency.competency.description">
<core-format-text [text]=" competency.competency.description "></core-format-text>
</div>
<div>
<strong>{{ 'addon.competency.path' | translate }}</strong>:
{{ competency.comppath.framework.name }}
<span *ngFor="let ancestor of competency.comppath.ancestors">
&nbsp;/&nbsp;<a (click)="openCompetencySummary(ancestor.id)">{{ ancestor.name }}</a>
</span>
</div>
<div>
<strong>{{ 'addon.competency.activities' | translate }}</strong>:
<span *ngIf="competency.coursemodules.length == 0">
{{ 'addon.competency.noactivities' | translate }}
</span>
<a ion-item text-wrap *ngFor="let activity of competency.coursemodules" [href]="activity.url" [title]="activity.name">
<img item-start [src]="activity.iconurl" core-external-content alt="" role="presentation" *ngIf="activity.iconurl" class="core-module-icon">
<core-format-text [text]="activity.name"></core-format-text>
</a>
</div>
</ion-item>
</ion-card>
</div>
</core-loading>
</ion-content>

@ -0,0 +1,104 @@
// (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, Input } from '@angular/core';
import { Content, NavController } from 'ionic-angular';
import { CoreAppProvider } from '@providers/app';
import { CoreDomUtilsProvider } from '@providers/utils/dom';
import { AddonCompetencyProvider } from '../../providers/competency';
import { AddonCompetencyHelperProvider } from '../../providers/helper';
/**
* Component that displays the competencies of a course.
*/
@Component({
selector: 'addon-competency-course',
templateUrl: 'course.html',
})
export class AddonCompetencyCourseComponent {
@ViewChild(Content) content: Content;
@Input() courseId: number;
@Input() userId: number;
competenciesLoaded = false;
competencies: any;
user: any;
constructor(private navCtrl: NavController, private appProvider: CoreAppProvider, private domUtils: CoreDomUtilsProvider,
private competencyProvider: AddonCompetencyProvider, private helperProvider: AddonCompetencyHelperProvider) {
}
/**
* View loaded.
*/
ngOnInit(): void {
this.fetchCourseCompetencies().finally(() => {
this.competenciesLoaded = true;
});
}
/**
* Fetches the competencies and updates the view.
*
* @return {Promise<void>} Promise resolved when done.
*/
protected fetchCourseCompetencies(): Promise<void> {
return this.competencyProvider.getCourseCompetencies(this.courseId, this.userId).then((competencies) => {
this.competencies = competencies;
// Get the user profile image.
this.helperProvider.getProfile(this.userId).then((user) => {
this.user = user;
});
}).catch((message) => {
this.domUtils.showErrorModalDefault(message, 'Error getting course competencies data.');
});
}
/**
* Opens a competency.
*
* @param {number} competencyId
*/
openCompetency(competencyId: number): void {
if (this.appProvider.isWide()) {
this.navCtrl.push('AddonCompetencyCompetenciesPage', {competencyId, courseId: this.courseId, userId: this.userId});
} else {
this.navCtrl.push('AddonCompetencyCompetencyPage', {competencyId, courseId: this.courseId, userId: this.userId});
}
}
/**
* Opens the summary of a competency.
*
* @param {number} competencyId
*/
openCompetencySummary(competencyId: number): void {
this.navCtrl.push('AddonCompetencyCompetencySummaryPage', {competencyId});
}
/**
* Refreshes the competencies.
*
* @param {any} refresher Refresher.
*/
refreshCourseCompetencies(refresher: any): void {
this.competencyProvider.invalidateCourseCompetencies(this.courseId, this.userId).finally(() => {
this.fetchCourseCompetencies().finally(() => {
refresher.complete();
});
});
}
}

@ -0,0 +1,47 @@
{
"activities": "Activities",
"competencies": "Competencies",
"competenciesmostoftennotproficientincourse": "Competencies most often not proficient in this course",
"coursecompetencies": "Course competencies",
"coursecompetencyratingsarenotpushedtouserplans": "Competency ratings in this course do not affect learning plans.",
"coursecompetencyratingsarepushedtouserplans": "Competency ratings in this course are updated immediately in learning plans.",
"crossreferencedcompetencies": "Cross-referenced competencies",
"duedate": "Due date",
"errornocompetenciesfound": "No competencies found",
"evidence": "Evidence",
"evidence_competencyrule": "The rule of the competency was met.",
"evidence_coursecompleted": "The course '{{$a}}' was completed.",
"evidence_coursemodulecompleted": "The activity '{{$a}}' was completed.",
"evidence_courserestored": "The rating was restored along with the course '{{$a}}'.",
"evidence_evidenceofpriorlearninglinked": "The evidence of prior learning '{{$a}}' was linked.",
"evidence_evidenceofpriorlearningunlinked": "The evidence of prior learning '{{$a}}' was unlinked.",
"evidence_manualoverride": "The competency rating was manually set.",
"evidence_manualoverrideincourse": "The competency rating was manually set in the course '{{$a}}'.",
"evidence_manualoverrideinplan": "The competency rating was manually set in the learning plan '{{$a}}'.",
"learningplancompetencies": "Learning plan competencies",
"learningplans": "Learning plans",
"myplans": "My learning plans",
"noactivities": "No activities",
"nocompetencies": "No competencies",
"nocrossreferencedcompetencies": "No other competencies have been cross-referenced to this competency.",
"noevidence": "No evidence",
"noplanswerecreated": "No learning plans were created.",
"path": "Path:",
"planstatusactive": "Active",
"planstatuscomplete": "Complete",
"planstatusdraft": "Draft",
"planstatusinreview": "In review",
"planstatuswaitingforreview": "Waiting for review",
"proficient": "Proficient",
"progress": "Progress",
"rating": "Rating",
"reviewstatus": "Review status",
"status": "Status",
"template": "Learning plan template",
"usercompetencystatus_idle": "Idle",
"usercompetencystatus_inreview": "In review",
"usercompetencystatus_waitingforreview": "Waiting for review",
"userplans": "Learning plans",
"xcompetenciesproficientoutofy": "{{$a.x}} out of {{$a.y}} competencies are proficient",
"xcompetenciesproficientoutofyincourse": "You are proficient in {{$a.x}} out of {{$a.y}} competencies in this course."
}

@ -0,0 +1,21 @@
<ion-header>
<ion-navbar>
<ion-title>{{ title }}</ion-title>
</ion-navbar>
</ion-header>
<core-split-view>
<ion-content>
<ion-refresher [enabled]="competenciesLoaded" (ionRefresh)="refreshCompetencies($event)">
<ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}"></ion-refresher-content>
</ion-refresher>
<core-loading [hideUntil]="competenciesLoaded">
<ion-list>
<a ion-item text-wrap *ngFor="let competency of competencies" [title]="competency.competency.shortname" (click)="openCompetency(competency.competency.id)" [class.core-split-item-selected]="competency.competency.id == competencyId">
{{ competency.competency.shortname }} <small>{{competency.competency.idnumber}}</small>
<ion-badge item-end *ngIf="competency.usercompetency" [color]="competency.usercompetency.proficiency ? 'success' : 'danger'">{{ competency.usercompetency.gradename }}</ion-badge>
<ion-badge item-end *ngIf="competency.usercompetencycourse" [color]="competency.usercompetencycourse.proficiency ? 'success' : 'danger'">{{ competency.usercompetencycourse.gradename }}</ion-badge>
</a>
</ion-list>
</core-loading>
</ion-content>
</core-split-view>

@ -0,0 +1,31 @@
// (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 { CoreComponentsModule } from '@components/components.module';
import { AddonCompetencyCompetenciesPage } from './competencies';
@NgModule({
declarations: [
AddonCompetencyCompetenciesPage,
],
imports: [
CoreComponentsModule,
IonicPageModule.forChild(AddonCompetencyCompetenciesPage),
TranslateModule.forChild()
],
})
export class AddonCompetencyCompetenciesPageModule {}

@ -0,0 +1,137 @@
// (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, NavParams } from 'ionic-angular';
import { TranslateService } from '@ngx-translate/core';
import { CoreDomUtilsProvider } from '@providers/utils/dom';
import { CoreSplitViewComponent } from '@components/split-view/split-view';
import { AddonCompetencyProvider } from '../../providers/competency';
/**
* Page that displays the list of competencies of a learning plan.
*/
@IonicPage({ segment: 'addon-competency-competencies' })
@Component({
selector: 'page-addon-competency-competencies',
templateUrl: 'competencies.html',
})
export class AddonCompetencyCompetenciesPage {
@ViewChild(CoreSplitViewComponent) splitviewCtrl: CoreSplitViewComponent;
protected planId: number;
protected courseId: number;
protected competencyId: number;
protected userId: number;
competenciesLoaded = false;
competencies = [];
title: string;
constructor(navParams: NavParams, private translate: TranslateService, private domUtils: CoreDomUtilsProvider,
private competencyProvider: AddonCompetencyProvider) {
this.planId = navParams.get('planId');
this.courseId = navParams.get('courseId');
this.competencyId = navParams.get('competencyId');
this.userId = navParams.get('userId');
}
/**
* View loaded.
*/
ionViewDidLoad(): void {
if (this.competencyId) {
// There is a competency to load.
this.openCompetency(this.competencyId);
}
this.fetchCompetencies().then(() => {
if (!this.competencyId && this.splitviewCtrl.isOn() && this.competencies.length > 0) {
// Take first and load it.
this.openCompetency(this.competencies[0].id);
}
}).finally(() => {
this.competenciesLoaded = true;
});
}
/**
* Fetches the competencies and updates the view.
*
* @return {Promise<void>} Promise resolved when done.
*/
protected fetchCompetencies(): Promise<void> {
let promise;
if (this.planId) {
promise = this.competencyProvider.getLearningPlan(this.planId);
} else if (this.courseId) {
promise = this.competencyProvider.getCourseCompetencies(this.courseId, this.userId);
} else {
promise = Promise.reject(null);
}
return promise.then((response) => {
if (response.competencycount <= 0) {
return Promise.reject(this.translate.instant('addon.competency.errornocompetenciesfound'));
}
if (this.planId) {
this.title = response.plan.name;
this.userId = response.plan.userid;
} else {
this.title = this.translate.instant('addon.competency.coursecompetencies');
}
this.competencies = response.competencies;
}).catch((message) => {
this.domUtils.showErrorModalDefault(message, 'Error getting competencies data.');
});
}
/**
* Opens a competency.
*
* @param {number} competencyId
*/
openCompetency(competencyId: number): void {
this.competencyId = competencyId;
let params;
if (this.planId) {
params = {competencyId, planId: this.planId};
} else {
params = {competencyId, courseId: this.courseId, userId: this.userId};
}
this.splitviewCtrl.push('AddonCompetencyCompetencyPage', params);
}
/**
* Refreshes the competencies.
*
* @param {any} refresher Refresher.
*/
refreshCompetencies(refresher: any): void {
let promise;
if (this.planId) {
promise = this.competencyProvider.invalidateLearningPlan(this.planId);
} else {
promise = this.competencyProvider.invalidateCourseCompetencies(this.courseId, this.userId);
}
return promise.finally(() => {
this.fetchCompetencies().finally(() => {
refresher.complete();
});
});
}
}

@ -0,0 +1,95 @@
<ion-header>
<ion-navbar>
<ion-title *ngIf="competency">{{ competency.competency.competency.shortname }} <small>{{ competency.competency.competency.idnumber }}</small></ion-title>
</ion-navbar>
</ion-header>
<ion-content>
<ion-refresher [enabled]="competencyLoaded" (ionRefresh)="refreshCompetency($event)">
<ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}"></ion-refresher-content>
</ion-refresher>
<core-loading [hideUntil]="competencyLoaded">
<ion-card *ngIf="user">
<ion-item text-wrap>
<ion-avatar *ngIf="user.profileimageurl && user.profileimageurl !== true" item-start>
<img [src]="user.profileimageurl" [alt]="'core.pictureof' | translate:{$a: user.fullname}" core-external-content>
</ion-avatar>
<span *ngIf="user.profileimageurl === true" item-start>
<ion-icon name="person"></ion-icon>
</span>
<h2><core-format-text [text]="user.fullname"></core-format-text></h2>
</ion-item>
</ion-card>
<ion-card *ngIf="competency">
<ion-item text-wrap *ngIf="competency.competency.competency.description">
<core-format-text [text]="competency.competency.competency.description"></core-format-text>
</ion-item>
<ion-item text-wrap>
<strong>{{ 'addon.competency.path' | translate }}</strong>:
{{ competency.competency.comppath.framework.name }}
<span *ngFor="let ancestor of competency.competency.comppath.ancestors">
&nbsp;/&nbsp;<a (click)="openCompetencySummary(ancestor.id)">{{ ancestor.name }}</a>
</span>
</ion-item>
<ion-item text-wrap>
<strong>{{ 'addon.competency.crossreferencedcompetencies' | translate }}</strong>:
<div *ngIf="!competency.competency.hasrelatedcompetencies">{{ 'addon.competency.nocrossreferencedcompetencies' | translate }}</div>
<div *ngIf="competency.competency.hasrelatedcompetencies">
<p *ngFor="let relatedcomp of competency.competency.relatedcompetencies">
<a (click)="openCompetencySummary(relatedcomp.id)">
{{ relatedcomp.shortname }} - {{ relatedcomp.idnumber }}
</a>
</p>
</div>
</ion-item>
<ion-item text-wrap *ngIf="coursemodules">
<strong>{{ 'addon.competency.activities' | translate }}</strong>:
<span *ngIf="coursemodules.length == 0">
{{ 'addon.competency.noactivities' | translate }}
</span>
<a ion-item text-wrap *ngFor="let activity of coursemodules" [href]="activity.url" [title]="activity.name">
<img item-start core-external-content [src]="activity.iconurl" alt="" role="presentation" *ngIf="activity.iconurl" class="core-module-icon">
<core-format-text [text]="activity.name"></core-format-text>
</a>
</ion-item>
<ion-item text-wrap *ngIf="competency.usercompetency.status">
<strong>{{ 'addon.competency.reviewstatus' | translate }}</strong>:
{{ competency.usercompetency.statusname }}
</ion-item>
<ion-item text-wrap>
<strong>{{ 'addon.competency.proficient' | translate }}</strong>:
<ion-badge color="success" *ngIf="competency.usercompetency.proficiency">
{{ 'core.yes' | translate }}
</ion-badge>
<ion-badge color="danger" *ngIf="!competency.usercompetency.proficiency">
{{ 'core.no' | translate }}
</ion-badge>
</ion-item>
<ion-item text-wrap>
<strong>{{ 'addon.competency.rating' | translate }}</strong>:
<ion-badge color="dark">{{ competency.usercompetency.gradename }}</ion-badge>
</ion-item>
</ion-card>
<div *ngIf="competency">
<h3 margin-horizontal>{{ 'addon.competency.evidence' | translate }}</h3>
<p margin-horizontal *ngIf="competency.evidence.length == 0">
{{ 'addon.competency.noevidence' | translate }}
</p>
<ion-card *ngFor="let evidence of competency.evidence">
<a ion-item text-wrap *ngIf="evidence.actionuser" (click)="openUserProfile(evidence.actionuser.id)">
<ion-avatar item-start>
<img core-external-content [src]="evidence.actionuser.profileimageurlsmall" [alt]="'core.pictureof' | translate:{$a: evidence.actionuser.fullname}" role="presentation">
</ion-avatar>
<h2>{{ evidence.actionuser.fullname }}</h2>
<p>{{ evidence.timemodified | coreToLocaleString }}</p>
</a>
<ion-item text-wrap>
<p><ion-badge color="dark">{{ evidence.gradename }}</ion-badge></p>
<p margin-top *ngIf="evidence.description">{{ evidence.description }}</p>
<blockquote *ngIf="evidence.note"><core-format-text [text]="evidence.note"></core-format-text></blockquote>
</ion-item>
</ion-card>
</div>
</core-loading>
</ion-content>

@ -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 { CoreComponentsModule } from '@components/components.module';
import { CoreDirectivesModule } from '@directives/directives.module';
import { CorePipesModule } from '@pipes/pipes.module';
import { AddonCompetencyCompetencyPage } from './competency';
@NgModule({
declarations: [
AddonCompetencyCompetencyPage,
],
imports: [
CoreComponentsModule,
CoreDirectivesModule,
CorePipesModule,
IonicPageModule.forChild(AddonCompetencyCompetencyPage),
TranslateModule.forChild()
],
})
export class AddonCompetencyCompetencyPageModule {}

@ -0,0 +1,178 @@
// (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, Optional } from '@angular/core';
import { IonicPage, NavController, NavParams } from 'ionic-angular';
import { TranslateService } from '@ngx-translate/core';
import { CoreSitesProvider } from '@providers/sites';
import { CoreDomUtilsProvider } from '@providers/utils/dom';
import { CoreSplitViewComponent } from '@components/split-view/split-view';
import { AddonCompetencyProvider } from '../../providers/competency';
/**
* Page that displays a learning plan.
*/
@IonicPage({ segment: 'addon-competency-competency' })
@Component({
selector: 'page-addon-competency-competency',
templateUrl: 'competency.html',
})
export class AddonCompetencyCompetencyPage {
competencyLoaded = false;
competencyId: number;
planId: number;
courseId: number;
userId: number;
planStatus: number;
coursemodules: any;
user: any;
competency: any;
constructor(private navCtrl: NavController, navParams: NavParams, private translate: TranslateService,
private sitesProvider: CoreSitesProvider, private domUtils: CoreDomUtilsProvider,
@Optional() private svComponent: CoreSplitViewComponent, private competencyProvider: AddonCompetencyProvider) {
this.competencyId = navParams.get('competencyId');
this.planId = navParams.get('planId');
this.courseId = navParams.get('courseId');
this.userId = navParams.get('userId');
}
/**
* View loaded.
*/
ionViewDidLoad(): void {
this.fetchCompetency().then(() => {
if (this.planId) {
this.competencyProvider.logCompetencyInPlanView(this.planId, this.competencyId, this.planStatus, this.userId);
} else {
this.competencyProvider.logCompetencyInCourseView(this.courseId, this.competencyId, this.userId);
}
}).finally(() => {
this.competencyLoaded = true;
});
}
/**
* Fetches the competency and updates the view.
*
* @return {Promise<void>} Promise resolved when done.
*/
protected fetchCompetency(): Promise<void> {
let promise;
if (this.planId) {
this.planStatus = null;
promise = this.competencyProvider.getCompetencyInPlan(this.planId, this.competencyId);
} else if (this.courseId) {
promise = this.competencyProvider.getCompetencyInCourse(this.courseId, this.competencyId, this.userId);
} else {
promise = Promise.reject(null);
}
return promise.then((competency) => {
this.competency = competency.usercompetencysummary;
if (this.planId) {
this.planStatus = competency.plan.status;
this.competency.usercompetency.statusname = this.getStatusName(this.competency.usercompetency.status);
} else {
this.competency.usercompetency = this.competency.usercompetencycourse;
this.coursemodules = competency.coursemodules;
}
if (this.competency.user.id != this.sitesProvider.getCurrentSiteUserId()) {
this.competency.user.profileimageurl = this.competency.user.profileimageurl || true;
// Get the user profile image from the returned object.
this.user = this.competency.user;
}
this.competency.evidence.forEach((evidence) => {
if (evidence.descidentifier) {
const key = 'addon.competency.' + evidence.descidentifier;
evidence.description = this.translate.instant(key, {$a: evidence.desca});
}
});
}).catch((message) => {
this.domUtils.showErrorModalDefault(message, 'Error getting competency data.');
});
}
/**
* Convenience function to get the review status name translated.
*
* @param {number} status
* @return {string}
*/
protected getStatusName(status: number): string {
let statusTranslateName;
switch (status) {
case AddonCompetencyProvider.REVIEW_STATUS_IDLE:
statusTranslateName = 'idle';
break;
case AddonCompetencyProvider.REVIEW_STATUS_IN_REVIEW:
statusTranslateName = 'inreview';
break;
case AddonCompetencyProvider.REVIEW_STATUS_WAITING_FOR_REVIEW:
statusTranslateName = 'waitingforreview';
break;
default:
// We can use the current status name.
return String(status);
}
return this.translate.instant('addon.competency.usercompetencystatus_' + statusTranslateName);
}
/**
* Refreshes the competency.
*
* @param {any} refresher Refresher.
*/
refreshCompetency(refresher: any): void {
let promise;
if (this.planId) {
promise = this.competencyProvider.invalidateCompetencyInPlan(this.planId, this.competencyId);
} else {
promise = this.competencyProvider.invalidateCompetencyInCourse(this.courseId, this.competencyId);
}
return promise.finally(() => {
this.fetchCompetency().finally(() => {
refresher.complete();
});
});
}
/**
* Opens the summary of a competency.
*
* @param {number} competencyId
*/
openCompetencySummary(competencyId: number): void {
// Decide which navCtrl to use. If this page is inside a split view, use the split view's master nav.
const navCtrl = this.svComponent ? this.svComponent.getMasterNav() : this.navCtrl;
navCtrl.push('AddonCompetencyCompetencySummaryPage', {competencyId});
}
/**
* Opens the profile of a user.
*
* @param {number} userId
*/
openUserProfile(userId: number): void {
// Decide which navCtrl to use. If this page is inside a split view, use the split view's master nav.
const navCtrl = this.svComponent ? this.svComponent.getMasterNav() : this.navCtrl;
navCtrl.push('CoreUserProfilePage', {userId, courseId: this.courseId});
}
}

@ -0,0 +1,24 @@
<ion-header>
<ion-navbar>
<ion-title *ngIf="competency">{{ competency.competency.shortname }} <small>{{ competency.competency.idnumber }}</small></ion-title>
</ion-navbar>
</ion-header>
<ion-content>
<ion-refresher [enabled]="competencyLoaded" (ionRefresh)="refreshCompetency($event)">
<ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}"></ion-refresher-content>
</ion-refresher>
<core-loading [hideUntil]="competencyLoaded">
<ion-card *ngIf="competency">
<ion-item text-wrap *ngIf="competency.competency.description">
<core-format-text [text]="competency.competency.description"></core-format-text>
</ion-item>
<ion-item text-wrap>
<strong>{{ 'addon.competency.path' | translate }}</strong>:
{{ competency.comppath.framework.name }}
<span *ngFor="let ancestor of competency.comppath.ancestors">
&nbsp;/&nbsp;<a (click)="openCompetencySummary(ancestor.id)">{{ ancestor.name }}</a>
</span>
</ion-item>
</ion-card>
</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 { CoreComponentsModule } from '@components/components.module';
import { CoreDirectivesModule } from '@directives/directives.module';
import { AddonCompetencyCompetencySummaryPage } from './competencysummary';
@NgModule({
declarations: [
AddonCompetencyCompetencySummaryPage,
],
imports: [
CoreComponentsModule,
CoreDirectivesModule,
IonicPageModule.forChild(AddonCompetencyCompetencySummaryPage),
TranslateModule.forChild()
],
})
export class AddonCompetencyCompetencySummaryPageModule {}

@ -0,0 +1,86 @@
// (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, Optional } from '@angular/core';
import { IonicPage, NavController, NavParams } from 'ionic-angular';
import { CoreDomUtilsProvider } from '@providers/utils/dom';
import { CoreSplitViewComponent } from '@components/split-view/split-view';
import { AddonCompetencyProvider } from '../../providers/competency';
/**
* Page that displays a learning plan.
*/
@IonicPage({ segment: 'addon-competency-competency-summary' })
@Component({
selector: 'page-addon-competency-competency-summary',
templateUrl: 'competencysummary.html',
})
export class AddonCompetencyCompetencySummaryPage {
competencyLoaded = false;
competencyId: number;
competency: any;
constructor(private navCtrl: NavController, navParams: NavParams, private domUtils: CoreDomUtilsProvider,
@Optional() private svComponent: CoreSplitViewComponent, private competencyProvider: AddonCompetencyProvider) {
this.competencyId = navParams.get('competencyId');
}
/**
* View loaded.
*/
ionViewDidLoad(): void {
this.fetchCompetency().then(() => {
this.competencyProvider.logCompetencyView(this.competencyId);
}).finally(() => {
this.competencyLoaded = true;
});
}
/**
* Fetches the competency summary and updates the view.
*
* @return {Promise<void>} Promise resolved when done.
*/
protected fetchCompetency(): Promise<void> {
return this.competencyProvider.getCompetencySummary(this.competencyId).then((competency) => {
this.competency = competency;
}).catch((message) => {
this.domUtils.showErrorModalDefault(message, 'Error getting competency summary data.');
});
}
/**
* Refreshes the competency summary.
*
* @param {any} refresher Refresher.
*/
refreshCompetency(refresher: any): void {
this.competencyProvider.invalidateCompetencySummary(this.competencyId).finally(() => {
this.fetchCompetency().finally(() => {
refresher.complete();
});
});
}
/**
* Opens the summary of a competency.
*
* @param {number} competencyId
*/
openCompetencySummary(competencyId: number): void {
// Decide which navCtrl to use. If this page is inside a split view, use the split view's master nav.
const navCtrl = this.svComponent ? this.svComponent.getMasterNav() : this.navCtrl;
navCtrl.push('AddonCompetencyCompetencySummaryPage', {competencyId});
}
}

@ -0,0 +1,6 @@
<ion-header>
<ion-navbar>
<ion-title>{{ 'addon.competency.coursecompetencies' | translate }}</ion-title>
</ion-navbar>
</ion-header>
<addon-competency-course class="core-avoid-header" [courseId]="courseId" [userId]="userId"></addon-competency-course>

@ -0,0 +1,31 @@
// (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 { AddonCompetencyComponentsModule } from '../../components/components.module';
import { AddonCompetencyCourseCompetenciesPage } from './coursecompetencies';
@NgModule({
declarations: [
AddonCompetencyCourseCompetenciesPage,
],
imports: [
IonicPageModule.forChild(AddonCompetencyCourseCompetenciesPage),
TranslateModule.forChild(),
AddonCompetencyComponentsModule
],
})
export class AddonCompetencyCourseCompetenciesPageModule {}

@ -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 { Component } from '@angular/core';
import { IonicPage, NavParams } from 'ionic-angular';
/**
* Page that displays the list of competencies of a course.
*/
@IonicPage({ segment: 'addon-competency-coursecompetencies' })
@Component({
selector: 'page-addon-competency-coursecompetencies',
templateUrl: 'coursecompetencies.html',
})
export class AddonCompetencyCourseCompetenciesPage {
protected courseId: number;
protected userId: number;
constructor(navParams: NavParams) {
this.courseId = navParams.get('courseId');
this.userId = navParams.get('userId');
}
}

@ -0,0 +1,56 @@
<ion-header>
<ion-navbar>
<ion-title *ngIf="plan">{{plan.plan.name}}</ion-title>
</ion-navbar>
</ion-header>
<ion-content>
<ion-refresher [enabled]="planLoaded" (ionRefresh)="refreshLearningPlan($event)">
<ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}"></ion-refresher-content>
</ion-refresher>
<core-loading [hideUntil]="planLoaded">
<ion-card *ngIf="user">
<ion-item text-wrap>
<ion-avatar *ngIf="user.profileimageurl && user.profileimageurl !== true" item-start>
<img [src]="user.profileimageurl" [alt]="'core.pictureof' | translate:{$a: user.fullname}" core-external-content>
</ion-avatar>
<span *ngIf="user.profileimageurl === true" item-start>
<ion-icon name="person"></ion-icon>
</span>
<h2><core-format-text [text]="user.fullname"></core-format-text></h2>
</ion-item>
</ion-card>
<ion-card *ngIf="plan">
<ion-list>
<ion-item text-wrap>
<strong>{{ 'addon.competency.status' | translate }}</strong>:
{{ plan.plan.statusname }}
</ion-item>
<ion-item text-wrap *ngIf="plan.plan.duedate > 0">
<strong>{{ 'addon.competency.duedate' | translate }}</strong>:
{{ plan.plan.duedate | coreToLocaleString }}
</ion-item>
<ion-item text-wrap *ngIf="plan.plan.template">
<strong>{{ 'addon.competency.template' | translate }}</strong>:
{{ plan.plan.template.shortname }}
</ion-item>
<ion-item text-wrap>
<strong>{{ 'addon.competency.progress' | translate }}</strong>:
{{ 'addon.competency.xcompetenciesproficientoutofy' | translate: {$a: {x: plan.proficientcompetencycount, y: plan.competencycount} } }}
<core-progress-bar [progress]="plan.proficientcompetencypercentage" [text]="plan.proficientcompetencypercentageformatted"></core-progress-bar>
</ion-item>
</ion-list>
</ion-card>
<ion-card *ngIf="plan">
<ion-card-header text-wrap>{{ 'addon.competency.learningplancompetencies' | translate }}</ion-card-header>
<ion-list>
<ion-item text-wrap *ngIf="plan.competencycount == 0">
{{ 'addon.competency.nocompetencies' | translate }}
</ion-item>
<a ion-item text-wrap *ngFor="let competency of plan.competencies" (click)="openCompetency(competency.competency.id)" [title]="competency.competency.shortname">
{{competency.competency.shortname}} <small>{{competency.competency.idnumber}}</small>
<ion-badge item-end [color]="competency.usercompetency.proficiency ? 'success' : 'danger'">{{ competency.usercompetency.gradename }}</ion-badge>
</a>
</ion-list>
</ion-card>
</core-loading>
</ion-content>

@ -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 { CoreComponentsModule } from '@components/components.module';
import { CoreDirectivesModule } from '@directives/directives.module';
import { CorePipesModule } from '@pipes/pipes.module';
import { AddonCompetencyPlanPage } from './plan';
@NgModule({
declarations: [
AddonCompetencyPlanPage,
],
imports: [
CoreComponentsModule,
CoreDirectivesModule,
CorePipesModule,
IonicPageModule.forChild(AddonCompetencyPlanPage),
TranslateModule.forChild()
],
})
export class AddonCompetencyPlanPageModule {}

@ -0,0 +1,130 @@
// (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, Optional } from '@angular/core';
import { IonicPage, NavController, NavParams } from 'ionic-angular';
import { TranslateService } from '@ngx-translate/core';
import { CoreAppProvider } from '@providers/app';
import { CoreDomUtilsProvider } from '@providers/utils/dom';
import { CoreSplitViewComponent } from '@components/split-view/split-view';
import { AddonCompetencyProvider } from '../../providers/competency';
import { AddonCompetencyHelperProvider } from '../../providers/helper';
/**
* Page that displays a learning plan.
*/
@IonicPage({ segment: 'addon-competency-plan' })
@Component({
selector: 'page-addon-competency-plan',
templateUrl: 'plan.html',
})
export class AddonCompetencyPlanPage {
protected planId: number;
planLoaded = false;
plan: any;
user: any;
constructor(private navCtrl: NavController, navParams: NavParams, private translate: TranslateService,
private appProvider: CoreAppProvider, private domUtils: CoreDomUtilsProvider,
@Optional() private svComponent: CoreSplitViewComponent, private competencyProvider: AddonCompetencyProvider,
private competencyHelperProvider: AddonCompetencyHelperProvider) {
this.planId = navParams.get('planId');
}
/**
* View loaded.
*/
ionViewDidLoad(): void {
this.fetchLearningPlan().finally(() => {
this.planLoaded = true;
});
}
/**
* Fetches the learning plan and updates the view.
*
* @return {Promise<void>} Promise resolved when done.
*/
protected fetchLearningPlan(): Promise<void> {
return this.competencyProvider.getLearningPlan(this.planId).then((plan) => {
plan.plan.statusname = this.getStatusName(plan.plan.status);
// Get the user profile image.
this.competencyHelperProvider.getProfile(plan.plan.userid).then((user) => {
this.user = user;
});
this.plan = plan;
}).catch((message) => {
this.domUtils.showErrorModalDefault(message, 'Error getting learning plan data.');
});
}
/**
* Navigates to a particular competency.
*
* @param {number} competencyId
*/
openCompetency(competencyId: number): void {
const navCtrl = this.svComponent ? this.svComponent.getMasterNav() : this.navCtrl;
if (this.appProvider.isWide()) {
navCtrl.push('AddonCompetencyCompetenciesPage', {competencyId, planId: this.planId});
} else {
navCtrl.push('AddonCompetencyCompetencyPage', {competencyId, planId: this.planId});
}
}
/**
* Convenience function to get the status name translated.
*
* @param {number} status
* @return {string}
*/
protected getStatusName(status: number): string {
let statusTranslateName;
switch (status) {
case AddonCompetencyProvider.STATUS_DRAFT:
statusTranslateName = 'draft';
break;
case AddonCompetencyProvider.REVIEW_STATUS_IN_REVIEW:
statusTranslateName = 'inreview';
break;
case AddonCompetencyProvider.REVIEW_STATUS_WAITING_FOR_REVIEW:
statusTranslateName = 'waitingforreview';
break;
case AddonCompetencyProvider.STATUS_ACTIVE:
statusTranslateName = 'active';
break;
case AddonCompetencyProvider.STATUS_COMPLETE:
statusTranslateName = 'complete';
break;
default:
// We can use the current status name.
return String(status);
}
return this.translate.instant('addon.competency.planstatus' + statusTranslateName);
}
/**
* Refreshes the learning plan.
*
* @param {any} refresher Refresher.
*/
refreshLearningPlan(refresher: any): void {
this.competencyProvider.invalidateLearningPlan(this.planId).finally(() => {
this.fetchLearningPlan().finally(() => {
refresher.complete();
});
});
}
}

@ -0,0 +1,22 @@
<ion-header>
<ion-navbar>
<ion-title>{{ 'addon.competency.userplans' | translate }}</ion-title>
</ion-navbar>
</ion-header>
<core-split-view>
<ion-content>
<ion-refresher [enabled]="plansLoaded" (ionRefresh)="refreshLearningPlans($event)">
<ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}"></ion-refresher-content>
</ion-refresher>
<core-loading [hideUntil]="plansLoaded">
<core-empty-box *ngIf="plans.length == 0" icon="map" [message]="'addon.competency.noplanswerecreated' | translate">
</core-empty-box>
<ion-list *ngIf="plans.length > 0" no-margin>
<a ion-item text-wrap *ngFor="let plan of plans" [title]="plan.name" (click)="openPlan(plan.id)" [class.core-split-item-selected]="plan.id == planId">
<h2>{{ plan.name }}</h2>
<p *ngIf="plan.duedate > 0">{{ 'addon.competency.duedate' | translate }}: {{ plan.duedate | coreToLocaleString }}</p>
</a>
</ion-list>
</core-loading>
</ion-content>
</core-split-view>

@ -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 { CoreComponentsModule } from '@components/components.module';
import { CorePipesModule } from '@pipes/pipes.module';
import { AddonCompetencyPlanListPage } from './planlist';
@NgModule({
declarations: [
AddonCompetencyPlanListPage,
],
imports: [
CoreComponentsModule,
CorePipesModule,
IonicPageModule.forChild(AddonCompetencyPlanListPage),
TranslateModule.forChild()
],
})
export class AddonCompetencyPlanListPageModule {}

@ -0,0 +1,95 @@
// (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, NavParams } from 'ionic-angular';
import { CoreDomUtilsProvider } from '@providers/utils/dom';
import { CoreSplitViewComponent } from '@components/split-view/split-view';
import { AddonCompetencyProvider } from '../../providers/competency';
/**
* Page that displays the list of learning plans.
*/
@IonicPage({ segment: 'addon-competency-planlist' })
@Component({
selector: 'page-addon-competency-planlist',
templateUrl: 'planlist.html',
})
export class AddonCompetencyPlanListPage {
@ViewChild(CoreSplitViewComponent) splitviewCtrl: CoreSplitViewComponent;
protected userId: number;
protected planId: number;
plansLoaded = false;
plans = [];
constructor(navParams: NavParams, private domUtils: CoreDomUtilsProvider, private competencyProvider: AddonCompetencyProvider) {
this.userId = navParams.get('userId');
}
/**
* View loaded.
*/
ionViewDidLoad(): void {
if (this.planId) {
// There is a learning plan to load.
this.openPlan(this.planId);
}
this.fetchLearningPlans().then(() => {
if (!this.planId && this.splitviewCtrl.isOn() && this.plans.length > 0) {
// Take first and load it.
this.openPlan(this.plans[0].id);
}
}).finally(() => {
this.plansLoaded = true;
});
}
/**
* Fetches the learning plans and updates the view.
*
* @return {Promise<void>} Promise resolved when done.
*/
protected fetchLearningPlans(): Promise<void> {
return this.competencyProvider.getLearningPlans(this.userId).then((plans) => {
this.plans = plans;
}).catch((message) => {
this.domUtils.showErrorModalDefault(message, 'Error getting learning plans data.');
});
}
/**
* Refreshes the learning plans.
*
* @param {any} refresher Refresher.
*/
refreshLearningPlans(refresher: any): void {
this.competencyProvider.invalidateLearningPlans(this.userId).finally(() => {
this.fetchLearningPlans().finally(() => {
refresher.complete();
});
});
}
/**
* Opens a learning plan.
*
* @param {number} planId Learning plan to load.
*/
openPlan(planId: number): void {
this.planId = planId;
this.splitviewCtrl.push('AddonCompetencyPlanPage', { planId });
}
}

@ -0,0 +1,519 @@
// (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 { Injectable } from '@angular/core';
import { CoreLoggerProvider } from '@providers/logger';
import { CoreSitesProvider } from '@providers/sites';
/**
* Service to handle caompetency learning plans.
*/
@Injectable()
export class AddonCompetencyProvider {
static STATUS_DRAFT = 0;
static STATUS_ACTIVE = 1;
static STATUS_COMPLETE = 2;
static STATUS_WAITIN_GFOR_REVIEW = 3;
static STATUS_IN_REVIEW = 4;
static REVIEW_STATUS_IDLE = 0;
static REVIEW_STATUS_WAITING_FOR_REVIEW = 1;
static REVIEW_STATUS_IN_REVIEW = 2;
protected ROOT_CACHE_KEY = 'mmaCompetency:';
protected logger;
constructor(loggerProvider: CoreLoggerProvider, private sitesProvider: CoreSitesProvider) {
this.logger = loggerProvider.getInstance('AddonCompetencyProvider');
}
/**
* Get cache key for user learning plans data WS calls.
*
* @param {number} userId User ID.
* @return {string} Cache key.
*/
protected getLearningPlansCacheKey(userId: number): string {
return this.ROOT_CACHE_KEY + 'userplans:' + userId;
}
/**
* Get cache key for learning plan data WS calls.
*
* @param {number} planId Plan ID.
* @return {string} Cache key.
*/
protected getLearningPlanCacheKey(planId: number): string {
return this.ROOT_CACHE_KEY + 'learningplan:' + planId;
}
/**
* Get cache key for competency in plan data WS calls.
*
* @param {number} planId Plan ID.
* @param {number} competencyId Competency ID.
* @return {string} Cache key.
*/
protected getCompetencyInPlanCacheKey(planId: number, competencyId: number): string {
return this.ROOT_CACHE_KEY + 'plancompetency:' + planId + ':' + competencyId;
}
/**
* Get cache key for competency in course data WS calls.
*
* @param {number} courseId Course ID.
* @param {number} competencyId Competency ID.
* @param {number} userId User ID.
* @return {string} Cache key.
*/
protected getCompetencyInCourseCacheKey(courseId: number, competencyId: number, userId: number): string {
return this.ROOT_CACHE_KEY + 'coursecompetency:' + userId + ':' + courseId + ':' + competencyId;
}
/**
* Get cache key for competency summary data WS calls.
*
* @param {number} competencyId Competency ID.
* @param {number} userId User ID.
* @return {string} Cache key.
*/
protected getCompetencySummaryCacheKey(competencyId: number, userId: number): string {
return this.ROOT_CACHE_KEY + 'competencysummary:' + userId + ':' + competencyId;
}
/**
* Get cache key for course competencies data WS calls.
*
* @param {number} courseId Course ID.
* @return {string} Cache key.
*/
protected getCourseCompetenciesCacheKey(courseId: number): string {
return this.ROOT_CACHE_KEY + 'coursecompetencies:' + courseId;
}
/**
* Returns whether competencies are enabled.
*
* @param {number} courseId Course ID.
* @param {string} [siteId] Site ID. If not defined, current site.
* @return {Promise<any>} competencies if enabled for the given course, false otherwise.
*/
isPluginForCourseEnabled(courseId: number, siteId?: string): Promise<any> {
if (!this.sitesProvider.isLoggedIn()) {
return Promise.resolve(false);
}
return this.getCourseCompetencies(courseId, 0, siteId).catch(() => {
return false;
});
}
/**
* Get plans for a certain user.
*
* @param {number} [userId] ID of the user. If not defined, current user.
* @param {string} [siteId] Site ID. If not defined, current site.
* @return {Promise<any>} Promise to be resolved when the plans are retrieved.
*/
getLearningPlans(userId?: number, siteId?: string): Promise<any> {
return this.sitesProvider.getSite(siteId).then((site) => {
userId = userId || site.getUserId();
this.logger.debug('Get plans for user ' + userId);
const params = {
userid: userId
},
preSets = {
cacheKey: this.getLearningPlansCacheKey(userId)
};
return site.read('tool_lp_data_for_plans_page', params, preSets).then((response) => {
if (response.plans) {
return response.plans;
}
return Promise.reject(null);
});
});
}
/**
* Get a certain plan.
*
* @param {number} planId ID of the plan.
* @param {string} [siteId] Site ID. If not defined, current site.
* @return {Promise<any>} Promise to be resolved when the plans are retrieved.
*/
getLearningPlan(planId: number, siteId?: string): Promise<any> {
return this.sitesProvider.getSite(siteId).then((site) => {
this.logger.debug('Get plan ' + planId);
const params = {
planid: planId
},
preSets = {
cacheKey: this.getLearningPlanCacheKey(planId)
};
return site.read('tool_lp_data_for_plan_page', params, preSets).then((response) => {
if (response.plan) {
return response;
}
return Promise.reject(null);
});
});
}
/**
* Get a certain competency in a plan.
*
* @param {number} planId ID of the plan.
* @param {number} competencyId ID of the competency.
* @param {string} [siteId] Site ID. If not defined, current site.
* @return {Promise<any>} Promise to be resolved when the plans are retrieved.
*/
getCompetencyInPlan(planId: number, competencyId: number, siteId?: string): Promise<any> {
return this.sitesProvider.getSite(siteId).then((site) => {
this.logger.debug('Get competency ' + competencyId + ' in plan ' + planId);
const params = {
planid: planId,
competencyid: competencyId
},
preSets = {
cacheKey: this.getCompetencyInPlanCacheKey(planId, competencyId)
};
return site.read('tool_lp_data_for_user_competency_summary_in_plan', params, preSets).then((response) => {
if (response.usercompetencysummary) {
return response;
}
return Promise.reject(null);
});
});
}
/**
* Get a certain competency in a course.
*
* @param {number} courseId ID of the course.
* @param {number} competencyId ID of the competency.
* @param {number} [userId] ID of the user. If not defined, current user.
* @param {string} [siteId] Site ID. If not defined, current site.
* @return {Promise<any>} Promise to be resolved when the plans are retrieved.
*/
getCompetencyInCourse(courseId: number, competencyId: number, userId?: number, siteId?: string): Promise<any> {
return this.sitesProvider.getSite(siteId).then((site) => {
userId = userId || site.getUserId();
this.logger.debug('Get competency ' + competencyId + ' in course ' + courseId);
const params = {
courseid: courseId,
competencyid: competencyId,
userid: userId
},
preSets = {
cacheKey: this.getCompetencyInCourseCacheKey(courseId, competencyId, userId)
};
return site.read('tool_lp_data_for_user_competency_summary_in_course', params, preSets).then((response) => {
if (response.usercompetencysummary) {
return response;
}
return Promise.reject(null);
});
});
}
/**
* Get a certain competency summary.
*
* @param {number} competencyId ID of the competency.
* @param {number} [userId] ID of the user. If not defined, current user.
* @param {string} [siteId] Site ID. If not defined, current site.
* @return {Promise<any>} Promise to be resolved when the plans are retrieved.
*/
getCompetencySummary(competencyId: number, userId?: number, siteId?: string): Promise<any> {
return this.sitesProvider.getSite(siteId).then((site) => {
userId = userId || site.getUserId();
this.logger.debug('Get competency ' + competencyId + ' summary for user' + userId);
const params = {
competencyid: competencyId,
userid: userId
},
preSets = {
cacheKey: this.getCompetencySummaryCacheKey(competencyId, userId)
};
return site.read('tool_lp_data_for_user_competency_summary', params, preSets).then((response) => {
if (response.competency) {
return response.competency;
}
return Promise.reject(null);
});
});
}
/**
* Get all competencies in a course.
*
* @param {number} courseId ID of the course.
* @param {number} [userId] ID of the user.
* @param {string} [siteId] Site ID. If not defined, current site.
* @return {Promise<any>} Promise to be resolved when the course competencies are retrieved.
*/
getCourseCompetencies(courseId: number, userId?: number, siteId?: string): Promise<any> {
return this.sitesProvider.getSite(siteId).then((site) => {
this.logger.debug('Get course competencies for course ' + courseId);
const params = {
courseid: courseId
},
preSets = {
cacheKey: this.getCourseCompetenciesCacheKey(courseId)
};
return site.read('tool_lp_data_for_course_competencies_page', params, preSets).then((response) => {
if (response.competencies) {
return response;
}
return Promise.reject(null);
});
}).then((response) => {
if (!userId || userId == this.sitesProvider.getCurrentSiteUserId()) {
return response;
}
const promises = response.competencies.map((competency) =>
this.getCompetencyInCourse(courseId, competency.competency.id, userId, siteId)
);
return Promise.all(promises).then((responses: any[]) => {
responses.forEach((resp, index) => {
response.competencies[index].usercompetencycourse = resp.usercompetencysummary.usercompetencycourse;
});
return response;
});
});
}
/**
* Invalidates User Learning Plans data.
*
* @param {number} [userId] ID of the user. If not defined, current user.
* @param {string} [siteId] Site ID. If not defined, current site.
* @return {Promise<any>} Promise resolved when the data is invalidated.
*/
invalidateLearningPlans(userId?: number, siteId?: string): Promise<any> {
return this.sitesProvider.getSite(siteId).then((site) => {
userId = userId || site.getUserId();
return site.invalidateWsCacheForKey(this.getLearningPlansCacheKey(userId));
});
}
/**
* Invalidates Learning Plan data.
*
* @param {number} planId ID of the plan.
* @param {string} [siteId] Site ID. If not defined, current site.
* @return {Promise<any>} Promise resolved when the data is invalidated.
*/
invalidateLearningPlan(planId: number, siteId?: string): Promise<any> {
return this.sitesProvider.getSite(siteId).then((site) => {
return site.invalidateWsCacheForKey(this.getLearningPlanCacheKey(planId));
});
}
/**
* Invalidates Competency in Plan data.
*
* @param {number} planId ID of the plan.
* @param {number} competencyId ID of the competency.
* @param {string} [siteId] Site ID. If not defined, current site.
* @return {Promise<any>} Promise resolved when the data is invalidated.
*/
invalidateCompetencyInPlan(planId: number, competencyId: number, siteId?: string): Promise<any> {
return this.sitesProvider.getSite(siteId).then((site) => {
return site.invalidateWsCacheForKey(this.getCompetencyInPlanCacheKey(planId, competencyId));
});
}
/**
* Invalidates Competency in Course data.
*
* @param {number} courseId ID of the course.
* @param {number} competencyId ID of the competency.
* @param {number} [userId] ID of the user. If not defined, current user.
* @param {string} [siteId] Site ID. If not defined, current site.
* @return {Promise<any>} Promise resolved when the data is invalidated.
*/
invalidateCompetencyInCourse(courseId: number, competencyId: number, userId?: number, siteId?: string): Promise<any> {
return this.sitesProvider.getSite(siteId).then((site) => {
userId = userId || site.getUserId();
return site.invalidateWsCacheForKey(this.getCompetencyInCourseCacheKey(courseId, competencyId, userId));
});
}
/**
* Invalidates Competency Summary data.
*
* @param {number} competencyId ID of the competency.
* @param {number} [userId] ID of the user. If not defined, current user.
* @param {string} [siteId] Site ID. If not defined, current site.
* @return {Promise<any>} Promise resolved when the data is invalidated.
*/
invalidateCompetencySummary(competencyId: number, userId?: number, siteId?: string): Promise<any> {
return this.sitesProvider.getSite(siteId).then((site) => {
userId = userId || site.getUserId();
return site.invalidateWsCacheForKey(this.getCompetencySummaryCacheKey(competencyId, userId));
});
}
/**
* Invalidates Course Competencies data.
*
* @param {number} courseId ID of the course.
* @param {number} [userId] ID of the user.
* @param {string} [siteId] Site ID. If not defined, current site.
* @return {Promise<any>} Promise resolved when the data is invalidated.
*/
invalidateCourseCompetencies(courseId: number, userId?: number, siteId?: string): Promise<any> {
return this.sitesProvider.getSite(siteId).then((site) => {
return site.invalidateWsCacheForKey(this.getCourseCompetenciesCacheKey(courseId));
}).then(() => {
if (!userId || userId == this.sitesProvider.getCurrentSiteUserId()) {
return;
}
/* Competencies for other users are fetched with getCompetencyInCourse (and saved in their own cache).
We need to fecth the list of competencies to know which ones to invalidate. We can pass 0 as userId
to getCourseCompetencies, we just need the competency IDs and this way we avid extra WS calls. */
return this.getCourseCompetencies(courseId, 0, siteId).then((competencies) => {
const promises = competencies.competencies.map((competency) => {
return this.invalidateCompetencyInCourse(courseId, competency.competency.id, userId, siteId);
});
return Promise.all(promises);
});
});
}
/**
* Report the competency as being viewed in plan.
*
* @param {number} planId ID of the plan.
* @param {number} competencyId ID of the competency.
* @param {number} planStatus Current plan Status to decide what action should be logged.
* @param {number} [userId] User ID. If not defined, current user.
* @param {string} [siteId] Site ID. If not defined, current site.
* @return {Promise<any>} Promise resolved when the WS call is successful.
*/
logCompetencyInPlanView(planId: number, competencyId: number, planStatus: number, userId?: number, siteId?: string)
: Promise<any> {
if (planId && competencyId) {
return this.sitesProvider.getSite(siteId).then((site) => {
userId = userId || site.getUserId();
const params = {
planid: planId,
competencyid: competencyId,
userid: userId
},
preSets = {
typeExpected: 'boolean'
};
if (planStatus == AddonCompetencyProvider.STATUS_COMPLETE) {
return site.write('core_competency_user_competency_plan_viewed', params, preSets);
} else {
return site.write('core_competency_user_competency_viewed_in_plan', params, preSets);
}
});
}
return Promise.reject(null);
}
/**
* Report the competency as being viewed in course.
*
* @param {number} courseId ID of the course.
* @param {number} competencyId ID of the competency.
* @param {number} [userId] User ID. If not defined, current user.
* @param {string} [siteId] Site ID. If not defined, current site.
* @return {Promise<any>} Promise resolved when the WS call is successful.
*/
logCompetencyInCourseView(courseId: number, competencyId: number, userId?: number, siteId?: string): Promise<any> {
if (courseId && competencyId) {
return this.sitesProvider.getSite(siteId).then((site) => {
userId = userId || site.getUserId();
const params = {
courseid: courseId,
competencyid: competencyId,
userid: userId
};
const preSets = {
typeExpected: 'boolean'
};
return site.write('core_competency_user_competency_viewed_in_course', params, preSets);
});
}
return Promise.reject(null);
}
/**
* Report the competency as being viewed.
*
* @param {number} competencyId ID of the competency.
* @param {string} [siteId] Site ID. If not defined, current site.
* @return {Promise<any>} Promise resolved when the WS call is successful.
*/
logCompetencyView(competencyId: number, siteId?: string): Promise<any> {
if (competencyId) {
return this.sitesProvider.getSite(siteId).then((site) => {
const params = {
id: competencyId,
};
const preSets = {
typeExpected: 'boolean'
};
return site.write('core_competency_competency_viewed', params, preSets);
});
}
return Promise.reject(null);
}
}

@ -0,0 +1,109 @@
// (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 { Injectable, Injector } from '@angular/core';
import { CoreCourseOptionsHandler, CoreCourseOptionsHandlerData } from '@core/course/providers/options-delegate';
import { CoreCourseProvider } from '@core/course/providers/course';
import { AddonCompetencyCourseComponent } from '../components/course/course';
import { AddonCompetencyProvider } from '../providers/competency';
/**
* Course nav handler.
*/
@Injectable()
export class AddonCompetencyCourseOptionHandler implements CoreCourseOptionsHandler {
name = 'AddonCompetency';
priority = 700;
protected coursesNavEnabledCache = {};
constructor(private competencyProvider: AddonCompetencyProvider) {}
/**
* Clear courses nav cache.
*/
clearCoursesNavCache(): void {
this.coursesNavEnabledCache = {};
}
/**
* Whether or not the handler is enabled ona site level.
* @return {boolean|Promise<boolean>} Whether or not the handler is enabled on a site level.
*/
isEnabled(): boolean | Promise<boolean> {
return true;
}
/**
* Whether or not the handler is enabled for a certain course.
*
* @param {number} courseId The course ID.
* @param {any} accessData Access type and data. Default, guest, ...
* @param {any} [navOptions] Course navigation options for current user. See CoreCoursesProvider.getUserNavigationOptions.
* @param {any} [admOptions] Course admin options for current user. See CoreCoursesProvider.getUserAdministrationOptions.
* @return {boolean|Promise<boolean>} True or promise resolved with true if enabled.
*/
isEnabledForCourse(courseId: number, accessData: any, navOptions?: any, admOptions?: any): boolean | Promise<boolean> {
if (accessData && accessData.type == CoreCourseProvider.ACCESS_GUEST) {
return false; // Not enabled for guests.
}
if (navOptions && typeof navOptions.competencies != 'undefined') {
return navOptions.competencies;
}
if (typeof this.coursesNavEnabledCache[courseId] != 'undefined') {
return this.coursesNavEnabledCache[courseId];
}
return this.competencyProvider.isPluginForCourseEnabled(courseId).then((competencies) => {
const enabled = competencies ? !competencies.canmanagecoursecompetencies : false;
this.coursesNavEnabledCache[courseId] = enabled;
return enabled;
});
}
/**
* Returns the data needed to render the handler.
*
* @param {Injector} injector Injector.
* @param {number} courseId The course ID.
* @return {CoreCourseOptionsHandlerData|Promise<CoreCourseOptionsHandlerData>} Data or promise resolved with the data.
*/
getDisplayData?(injector: Injector, courseId: number): CoreCourseOptionsHandlerData | Promise<CoreCourseOptionsHandlerData> {
return {
title: 'addon.competency.competencies',
class: 'addon-competency-course-handler',
component: AddonCompetencyCourseComponent
};
}
/**
* Should invalidate the data to determine if the handler is enabled for a certain course.
*
* @param {number} courseId The course ID.
* @param {any} [navOptions] Course navigation options for current user. See CoreCoursesProvider.getUserNavigationOptions.
* @param {any} [admOptions] Course admin options for current user. See CoreCoursesProvider.getUserAdministrationOptions.
* @return {Promise<any>} Promise resolved when done.
*/
invalidateEnabledForCourse(courseId: number, navOptions?: any, admOptions?: any): Promise<any> {
if (navOptions && typeof navOptions.competencies != 'undefined') {
// No need to invalidate anything.
return Promise.resolve();
}
return this.competencyProvider.invalidateCourseCompetencies(courseId);
}
}

@ -0,0 +1,46 @@
// (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 { Injectable } from '@angular/core';
import { CoreSitesProvider } from '@providers/sites';
import { CoreUserProvider } from '@core/user/providers/user';
/**
* Service that provides some features regarding learning plans.
*/
@Injectable()
export class AddonCompetencyHelperProvider {
constructor(private sitesProvider: CoreSitesProvider, private userProvider: CoreUserProvider) {
}
/**
* Convenient helper to get the user profile image.
*
* @param {number} userId User Id
* @return {Promise<any>} User profile Image URL or true if default icon.
*/
getProfile(userId: number): Promise<any> {
if (!userId || userId == this.sitesProvider.getCurrentSiteUserId()) {
return Promise.resolve(false);
}
// Get the user profile to retrieve the user image.
return this.userProvider.getProfile(userId, null, true).then((user) => {
user.profileimageurl = user.profileimageurl || true;
return user;
});
}
}

@ -0,0 +1,54 @@
// (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 { Injectable } from '@angular/core';
import { AddonCompetencyProvider } from './competency';
import { CoreMainMenuHandler, CoreMainMenuHandlerData } from '@core/mainmenu/providers/delegate';
/**
* Handler to inject an option into main menu.
*/
@Injectable()
export class AddonCompetencyMainMenuHandler implements CoreMainMenuHandler {
name = 'AddonCompetency';
priority = 500;
constructor(private competencyProvider: AddonCompetencyProvider) { }
/**
* Check if the handler is enabled on a site level.
*
* @return {boolean} Whether or not the handler is enabled on a site level.
*/
isEnabled(): boolean | Promise<boolean> {
// Check the user has at least one learn plan available.
return this.competencyProvider.getLearningPlans().then((plans) => {
return plans.length > 0;
});
}
/**
* Returns the data needed to render the handler.
*
* @return {CoreMainMenuHandlerData} Data needed to render the handler.
*/
getDisplayData(): CoreMainMenuHandlerData {
return {
icon: 'map',
title: 'addon.competency.myplans',
page: 'AddonCompetencyPlanListPage',
class: 'addon-competency-handler'
};
}
}

@ -0,0 +1,128 @@
// (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 { Injectable } from '@angular/core';
import { CoreUserDelegate, CoreUserProfileHandler, CoreUserProfileHandlerData } from '@core/user/providers/user-delegate';
import { CoreSitesProvider } from '@providers/sites';
import { CoreContentLinksHelperProvider } from '@core/contentlinks/providers/helper';
import { AddonCompetencyProvider } from './competency';
/**
* Profile competencies handler.
*/
@Injectable()
export class AddonCompetencyUserHandler implements CoreUserProfileHandler {
name = 'AddonCompetency';
priority = 900;
type = CoreUserDelegate.TYPE_NEW_PAGE;
participantsNavEnabledCache = {};
usersNavEnabledCache = {};
constructor(private linkHelper: CoreContentLinksHelperProvider, protected sitesProvider: CoreSitesProvider,
private competencyProvider: AddonCompetencyProvider) {
}
/**
* Clear users nav cache.
*/
clearUsersNavCache(): void {
this.participantsNavEnabledCache = {};
this.usersNavEnabledCache = {};
}
/**
* Whether or not the handler is enabled on a site level.
* @return {boolean|Promise<boolean>} Whether or not the handler is enabled on a site level.
*/
isEnabled(): boolean | Promise<boolean> {
return true;
}
/**
* Check if handler is enabled for this user in this context.
*
* @param {any} user User to check.
* @param {number} courseId Course ID.
* @param {any} [navOptions] Course navigation options for current user. See $mmCourses#getUserNavigationOptions.
* @param {any} [admOptions] Course admin options for current user. See $mmCourses#getUserAdministrationOptions.
* @return {boolean|Promise<boolean>} Promise resolved with true if enabled, resolved with false otherwise.
*/
isEnabledForUser(user: any, courseId: number, navOptions?: any, admOptions?: any): boolean | Promise<boolean> {
if (courseId) {
const cacheKey = courseId + '.' + user.id;
// Link on a user course profile.
if (typeof this.participantsNavEnabledCache[cacheKey] != 'undefined') {
return this.participantsNavEnabledCache[cacheKey];
}
return this.competencyProvider.getCourseCompetencies(courseId, user.id).then((response) => {
const enabled = response.competencies.length > 0;
this.participantsNavEnabledCache[cacheKey] = enabled;
return enabled;
}).catch((message) => {
this.participantsNavEnabledCache[cacheKey] = false;
return false;
});
} else {
// Link on a user site profile.
if (typeof this.usersNavEnabledCache[user.id] != 'undefined') {
return this.usersNavEnabledCache[user.id];
}
return this.competencyProvider.getLearningPlans(user.id).then((plans) => {
// Check the user has at least one learn plan available.
const enabled = plans.length > 0;
this.usersNavEnabledCache[user.id] = enabled;
return enabled;
});
}
}
/**
* Returns the data needed to render the handler.
*
* @return {CoreUserProfileHandlerData} Data needed to render the handler.
*/
getDisplayData(user: any, courseId: number): CoreUserProfileHandlerData {
if (courseId) {
return {
icon: 'ribbon',
title: 'addon.competency.competencies',
class: 'addon-competency-handler',
action: (event, navCtrl, user, courseId): void => {
event.preventDefault();
event.stopPropagation();
// Always use redirect to make it the new history root (to avoid "loops" in history).
this.linkHelper.goInSite(navCtrl, 'AddonCompetencyCourseCompetenciesPage', {courseId, userId: user.id});
}
};
} else {
return {
icon: 'map',
title: 'addon.competency.learningplans',
class: 'addon-competency-handler',
action: (event, navCtrl, user, courseId): void => {
event.preventDefault();
event.stopPropagation();
// Always use redirect to make it the new history root (to avoid "loops" in history).
this.linkHelper.goInSite(navCtrl, 'AddonCompetencyPlanListPage', {userId: user.id});
}
};
}
}
}

@ -12,8 +12,8 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
import { Component, ViewChild, OnDestroy } from '@angular/core'; import { Component, OnDestroy } from '@angular/core';
import { IonicPage, NavParams, NavController } from 'ionic-angular'; import { IonicPage, NavParams } from 'ionic-angular';
import { TranslateService } from '@ngx-translate/core'; import { TranslateService } from '@ngx-translate/core';
import { CoreAppProvider } from '@providers/app'; import { CoreAppProvider } from '@providers/app';
import { CoreEventsProvider } from '@providers/events'; import { CoreEventsProvider } from '@providers/events';

@ -16,7 +16,6 @@ import { Injectable } from '@angular/core';
import { CoreSitesProvider } from '@providers/sites'; import { CoreSitesProvider } from '@providers/sites';
import { CoreMimetypeUtilsProvider } from '@providers/utils/mimetype'; import { CoreMimetypeUtilsProvider } from '@providers/utils/mimetype';
import { CoreSite } from '@classes/site'; import { CoreSite } from '@classes/site';
import { Md5 } from 'ts-md5/dist/md5';
/** /**
* Service to handle my files and site files. * Service to handle my files and site files.

@ -18,7 +18,6 @@ import { TranslateService } from '@ngx-translate/core';
import { CoreSitesProvider } from '@providers/sites'; import { CoreSitesProvider } from '@providers/sites';
import { AddonMessagesProvider } from '../../providers/messages'; import { AddonMessagesProvider } from '../../providers/messages';
import { CoreDomUtilsProvider } from '@providers/utils/dom'; import { CoreDomUtilsProvider } from '@providers/utils/dom';
import { CoreUtilsProvider } from '@providers/utils/utils';
import { CoreAppProvider } from '@providers/app'; import { CoreAppProvider } from '@providers/app';
import { CoreEventsProvider } from '@providers/events'; import { CoreEventsProvider } from '@providers/events';

@ -28,7 +28,6 @@ import { AddonMessagesBlockContactUserHandler } from './providers/user-block-con
import { AddonMessagesDiscussionLinkHandler } from './providers/discussion-link-handler'; import { AddonMessagesDiscussionLinkHandler } from './providers/discussion-link-handler';
import { AddonMessagesIndexLinkHandler } from './providers/index-link-handler'; import { AddonMessagesIndexLinkHandler } from './providers/index-link-handler';
import { AddonMessagesSyncCronHandler } from './providers/sync-cron-handler'; import { AddonMessagesSyncCronHandler } from './providers/sync-cron-handler';
import { CoreEventsProvider } from '@providers/events';
import { CoreAppProvider } from '@providers/app'; import { CoreAppProvider } from '@providers/app';
import { CoreSitesProvider } from '@providers/sites'; import { CoreSitesProvider } from '@providers/sites';
import { CoreLocalNotificationsProvider } from '@providers/local-notifications'; import { CoreLocalNotificationsProvider } from '@providers/local-notifications';

@ -33,8 +33,7 @@ export class AddonMessagesIndexPage implements OnDestroy {
protected loadSplitViewObserver: any; protected loadSplitViewObserver: any;
protected siteId: string; protected siteId: string;
constructor(private eventsProvider: CoreEventsProvider, sitesProvider: CoreSitesProvider, constructor(eventsProvider: CoreEventsProvider, sitesProvider: CoreSitesProvider) {
private messagesProvider: AddonMessagesProvider) {
this.siteId = sitesProvider.getCurrentSiteId(); this.siteId = sitesProvider.getCurrentSiteId();

@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
import { Injectable, Inject } from '@angular/core'; import { Injectable } from '@angular/core';
import { AddonMessagesProvider } from './messages'; import { AddonMessagesProvider } from './messages';
import { CoreMainMenuDelegate, CoreMainMenuHandler, CoreMainMenuHandlerToDisplay } from '@core/mainmenu/providers/delegate'; import { CoreMainMenuDelegate, CoreMainMenuHandler, CoreMainMenuHandlerToDisplay } from '@core/mainmenu/providers/delegate';
import { CoreCronHandler } from '@providers/cron'; import { CoreCronHandler } from '@providers/cron';

@ -12,10 +12,9 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
import { Injectable, Inject } from '@angular/core'; import { Injectable } from '@angular/core';
import { AddonMessagesProvider } from './messages'; import { AddonMessagesProvider } from './messages';
import { CoreSettingsHandler, CoreSettingsHandlerData } from '@core/settings/providers/delegate'; import { CoreSettingsHandler, CoreSettingsHandlerData } from '@core/settings/providers/delegate';
import { CoreSitesProvider } from '@providers/sites';
/** /**
* Message settings handler. * Message settings handler.
@ -25,7 +24,7 @@ export class AddonMessagesSettingsHandler implements CoreSettingsHandler {
name = 'AddonMessages'; name = 'AddonMessages';
priority = 600; priority = 600;
constructor(private messagesProvider: AddonMessagesProvider, private sitesProvider: CoreSitesProvider) { constructor(private messagesProvider: AddonMessagesProvider) {
} }
/** /**

@ -14,7 +14,6 @@
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { CoreCronHandler } from '@providers/cron'; import { CoreCronHandler } from '@providers/cron';
import { CoreSitesProvider } from '@providers/sites';
import { AddonMessagesSyncProvider } from './sync'; import { AddonMessagesSyncProvider } from './sync';
/** /**
@ -24,7 +23,7 @@ import { AddonMessagesSyncProvider } from './sync';
export class AddonMessagesSyncCronHandler implements CoreCronHandler { export class AddonMessagesSyncCronHandler implements CoreCronHandler {
name = 'AddonMessagesSyncCronHandler'; name = 'AddonMessagesSyncCronHandler';
constructor(private sitesProvider: CoreSitesProvider, private messagesSync: AddonMessagesSyncProvider) {} constructor(private messagesSync: AddonMessagesSyncProvider) {}
/** /**
* Execute the process. * Execute the process.

@ -15,7 +15,6 @@
import { Injectable, OnDestroy } from '@angular/core'; import { Injectable, OnDestroy } from '@angular/core';
import { CoreUserDelegate, CoreUserProfileHandler, CoreUserProfileHandlerData } from '@core/user/providers/user-delegate'; import { CoreUserDelegate, CoreUserProfileHandler, CoreUserProfileHandlerData } from '@core/user/providers/user-delegate';
import { CoreSitesProvider } from '@providers/sites'; import { CoreSitesProvider } from '@providers/sites';
import { CoreContentLinksHelperProvider } from '@core/contentlinks/providers/helper';
import { AddonMessagesProvider } from './messages'; import { AddonMessagesProvider } from './messages';
import { AddonMessagesBlockContactUserHandler } from './user-block-contact-handler'; import { AddonMessagesBlockContactUserHandler } from './user-block-contact-handler';
import { CoreEventsProvider } from '@providers/events'; import { CoreEventsProvider } from '@providers/events';
@ -40,7 +39,7 @@ export class AddonMessagesAddContactUserHandler implements CoreUserProfileHandle
protected disabled = false; protected disabled = false;
protected updateObs: any; protected updateObs: any;
constructor(private linkHelper: CoreContentLinksHelperProvider, protected sitesProvider: CoreSitesProvider, constructor(protected sitesProvider: CoreSitesProvider,
private messagesProvider: AddonMessagesProvider, protected eventsProvider: CoreEventsProvider, private messagesProvider: AddonMessagesProvider, protected eventsProvider: CoreEventsProvider,
private domUtils: CoreDomUtilsProvider, private translate: TranslateService) { private domUtils: CoreDomUtilsProvider, private translate: TranslateService) {

@ -15,7 +15,6 @@
import { Injectable, OnDestroy } from '@angular/core'; import { Injectable, OnDestroy } from '@angular/core';
import { CoreUserDelegate, CoreUserProfileHandler, CoreUserProfileHandlerData } from '@core/user/providers/user-delegate'; import { CoreUserDelegate, CoreUserProfileHandler, CoreUserProfileHandlerData } from '@core/user/providers/user-delegate';
import { CoreSitesProvider } from '@providers/sites'; import { CoreSitesProvider } from '@providers/sites';
import { CoreContentLinksHelperProvider } from '@core/contentlinks/providers/helper';
import { AddonMessagesProvider } from './messages'; import { AddonMessagesProvider } from './messages';
import { AddonMessagesAddContactUserHandler } from './user-add-contact-handler'; import { AddonMessagesAddContactUserHandler } from './user-add-contact-handler';
import { CoreEventsProvider } from '@providers/events'; import { CoreEventsProvider } from '@providers/events';
@ -40,9 +39,9 @@ export class AddonMessagesBlockContactUserHandler implements CoreUserProfileHand
protected disabled = false; protected disabled = false;
protected updateObs: any; protected updateObs: any;
constructor(private linkHelper: CoreContentLinksHelperProvider, protected sitesProvider: CoreSitesProvider, constructor(protected sitesProvider: CoreSitesProvider, private messagesProvider: AddonMessagesProvider,
private messagesProvider: AddonMessagesProvider, protected eventsProvider: CoreEventsProvider, protected eventsProvider: CoreEventsProvider, private domUtils: CoreDomUtilsProvider,
private domUtils: CoreDomUtilsProvider, private translate: TranslateService) { private translate: TranslateService) {
this.updateObs = eventsProvider.on(AddonMessagesAddContactUserHandler.UPDATED_EVENT, (data) => { this.updateObs = eventsProvider.on(AddonMessagesAddContactUserHandler.UPDATED_EVENT, (data) => {
this.checkButton(data.userId); this.checkButton(data.userId);

@ -70,6 +70,7 @@ import { CoreCompileModule } from '@core/compile/compile.module';
// Addon modules. // Addon modules.
import { AddonCalendarModule } from '@addon/calendar/calendar.module'; import { AddonCalendarModule } from '@addon/calendar/calendar.module';
import { AddonCompetencyModule } from '../addon/competency/competency.module';
import { AddonUserProfileFieldModule } from '@addon/userprofilefield/userprofilefield.module'; import { AddonUserProfileFieldModule } from '@addon/userprofilefield/userprofilefield.module';
import { AddonFilesModule } from '@addon/files/files.module'; import { AddonFilesModule } from '@addon/files/files.module';
import { AddonModBookModule } from '@addon/mod/book/book.module'; import { AddonModBookModule } from '@addon/mod/book/book.module';
@ -148,6 +149,7 @@ export const CORE_PROVIDERS: any[] = [
CoreSitePluginsModule, CoreSitePluginsModule,
CoreCompileModule, CoreCompileModule,
AddonCalendarModule, AddonCalendarModule,
AddonCompetencyModule,
AddonUserProfileFieldModule, AddonUserProfileFieldModule,
AddonFilesModule, AddonFilesModule,
AddonModBookModule, AddonModBookModule,

@ -39,7 +39,7 @@ export class CoreContextMenuComponent implements OnInit, OnDestroy {
protected instanceId: string; protected instanceId: string;
protected parentContextMenu: CoreContextMenuComponent; protected parentContextMenu: CoreContextMenuComponent;
constructor(private translate: TranslateService, private popoverCtrl: PopoverController, private elementRef: ElementRef, constructor(private translate: TranslateService, private popoverCtrl: PopoverController, elementRef: ElementRef,
private domUtils: CoreDomUtilsProvider) { private domUtils: CoreDomUtilsProvider) {
// Create the stream and subscribe to it. We ignore successive changes during 250ms. // Create the stream and subscribe to it. We ignore successive changes during 250ms.
this.itemsChangedStream = new Subject<void>(); this.itemsChangedStream = new Subject<void>();

@ -15,7 +15,6 @@
import { Component, ViewChild, Input, Optional } from '@angular/core'; import { Component, ViewChild, Input, Optional } from '@angular/core';
import { Content, NavParams, NavController } from 'ionic-angular'; import { Content, NavParams, NavController } from 'ionic-angular';
import { CoreGradesProvider } from '../../providers/grades'; import { CoreGradesProvider } from '../../providers/grades';
import { CoreSitesProvider } from '@providers/sites';
import { CoreDomUtilsProvider } from '@providers/utils/dom'; import { CoreDomUtilsProvider } from '@providers/utils/dom';
import { CoreGradesHelperProvider } from '../../providers/helper'; import { CoreGradesHelperProvider } from '../../providers/helper';
import { CoreSplitViewComponent } from '@components/split-view/split-view'; import { CoreSplitViewComponent } from '@components/split-view/split-view';
@ -39,9 +38,8 @@ export class CoreGradesCourseComponent {
gradesTable: any; gradesTable: any;
constructor(private gradesProvider: CoreGradesProvider, private domUtils: CoreDomUtilsProvider, navParams: NavParams, constructor(private gradesProvider: CoreGradesProvider, private domUtils: CoreDomUtilsProvider, navParams: NavParams,
private gradesHelper: CoreGradesHelperProvider, private sitesProvider: CoreSitesProvider, private gradesHelper: CoreGradesHelperProvider, @Optional() private navCtrl: NavController,
@Optional() private navCtrl: NavController, private appProvider: CoreAppProvider, private appProvider: CoreAppProvider, @Optional() private svComponent: CoreSplitViewComponent) {
@Optional() private svComponent: CoreSplitViewComponent) {
} }
/** /**

@ -13,7 +13,6 @@
// limitations under the License. // limitations under the License.
import { Injectable, Injector } from '@angular/core'; import { Injectable, Injector } from '@angular/core';
import { NavController } from 'ionic-angular';
import { CoreCourseOptionsHandler, CoreCourseOptionsHandlerData } from '@core/course/providers/options-delegate'; import { CoreCourseOptionsHandler, CoreCourseOptionsHandlerData } from '@core/course/providers/options-delegate';
import { CoreCourseProvider } from '@core/course/providers/course'; import { CoreCourseProvider } from '@core/course/providers/course';
import { CoreGradesProvider } from './grades'; import { CoreGradesProvider } from './grades';

@ -14,7 +14,6 @@
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { CoreLoggerProvider } from '@providers/logger'; import { CoreLoggerProvider } from '@providers/logger';
import { CoreSite } from '@classes/site';
import { CoreSitesProvider } from '@providers/sites'; import { CoreSitesProvider } from '@providers/sites';
import { CoreCoursesProvider } from '@core/courses/providers/courses'; import { CoreCoursesProvider } from '@core/courses/providers/courses';

@ -15,7 +15,6 @@
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { CoreLoggerProvider } from '@providers/logger'; import { CoreLoggerProvider } from '@providers/logger';
import { CoreSitesProvider } from '@providers/sites'; import { CoreSitesProvider } from '@providers/sites';
import { TranslateService } from '@ngx-translate/core';
import { CoreCoursesProvider } from '@core/courses/providers/courses'; import { CoreCoursesProvider } from '@core/courses/providers/courses';
import { CoreCourseProvider } from '@core/course/providers/course'; import { CoreCourseProvider } from '@core/course/providers/course';
import { CoreGradesProvider } from './grades'; import { CoreGradesProvider } from './grades';
@ -33,8 +32,7 @@ export class CoreGradesHelperProvider {
constructor(logger: CoreLoggerProvider, private coursesProvider: CoreCoursesProvider, constructor(logger: CoreLoggerProvider, private coursesProvider: CoreCoursesProvider,
private gradesProvider: CoreGradesProvider, private sitesProvider: CoreSitesProvider, private gradesProvider: CoreGradesProvider, private sitesProvider: CoreSitesProvider,
private textUtils: CoreTextUtilsProvider, private courseProvider: CoreCourseProvider, private textUtils: CoreTextUtilsProvider, private courseProvider: CoreCourseProvider,
private domUtils: CoreDomUtilsProvider, private translate: TranslateService, private domUtils: CoreDomUtilsProvider, private urlUtils: CoreUrlUtilsProvider) {
private urlUtils: CoreUrlUtilsProvider) {
this.logger = logger.getInstance('CoreGradesHelperProvider'); this.logger = logger.getInstance('CoreGradesHelperProvider');
} }

@ -13,7 +13,7 @@
// limitations under the License. // limitations under the License.
import { Component, ViewChild } from '@angular/core'; import { Component, ViewChild } from '@angular/core';
import { IonicPage, NavController, NavParams, Platform } from 'ionic-angular'; import { IonicPage, NavParams, Platform } from 'ionic-angular';
import { CoreSettingsDelegate, CoreSettingsHandlerData } from '../../providers/delegate'; import { CoreSettingsDelegate, CoreSettingsHandlerData } from '../../providers/delegate';
import { CoreSplitViewComponent } from '@components/split-view/split-view'; import { CoreSplitViewComponent } from '@components/split-view/split-view';
@ -32,8 +32,7 @@ export class CoreSettingsListPage {
isIOS: boolean; isIOS: boolean;
selectedPage: string; selectedPage: string;
constructor(private settingsDelegate: CoreSettingsDelegate, private navCtrl: NavController, platorm: Platform, constructor(private settingsDelegate: CoreSettingsDelegate, platorm: Platform, navParams: NavParams) {
navParams: NavParams) {
this.isIOS = platorm.is('ios'); this.isIOS = platorm.is('ios');
this.selectedPage = navParams.get('page') || false; this.selectedPage = navParams.get('page') || false;

@ -12,10 +12,9 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
import { Directive, Input, OnInit, ElementRef, Optional } from '@angular/core'; import { Directive, OnInit, ElementRef, Optional } from '@angular/core';
import { TranslateService } from '@ngx-translate/core'; import { TranslateService } from '@ngx-translate/core';
import { CoreDomUtilsProvider } from '@providers/utils/dom'; import { CoreDomUtilsProvider } from '@providers/utils/dom';
import { CoreUtilsProvider } from '@providers/utils/utils';
import { CoreSitePluginsProvider } from '../providers/siteplugins'; import { CoreSitePluginsProvider } from '../providers/siteplugins';
import { CoreSitePluginsCallWSBaseDirective } from '../classes/call-ws-directive'; import { CoreSitePluginsCallWSBaseDirective } from '../classes/call-ws-directive';
import { CoreSitePluginsPluginContentComponent } from '../components/plugin-content/plugin-content'; import { CoreSitePluginsPluginContentComponent } from '../components/plugin-content/plugin-content';

@ -20,7 +20,6 @@ import { CoreLangProvider } from '@providers/lang';
import { CoreLoggerProvider } from '@providers/logger'; import { CoreLoggerProvider } from '@providers/logger';
import { CoreSite, CoreSiteWSPreSets } from '@classes/site'; import { CoreSite, CoreSiteWSPreSets } from '@classes/site';
import { CoreSitesProvider } from '@providers/sites'; import { CoreSitesProvider } from '@providers/sites';
import { CoreTextUtilsProvider } from '@providers/utils/text';
import { CoreUtilsProvider } from '@providers/utils/utils'; import { CoreUtilsProvider } from '@providers/utils/utils';
import { CoreConfigConstants } from '../../../configconstants'; import { CoreConfigConstants } from '../../../configconstants';
import { CoreCoursesProvider } from '@core/courses/providers/courses'; import { CoreCoursesProvider } from '@core/courses/providers/courses';
@ -67,8 +66,7 @@ export class CoreSitePluginsProvider {
constructor(logger: CoreLoggerProvider, private sitesProvider: CoreSitesProvider, private utils: CoreUtilsProvider, constructor(logger: CoreLoggerProvider, private sitesProvider: CoreSitesProvider, private utils: CoreUtilsProvider,
private langProvider: CoreLangProvider, private appProvider: CoreAppProvider, private platform: Platform, private langProvider: CoreLangProvider, private appProvider: CoreAppProvider, private platform: Platform,
private filepoolProvider: CoreFilepoolProvider, private coursesProvider: CoreCoursesProvider, private filepoolProvider: CoreFilepoolProvider, private coursesProvider: CoreCoursesProvider) {
private textUtils: CoreTextUtilsProvider) {
this.logger = logger.getInstance('CoreUserProvider'); this.logger = logger.getInstance('CoreUserProvider');
} }

@ -13,7 +13,7 @@
// limitations under the License. // limitations under the License.
import { Component, ViewChild, Input, OnInit } from '@angular/core'; import { Component, ViewChild, Input, OnInit } from '@angular/core';
import { Content, NavParams } from 'ionic-angular'; import { Content } from 'ionic-angular';
import { CoreUserProvider } from '../../providers/user'; import { CoreUserProvider } from '../../providers/user';
import { CoreDomUtilsProvider } from '@providers/utils/dom'; import { CoreDomUtilsProvider } from '@providers/utils/dom';
import { CoreSplitViewComponent } from '@components/split-view/split-view'; import { CoreSplitViewComponent } from '@components/split-view/split-view';

@ -13,7 +13,6 @@
// limitations under the License. // limitations under the License.
import { Injectable, Injector } from '@angular/core'; import { Injectable, Injector } from '@angular/core';
import { NavController } from 'ionic-angular';
import { CoreCourseOptionsHandler, CoreCourseOptionsHandlerData } from '@core/course/providers/options-delegate'; import { CoreCourseOptionsHandler, CoreCourseOptionsHandlerData } from '@core/course/providers/options-delegate';
import { CoreCourseProvider } from '@core/course/providers/course'; import { CoreCourseProvider } from '@core/course/providers/course';
import { CoreUserProvider } from './user'; import { CoreUserProvider } from './user';

@ -15,7 +15,6 @@
import { Directive, Input, OnInit, ElementRef } from '@angular/core'; import { Directive, Input, OnInit, ElementRef } from '@angular/core';
import { CoreFileHelperProvider } from '@providers/file-helper'; import { CoreFileHelperProvider } from '@providers/file-helper';
import { CoreDomUtilsProvider } from '@providers/utils/dom'; import { CoreDomUtilsProvider } from '@providers/utils/dom';
import { CoreUtilsProvider } from '@providers/utils/utils';
/** /**
* Directive to allow downloading and open a file. When the item with this directive is clicked, the file will be * Directive to allow downloading and open a file. When the item with this directive is clicked, the file will be

@ -19,7 +19,6 @@ import { Globalization } from '@ionic-native/globalization';
import { Platform } from 'ionic-angular'; import { Platform } from 'ionic-angular';
import { CoreConfigProvider } from './config'; import { CoreConfigProvider } from './config';
import { CoreConfigConstants } from '../configconstants'; import { CoreConfigConstants } from '../configconstants';
import { Observable } from 'rxjs';
/* /*
* Service to handle language features, like changing the current language. * Service to handle language features, like changing the current language.

@ -55,6 +55,7 @@
"no-eval": true, "no-eval": true,
"no-invalid-this": true, "no-invalid-this": true,
"no-this-assignment": true, "no-this-assignment": true,
"no-unused-variable": true,
"no-var-keyword": true, "no-var-keyword": true,
"switch-default": true, "switch-default": true,
"typeof-compare": true, "typeof-compare": true,