MOBILE-2302 courses: Implement course preview
parent
0c69cbddad
commit
2b8b5b8b87
|
@ -42,6 +42,7 @@
|
|||
// This is done for accessibility reasons when a heading is semantically incorrect.
|
||||
.item .item-heading {
|
||||
@extend h6;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.mm-oauth-icon, .item.mm-oauth-icon, .list .item.mm-oauth-icon {
|
||||
|
|
|
@ -0,0 +1,66 @@
|
|||
<ion-header>
|
||||
<ion-navbar>
|
||||
<ion-title><core-format-text [text]="course.fullname"></core-format-text></ion-title>
|
||||
</ion-navbar>
|
||||
</ion-header>
|
||||
<ion-content>
|
||||
<ion-refresher [enabled]="dataLoaded" (ionRefresh)="refreshData($event)">
|
||||
<ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}"></ion-refresher-content>
|
||||
</ion-refresher>
|
||||
<core-loading [hideUntil]="dataLoaded">
|
||||
|
||||
<ion-list *ngIf="course">
|
||||
<a ion-item text-wrap (click)="openCourse()" [title]="course.fullname">
|
||||
<ion-icon name="ionic" item-start></ion-icon>
|
||||
<h2><core-format-text [text]="course.fullname"></core-format-text></h2>
|
||||
<p *ngIf="course.categoryname">{{course.categoryname}}</p>
|
||||
<p *ngIf="course.startdate">{{course.startdate * 1000 | coreFormatDate:"dfdaymonthyear"}} <span *ngIf="course.enddate"> - {{course.enddate * 1000 | coreFormatDate:"dfdaymonthyear"}}</span></p>
|
||||
</a>
|
||||
|
||||
<ion-item text-wrap *ngIf="course.summary">
|
||||
<core-format-text [text]="course.summary" maxHeight="120"></core-format-text>
|
||||
</ion-item>
|
||||
|
||||
<a ion-item text-wrap *ngIf="course.contacts && course.contacts.length" core-user-link [attr.aria-label]="'core.viewprofile' | translate">
|
||||
<p class="item-heading">{{ 'core.teachers' | translate }}</p>
|
||||
<p *ngFor="let contact of course.contacts">{{contact.fullname}}</p>
|
||||
</a>
|
||||
<!-- <mm-file ng-repeat="file in course.overviewfiles" file="file" component="{{component}}" component-id="{{course.id}}"></mm-file> -->
|
||||
<div *ngIf="!isEnrolled">
|
||||
<ion-item text-wrap *ngFor="let instance of selfEnrolInstances">
|
||||
<p class="item-heading">{{ instance.name }}</p>
|
||||
<button ion-button block (click)="selfEnrolClicked(instance.id)">{{ 'core.courses.enrolme' | translate }}</button>
|
||||
</ion-item>
|
||||
</div>
|
||||
<ion-item text-wrap *ngIf="!isEnrolled && paypalEnabled">
|
||||
<p class="item-heading">{{ 'core.courses.paypalaccepted' | translate }}</p>
|
||||
<p>{{ 'core.paymentinstant' | translate }}</p>
|
||||
<button ion-button block (click)="paypalEnrol()">{{ 'core.courses.sendpaymentbutton' | translate }}</button>
|
||||
</ion-item>
|
||||
<ion-item *ngIf="!isEnrolled && !selfEnrolInstances.length && !paypalEnabled">
|
||||
<p>{{ 'core.courses.notenrollable' | translate }}</p>
|
||||
</ion-item>
|
||||
<!-- @todo: Prefetch course.
|
||||
<a class="item item-icon-left" ng-if="handlersShouldBeShown" ng-click="prefetchCourse()">
|
||||
<i ng-if="prefetchCourseIcon != 'spinner'" class="icon {{prefetchCourseIcon}}"></i>
|
||||
<ion-spinner ng-if="prefetchCourseIcon == 'spinner'" class="icon"></ion-spinner>
|
||||
<h2>{{ 'core.course.downloadcourse' | translate }}</h2>
|
||||
</a> -->
|
||||
<a ion-item (click)="openCourse()" [title]="course.fullname" *ngIf="handlersShouldBeShown">
|
||||
<ion-icon name="briefcase" item-start></ion-icon>
|
||||
<h2>{{ 'core.course.contents' | translate }}</h2>
|
||||
<ion-icon name="arrow-forward" md="ios-arrow-forward" class="icon-accessory" item-end></ion-icon>
|
||||
</a>
|
||||
<div class="mm-course-handlers" *ngIf="handlersShouldBeShown && course._handlers && course._handlers.length">
|
||||
<a ion-item text-wrap *ngFor="let handler of course._handlers" class="mm-courses-handler {{handler.class}}">
|
||||
<ion-icon [name]="icon" item-start></ion-icon>
|
||||
<h2><core-format-text [text]="title | translate"></core-format-text></h2>
|
||||
<ion-icon name="arrow-forward" md="ios-arrow-forward" class="icon-accessory" item-end></ion-icon>
|
||||
</a>
|
||||
</div>
|
||||
<ion-item class="mm-loading-course-handlers text-center" *ngIf="handlersShouldBeShown && !handlersLoaded">
|
||||
<ion-spinner></ion-spinner>
|
||||
</ion-item>
|
||||
</ion-list>
|
||||
</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 { CoreCoursesCoursePreviewPage } from './course-preview';
|
||||
import { CoreComponentsModule } from '../../../../components/components.module';
|
||||
import { CoreDirectivesModule } from '../../../../directives/directives.module';
|
||||
import { CorePipesModule } from '../../../../pipes/pipes.module';
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
CoreCoursesCoursePreviewPage,
|
||||
],
|
||||
imports: [
|
||||
CoreComponentsModule,
|
||||
CoreDirectivesModule,
|
||||
CorePipesModule,
|
||||
IonicPageModule.forChild(CoreCoursesCoursePreviewPage),
|
||||
TranslateModule.forChild()
|
||||
],
|
||||
})
|
||||
export class CoreCoursesCoursePreviewPageModule {}
|
|
@ -0,0 +1,3 @@
|
|||
page-core-courses-course-preview {
|
||||
|
||||
}
|
|
@ -0,0 +1,396 @@
|
|||
// (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, OnDestroy } from '@angular/core';
|
||||
import { IonicPage, NavController, NavParams, Platform, ModalController, Modal } from 'ionic-angular';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { CoreAppProvider } from '../../../../providers/app';
|
||||
import { CoreEventsProvider } from '../../../../providers/events';
|
||||
import { CoreSitesProvider } from '../../../../providers/sites';
|
||||
import { CoreDomUtilsProvider } from '../../../../providers/utils/dom';
|
||||
import { CoreTextUtilsProvider } from '../../../../providers/utils/text';
|
||||
import { CoreCoursesProvider } from '../../providers/courses';
|
||||
|
||||
/**
|
||||
* Page that allows "previewing" a course and enrolling in it if enabled and not enrolled.
|
||||
*/
|
||||
@IonicPage()
|
||||
@Component({
|
||||
selector: 'page-core-courses-course-preview',
|
||||
templateUrl: 'course-preview.html',
|
||||
})
|
||||
export class CoreCoursesCoursePreviewPage implements OnDestroy {
|
||||
course: any;
|
||||
isEnrolled: boolean;
|
||||
handlersShouldBeShown: boolean = true;
|
||||
handlersLoaded: boolean;
|
||||
component = 'CoreCoursesCoursePreview';
|
||||
selfEnrolInstances: any[] = [];
|
||||
paypalEnabled: boolean;
|
||||
dataLoaded: boolean;
|
||||
prefetchCourseIcon: string;
|
||||
|
||||
protected guestWSAvailable: boolean;
|
||||
protected isGuestEnabled: boolean = false;
|
||||
protected guestInstanceId: number;
|
||||
protected enrollmentMethods: any[];
|
||||
protected waitStart = 0;
|
||||
protected enrolUrl: string;
|
||||
protected courseUrl: string;
|
||||
protected paypalReturnUrl: string;
|
||||
protected isMobile: boolean;
|
||||
protected isDesktop: boolean;
|
||||
protected selfEnrolModal: Modal;
|
||||
protected pageDestroyed = false;
|
||||
protected currentInstanceId: number;
|
||||
|
||||
constructor(private navCtrl: NavController, navParams: NavParams, private sitesProvider: CoreSitesProvider,
|
||||
private domUtils: CoreDomUtilsProvider, private textUtils: CoreTextUtilsProvider, appProvider: CoreAppProvider,
|
||||
private coursesProvider: CoreCoursesProvider, private platform: Platform, private modalCtrl: ModalController,
|
||||
private translate: TranslateService, private eventsProvider: CoreEventsProvider) {
|
||||
this.course = navParams.get('course');
|
||||
this.isMobile = appProvider.isMobile();
|
||||
this.isDesktop = appProvider.isDesktop();
|
||||
}
|
||||
|
||||
/**
|
||||
* View loaded.
|
||||
*/
|
||||
ionViewDidLoad() {
|
||||
const currentSite = this.sitesProvider.getCurrentSite(),
|
||||
currentSiteUrl = currentSite && currentSite.getURL();
|
||||
|
||||
this.paypalEnabled = this.course.enrollmentmethods && this.course.enrollmentmethods.indexOf('paypal') > -1;
|
||||
this.guestWSAvailable = this.coursesProvider.isGuestWSAvailable();
|
||||
this.enrolUrl = this.textUtils.concatenatePaths(currentSiteUrl, 'enrol/index.php?id=' + this.course.id);
|
||||
this.courseUrl = this.textUtils.concatenatePaths(currentSiteUrl, 'course/view.php?id=' + this.course.id);
|
||||
this.paypalReturnUrl = this.textUtils.concatenatePaths(currentSiteUrl, 'enrol/paypal/return.php');
|
||||
|
||||
// Initialize the self enrol modal.
|
||||
this.selfEnrolModal = this.modalCtrl.create('CoreCoursesSelfEnrolPasswordPage');
|
||||
this.selfEnrolModal.onDidDismiss((password: string) => {
|
||||
if (typeof password != 'undefined') {
|
||||
this.selfEnrolInCourse(password, this.currentInstanceId);
|
||||
}
|
||||
});
|
||||
|
||||
this.getCourse().finally(() => {
|
||||
// @todo: Prefetch course.
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Page destroyed.
|
||||
*/
|
||||
ngOnDestroy() {
|
||||
this.pageDestroyed = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the user can access as guest.
|
||||
*
|
||||
* @return {Promise<boolean>} Promise resolved if can access as guest, rejected otherwise. Resolve param indicates if
|
||||
* password is required for guest access.
|
||||
*/
|
||||
protected canAccessAsGuest() : Promise<boolean> {
|
||||
if (!this.isGuestEnabled) {
|
||||
return Promise.reject(null);
|
||||
}
|
||||
|
||||
// Search instance ID of guest enrolment method.
|
||||
this.guestInstanceId = undefined;
|
||||
for (let i = 0; i < this.enrollmentMethods.length; i++) {
|
||||
let method = this.enrollmentMethods[i];
|
||||
if (method.type == 'guest') {
|
||||
this.guestInstanceId = method.id;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (this.guestInstanceId) {
|
||||
return this.coursesProvider.getCourseGuestEnrolmentInfo(this.guestInstanceId).then((info) => {
|
||||
if (!info.status) {
|
||||
// Not active, reject.
|
||||
return Promise.reject(null);
|
||||
}
|
||||
return info.passwordrequired;
|
||||
});
|
||||
}
|
||||
|
||||
return Promise.reject(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience function to get course. We use this to determine if a user can see the course or not.
|
||||
*
|
||||
* @param {boolean} refresh Whether the user is refreshing the data.
|
||||
*/
|
||||
protected getCourse(refresh?: boolean) : Promise<any> {
|
||||
// Get course enrolment methods.
|
||||
this.selfEnrolInstances = [];
|
||||
return this.coursesProvider.getCourseEnrolmentMethods(this.course.id).then((methods) => {
|
||||
this.enrollmentMethods = methods;
|
||||
|
||||
this.enrollmentMethods.forEach((method) => {
|
||||
if (method.type === 'self') {
|
||||
this.selfEnrolInstances.push(method);
|
||||
} else if (this.guestWSAvailable && method.type === 'guest') {
|
||||
this.isGuestEnabled = true;
|
||||
}
|
||||
});
|
||||
}).catch((error) => {
|
||||
this.domUtils.showErrorModalDefault(error, 'Error getting enrolment data');
|
||||
}).then(() => {
|
||||
// Check if user is enrolled in the course.
|
||||
return this.coursesProvider.getUserCourse(this.course.id).then((course) => {
|
||||
this.isEnrolled = true;
|
||||
return course;
|
||||
}).catch(() => {
|
||||
// The user is not enrolled in the course. Use getCourses to see if it's an admin/manager and can see the course.
|
||||
this.isEnrolled = false;
|
||||
return this.coursesProvider.getCourse(this.course.id);
|
||||
}).then((course) => {
|
||||
// Success retrieving the course, we can assume the user has permissions to view it.
|
||||
this.course.fullname = course.fullname || this.course.fullname;
|
||||
this.course.summary = course.summary || this.course.summary;
|
||||
return this.loadCourseNavHandlers(refresh, false);
|
||||
}).catch(() => {
|
||||
// The user is not an admin/manager. Check if we can provide guest access to the course.
|
||||
return this.canAccessAsGuest().then((passwordRequired) => {
|
||||
if (!passwordRequired) {
|
||||
return this.loadCourseNavHandlers(refresh, true);
|
||||
} else {
|
||||
return Promise.reject(null);
|
||||
}
|
||||
}).catch(() => {
|
||||
this.course._handlers = [];
|
||||
this.handlersShouldBeShown = false;
|
||||
});
|
||||
});
|
||||
}).finally(() => {
|
||||
this.dataLoaded = true;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Load course nav handlers.
|
||||
*
|
||||
* @param {boolean} refresh Whether the user is refreshing the data.
|
||||
* @param {boolean} guest Whether it's guest access.
|
||||
*/
|
||||
protected loadCourseNavHandlers(refresh: boolean, guest: boolean) : Promise<any> {
|
||||
// @todo: Get the handlers to be shown.
|
||||
return new Promise((resolve, reject) => {
|
||||
this.course._handlers = [];
|
||||
this.handlersShouldBeShown = true;
|
||||
this.handlersLoaded = true;
|
||||
resolve();
|
||||
});
|
||||
// return $mmCoursesDelegate.getNavHandlersToDisplay(course, refresh, guest, true).then(function(handlers) {
|
||||
// course._handlers = handlers;
|
||||
// $scope.handlersShouldBeShown = true;
|
||||
// }).catch(() => {
|
||||
|
||||
// });
|
||||
}
|
||||
|
||||
/**
|
||||
* Open the course.
|
||||
*/
|
||||
openCourse() {
|
||||
if (!this.handlersShouldBeShown) {
|
||||
// Course cannot be opened.
|
||||
return;
|
||||
}
|
||||
|
||||
this.navCtrl.push('CoreCourseSectionPage', {course: this.course});
|
||||
}
|
||||
|
||||
/**
|
||||
* Enrol using PayPal.
|
||||
*/
|
||||
paypalEnrol() {
|
||||
let window,
|
||||
hasReturnedFromPaypal = false,
|
||||
inAppLoadSubscription,
|
||||
inAppFinishSubscription,
|
||||
inAppExitSubscription,
|
||||
appResumeSubscription,
|
||||
urlLoaded = (event) => {
|
||||
if (event.url.indexOf(this.paypalReturnUrl) != -1) {
|
||||
hasReturnedFromPaypal = true;
|
||||
} else if (event.url.indexOf(this.courseUrl) != -1 && hasReturnedFromPaypal) {
|
||||
// User reached the course index page after returning from PayPal, close the InAppBrowser.
|
||||
inAppClosed();
|
||||
window.close();
|
||||
}
|
||||
},
|
||||
inAppClosed = () => {
|
||||
// InAppBrowser closed, refresh data.
|
||||
unsubscribeAll();
|
||||
|
||||
if (!this.dataLoaded) {
|
||||
return;
|
||||
}
|
||||
this.dataLoaded = false;
|
||||
this.refreshData();
|
||||
},
|
||||
unsubscribeAll = () => {
|
||||
inAppLoadSubscription && inAppLoadSubscription.unsubscribe();
|
||||
inAppFinishSubscription && inAppFinishSubscription.unsubscribe();
|
||||
inAppExitSubscription && inAppExitSubscription.unsubscribe();
|
||||
appResumeSubscription && appResumeSubscription.unsubscribe();
|
||||
};
|
||||
|
||||
// Open the enrolment page in InAppBrowser.
|
||||
this.sitesProvider.getCurrentSite().openInAppWithAutoLogin(this.enrolUrl).then((w) => {
|
||||
window = w;
|
||||
|
||||
if (this.isDesktop || this.isMobile) {
|
||||
// Observe loaded pages in the InAppBrowser to check if the enrol process has ended.
|
||||
inAppLoadSubscription = window.on('loadstart').subscribe(urlLoaded);
|
||||
// Observe window closed.
|
||||
inAppExitSubscription = window.on('exit').subscribe(inAppClosed);
|
||||
}
|
||||
|
||||
if (this.isDesktop) {
|
||||
// In desktop, also observe stop loading since some pages don't throw the loadstart event.
|
||||
inAppFinishSubscription = window.on('loadstop').subscribe(urlLoaded);
|
||||
|
||||
// Since the user can switch windows, reload the data if he comes back to the app.
|
||||
appResumeSubscription = this.platform.resume.subscribe(() => {
|
||||
if (!this.dataLoaded) {
|
||||
return;
|
||||
}
|
||||
this.dataLoaded = false;
|
||||
this.refreshData();
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* User clicked in a self enrol button.
|
||||
*
|
||||
* @param {number} instanceId The instance ID of the enrolment method.
|
||||
*/
|
||||
selfEnrolClicked(instanceId: number) {
|
||||
this.domUtils.showConfirm(this.translate.instant('core.courses.confirmselfenrol')).then(() => {
|
||||
this.selfEnrolInCourse('', instanceId);
|
||||
}).catch(() => {
|
||||
// User cancelled.
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Self enrol in a course.
|
||||
*
|
||||
* @param {string} password Password to use.
|
||||
* @param {number} instanceId The instance ID.
|
||||
* @return {Promise<any>} Promise resolved when self enrolled.
|
||||
*/
|
||||
selfEnrolInCourse(password: string, instanceId: number) : Promise<any> {
|
||||
let modal = this.domUtils.showModalLoading('core.loading', true);
|
||||
|
||||
return this.coursesProvider.selfEnrol(this.course.id, password, instanceId).then(() => {
|
||||
// Close modal and refresh data.
|
||||
this.isEnrolled = true;
|
||||
this.dataLoaded = false;
|
||||
|
||||
// Sometimes the list of enrolled courses takes a while to be updated. Wait for it.
|
||||
this.waitForEnrolled(true).then(() => {
|
||||
this.refreshData().finally(() => {
|
||||
// My courses have been updated, trigger event.
|
||||
this.eventsProvider.trigger(
|
||||
CoreCoursesProvider.EVENT_MY_COURSES_UPDATED, {siteId: this.sitesProvider.getCurrentSiteId()});
|
||||
});
|
||||
});
|
||||
}).catch((error) => {
|
||||
if (error && error.code === CoreCoursesProvider.ENROL_INVALID_KEY) {
|
||||
// Invalid password, show the modal to enter the password.
|
||||
this.selfEnrolModal.present();
|
||||
this.currentInstanceId = instanceId;
|
||||
|
||||
if (!password) {
|
||||
// No password entered, don't show error.
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
this.domUtils.showErrorModalDefault(error, 'core.courses.errorselfenrol', true);
|
||||
}).finally(() => {
|
||||
modal.dismiss();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Refresh the data.
|
||||
*
|
||||
* @param {any} [refresher] The refresher if this was triggered by a Pull To Refresh.
|
||||
*/
|
||||
refreshData(refresher?: any) : Promise<any> {
|
||||
let promises = [];
|
||||
|
||||
promises.push(this.coursesProvider.invalidateUserCourses());
|
||||
promises.push(this.coursesProvider.invalidateCourse(this.course.id));
|
||||
promises.push(this.coursesProvider.invalidateCourseEnrolmentMethods(this.course.id));
|
||||
// promises.push($mmCoursesDelegate.clearAndInvalidateCoursesOptions(course.id));
|
||||
if (this.guestInstanceId) {
|
||||
promises.push(this.coursesProvider.invalidateCourseGuestEnrolmentInfo(this.guestInstanceId));
|
||||
}
|
||||
|
||||
return Promise.all(promises).finally(() => {
|
||||
return this.getCourse(true);
|
||||
}).finally(() => {
|
||||
if (refresher) {
|
||||
refresher.complete();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Wait for the user to be enrolled in the course.
|
||||
*
|
||||
* @param {boolean} first If it's the first call (true) or it's a recursive call (false).
|
||||
*/
|
||||
protected waitForEnrolled(first?: boolean) {
|
||||
if (first) {
|
||||
this.waitStart = Date.now();
|
||||
}
|
||||
|
||||
// Check if user is enrolled in the course.
|
||||
return this.coursesProvider.invalidateUserCourses().catch(() => {
|
||||
// Ignore errors.
|
||||
}).then(() => {
|
||||
return this.coursesProvider.getUserCourse(this.course.id);
|
||||
}).catch(() => {
|
||||
// Not enrolled, wait a bit and try again.
|
||||
if (this.pageDestroyed || (Date.now() - this.waitStart > 60000)) {
|
||||
// Max time reached or the user left the view, stop.
|
||||
return;
|
||||
}
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
setTimeout(() => {
|
||||
if (!this.pageDestroyed) {
|
||||
// Wait again.
|
||||
this.waitForEnrolled().then(resolve);
|
||||
} else {
|
||||
resolve();
|
||||
}
|
||||
}, 5000);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
|
@ -12,7 +12,7 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import { Component } from '@angular/core';
|
||||
import { Component, OnDestroy } from '@angular/core';
|
||||
import { IonicPage, NavController } from 'ionic-angular';
|
||||
import { CoreEventsProvider } from '../../../../providers/events';
|
||||
import { CoreSitesProvider } from '../../../../providers/sites';
|
||||
|
@ -27,7 +27,7 @@ import { CoreCoursesProvider } from '../../providers/courses';
|
|||
selector: 'page-core-courses-my-courses',
|
||||
templateUrl: 'my-courses.html',
|
||||
})
|
||||
export class CoreCoursesMyCoursesPage {
|
||||
export class CoreCoursesMyCoursesPage implements OnDestroy {
|
||||
courses: any[];
|
||||
filteredCourses: any[];
|
||||
searchEnabled: boolean;
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
<ion-header>
|
||||
<ion-navbar>
|
||||
<ion-title>{{ 'core.courses.selfenrolment' | translate }}</ion-title>
|
||||
|
||||
<ion-buttons end>
|
||||
<button ion-button icon-only (click)="close()" [attr.aria-label]="'core.close' | translate">
|
||||
<ion-icon name="close"></ion-icon>
|
||||
</button>
|
||||
</ion-buttons>
|
||||
</ion-navbar>
|
||||
</ion-header>
|
||||
<ion-content padding>
|
||||
<form ion-list #f="ngForm" (ngSubmit)="submitPassword(f.value.password)">
|
||||
<ion-item>
|
||||
<core-show-password item-content [name]="'password'">
|
||||
<ion-input text-wrap class="mm-ioninput-password" name="password" type="password" placeholder="{{ 'core.courses.password' | translate }}" ngModel [core-auto-focus]></ion-input>
|
||||
</core-show-password>
|
||||
</ion-item>
|
||||
<ion-item>
|
||||
<button ion-button block [disabled]="!f.value.password">{{ 'core.courses.enrolme' | translate }}</button>
|
||||
</ion-item>
|
||||
</form>
|
||||
</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 { CoreCoursesSelfEnrolPasswordPage } from './self-enrol-password';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { CoreComponentsModule } from '../../../../components/components.module';
|
||||
import { CoreDirectivesModule } from '../../../../directives/directives.module';
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
CoreCoursesSelfEnrolPasswordPage
|
||||
],
|
||||
imports: [
|
||||
CoreComponentsModule,
|
||||
CoreDirectivesModule,
|
||||
IonicPageModule.forChild(CoreCoursesSelfEnrolPasswordPage),
|
||||
TranslateModule.forChild(),
|
||||
]
|
||||
})
|
||||
export class CoreCoursesSelfEnrolPasswordPageModule {}
|
|
@ -0,0 +1,44 @@
|
|||
// (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, ViewController } from 'ionic-angular';
|
||||
|
||||
/**
|
||||
* Page that displays a form to enter a password to self enrol in a course.
|
||||
*/
|
||||
@IonicPage()
|
||||
@Component({
|
||||
selector: 'page-core-courses-self-enrol-password',
|
||||
templateUrl: 'self-enrol-password.html',
|
||||
})
|
||||
export class CoreCoursesSelfEnrolPasswordPage {
|
||||
constructor(private viewCtrl: ViewController) {}
|
||||
|
||||
/**
|
||||
* Close help modal.
|
||||
*/
|
||||
close() : void {
|
||||
this.viewCtrl.dismiss();
|
||||
}
|
||||
|
||||
/**
|
||||
* Submit password.
|
||||
*
|
||||
* @param {string} password Password to submit.
|
||||
*/
|
||||
submitPassword(password: string) {
|
||||
this.viewCtrl.dismiss(password);
|
||||
}
|
||||
}
|
|
@ -24,6 +24,7 @@ import { CoreSite } from '../../../classes/site';
|
|||
export class CoreCoursesProvider {
|
||||
public static SEARCH_PER_PAGE = 20;
|
||||
public static ENROL_INVALID_KEY = 'CoreCoursesEnrolInvalidKey';
|
||||
public static EVENT_MY_COURSES_UPDATED = 'courses_my_courses_updated';
|
||||
protected logger;
|
||||
|
||||
constructor(logger: CoreLoggerProvider, private sitesProvider: CoreSitesProvider) {
|
||||
|
|
Loading…
Reference in New Issue