MOBILE-2302 courses: Implement My Courses
parent
e778448824
commit
2d29cc2da6
102
src/app/app.scss
102
src/app/app.scss
|
@ -113,3 +113,105 @@ ion-avatar ion-img, ion-avatar img {
|
||||||
font-style: italic;
|
font-style: italic;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Format Text */
|
||||||
|
core-format-text[maxHeight], *[core-format-text][maxHeight] {
|
||||||
|
display: block;
|
||||||
|
position: relative;
|
||||||
|
width: 100%;
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
|
/* Force display inline */
|
||||||
|
&.inline {
|
||||||
|
display: inline-block;
|
||||||
|
width: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is to allow clicks in radio/checkbox content.
|
||||||
|
&.mm-text-formatted {
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
.mm-show-more {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:not(.mm-shortened) {
|
||||||
|
max-height: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.mm-shortened {
|
||||||
|
color: $gray-darker;
|
||||||
|
overflow: hidden;
|
||||||
|
min-height: 50px;
|
||||||
|
|
||||||
|
.mm-show-more {
|
||||||
|
color: color($colors, dark);
|
||||||
|
text-align: right;
|
||||||
|
font-size: 14px;
|
||||||
|
display: block;
|
||||||
|
position: absolute;
|
||||||
|
bottom: 0;
|
||||||
|
right: 0;
|
||||||
|
z-index: 1001;
|
||||||
|
background-color: $white;
|
||||||
|
padding-left: 10px;
|
||||||
|
|
||||||
|
/* @todo
|
||||||
|
&:after {
|
||||||
|
@extend .ion;
|
||||||
|
content: $ionicon-var-chevron-down;
|
||||||
|
margin-left: 10px;
|
||||||
|
color: $item-icon-accessory-color;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
&.mm-expand-in-fullview .mm-show-more:after {
|
||||||
|
// content: $ionicon-var-chevron-right; @todo
|
||||||
|
}
|
||||||
|
|
||||||
|
&:before {
|
||||||
|
content: '';
|
||||||
|
height: 100%;
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
background: -moz-linear-gradient(top, rgba(255, 255, 255, 0) calc(100% - 50px), white calc(100% - 15px));
|
||||||
|
background: -webkit-gradient(left top, left bottom, color-stop(calc(100% - 50px), rgba(255, 255, 255, 0)), color-stop(calc(100% - 15px), white));
|
||||||
|
background: -webkit-linear-gradient(top, rgba(255, 255, 255, 0) calc(100% - 50px), white calc(100% - 15px));
|
||||||
|
background: -o-linear-gradient(top, rgba(255, 255, 255, 0) calc(100% - 50px), white calc(100% - 15px));
|
||||||
|
background: -ms-linear-gradient(top, rgba(255, 255, 255, 0) calc(100% - 50px), white calc(100% - 15px));
|
||||||
|
background: linear-gradient(to bottom, rgba(255, 255, 255, 0) calc(100% - 50px), white calc(100% - 15px));
|
||||||
|
z-index: 1000;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
core-format-text, *[core-format-text] {
|
||||||
|
audio, video, a, iframe {
|
||||||
|
pointer-events: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fix lists styles in core-format-text.
|
||||||
|
ul, ol {
|
||||||
|
-webkit-padding-start: 40px;
|
||||||
|
}
|
||||||
|
ul {
|
||||||
|
list-style: disc;
|
||||||
|
}
|
||||||
|
ol {
|
||||||
|
list-style: decimal;
|
||||||
|
}
|
||||||
|
|
||||||
|
.badge {
|
||||||
|
position: initial !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Message item.
|
||||||
|
.item-message {
|
||||||
|
core-format-text > p:only-child {
|
||||||
|
display: inline;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -482,7 +482,14 @@ export class CoreSite {
|
||||||
|
|
||||||
// We pass back a clone of the original object, this may
|
// We pass back a clone of the original object, this may
|
||||||
// prevent errors if in the callback the object is modified.
|
// prevent errors if in the callback the object is modified.
|
||||||
|
if (typeof response == 'object') {
|
||||||
|
if (Array.isArray(response)) {
|
||||||
|
return Array.from(response);
|
||||||
|
} else {
|
||||||
return Object.assign({}, response);
|
return Object.assign({}, response);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return response;
|
||||||
}).catch((error) => {
|
}).catch((error) => {
|
||||||
if (error.errorcode == 'invalidtoken' ||
|
if (error.errorcode == 'invalidtoken' ||
|
||||||
(error.errorcode == 'accessexception' && error.message.indexOf('Invalid token - token expired') > -1)) {
|
(error.errorcode == 'accessexception' && error.message.indexOf('Invalid token - token expired') > -1)) {
|
||||||
|
|
|
@ -22,6 +22,7 @@ import { CoreInputErrorsComponent } from './input-errors/input-errors';
|
||||||
import { CoreShowPasswordComponent } from './show-password/show-password';
|
import { CoreShowPasswordComponent } from './show-password/show-password';
|
||||||
import { CoreIframeComponent } from './iframe/iframe';
|
import { CoreIframeComponent } from './iframe/iframe';
|
||||||
import { CoreProgressBarComponent } from './progress-bar/progress-bar';
|
import { CoreProgressBarComponent } from './progress-bar/progress-bar';
|
||||||
|
import { CoreEmptyBoxComponent } from './empty-box/empty-box';
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
declarations: [
|
declarations: [
|
||||||
|
@ -30,7 +31,8 @@ import { CoreProgressBarComponent } from './progress-bar/progress-bar';
|
||||||
CoreInputErrorsComponent,
|
CoreInputErrorsComponent,
|
||||||
CoreShowPasswordComponent,
|
CoreShowPasswordComponent,
|
||||||
CoreIframeComponent,
|
CoreIframeComponent,
|
||||||
CoreProgressBarComponent
|
CoreProgressBarComponent,
|
||||||
|
CoreEmptyBoxComponent
|
||||||
],
|
],
|
||||||
imports: [
|
imports: [
|
||||||
IonicModule,
|
IonicModule,
|
||||||
|
@ -43,7 +45,8 @@ import { CoreProgressBarComponent } from './progress-bar/progress-bar';
|
||||||
CoreInputErrorsComponent,
|
CoreInputErrorsComponent,
|
||||||
CoreShowPasswordComponent,
|
CoreShowPasswordComponent,
|
||||||
CoreIframeComponent,
|
CoreIframeComponent,
|
||||||
CoreProgressBarComponent
|
CoreProgressBarComponent,
|
||||||
|
CoreEmptyBoxComponent
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
export class CoreComponentsModule {}
|
export class CoreComponentsModule {}
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
<div class="mm-empty-box" [class.mm-empty-box-inline]="!image && !icon">
|
||||||
|
<div class="mm-empty-box-content">
|
||||||
|
<img *ngIf="image && !icon" [src]="image" role="presentation">
|
||||||
|
<ion-icon *ngIf="icon" name="icon"></ion-icon>
|
||||||
|
<p *ngIf="message">{{ message }}</p>
|
||||||
|
<ng-content></ng-content>
|
||||||
|
</div>
|
||||||
|
</div>
|
|
@ -0,0 +1,3 @@
|
||||||
|
core-empty-box {
|
||||||
|
|
||||||
|
}
|
|
@ -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 { Component, Input } from '@angular/core';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Component to show an empty box message. It will show an optional icon or image and a text centered on page.
|
||||||
|
*
|
||||||
|
* Usage:
|
||||||
|
* <core-empty-box *ngIf="empty" icon="bell" [message]="'core.emptymessage' | translate"></core-empty-box>
|
||||||
|
*/
|
||||||
|
@Component({
|
||||||
|
selector: 'core-empty-box',
|
||||||
|
templateUrl: 'empty-box.html'
|
||||||
|
})
|
||||||
|
export class CoreEmptyBoxComponent {
|
||||||
|
@Input() message: string; // Message to display.
|
||||||
|
@Input() icon?: string; // Name of the icon to use.
|
||||||
|
@Input() image?: string; // Image source. If an icon is provided, image won't be used.
|
||||||
|
|
||||||
|
constructor() {}
|
||||||
|
}
|
|
@ -0,0 +1,40 @@
|
||||||
|
// (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 { CoreCoursesCourseProgressComponent } from '../components/course-progress/course-progress';
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
declarations: [
|
||||||
|
CoreCoursesCourseProgressComponent
|
||||||
|
],
|
||||||
|
imports: [
|
||||||
|
CommonModule,
|
||||||
|
IonicModule,
|
||||||
|
TranslateModule.forChild(),
|
||||||
|
CoreComponentsModule,
|
||||||
|
CoreDirectivesModule
|
||||||
|
],
|
||||||
|
providers: [
|
||||||
|
],
|
||||||
|
exports: [
|
||||||
|
CoreCoursesCourseProgressComponent
|
||||||
|
]
|
||||||
|
})
|
||||||
|
export class CoreCoursesComponentsModule {}
|
|
@ -14,19 +14,21 @@
|
||||||
|
|
||||||
import { NgModule } from '@angular/core';
|
import { NgModule } from '@angular/core';
|
||||||
import { CoreCoursesProvider } from './providers/courses';
|
import { CoreCoursesProvider } from './providers/courses';
|
||||||
import { CoreCoursesCourseProgressComponent } from './components/course-progress/course-progress';
|
import { CoreCoursesMainMenuHandler } from './providers/handlers';
|
||||||
|
import { CoreMainMenuDelegate } from '../mainmenu/providers/delegate';
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
declarations: [
|
declarations: [],
|
||||||
CoreCoursesCourseProgressComponent
|
|
||||||
],
|
|
||||||
imports: [
|
imports: [
|
||||||
],
|
],
|
||||||
providers: [
|
providers: [
|
||||||
CoreCoursesProvider
|
CoreCoursesProvider,
|
||||||
|
CoreCoursesMainMenuHandler
|
||||||
],
|
],
|
||||||
exports: [
|
exports: []
|
||||||
CoreCoursesCourseProgressComponent
|
|
||||||
]
|
|
||||||
})
|
})
|
||||||
export class CoreCoursesModule {}
|
export class CoreCoursesModule {
|
||||||
|
constructor(mainMenuDelegate: CoreMainMenuDelegate, mainMenuHandler: CoreCoursesMainMenuHandler) {
|
||||||
|
mainMenuDelegate.registerHandler(mainMenuHandler);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
<ion-header>
|
||||||
|
<ion-navbar>
|
||||||
|
<ion-title>{{ 'core.courses.mycourses' | translate }}</ion-title>
|
||||||
|
|
||||||
|
<ion-buttons end>
|
||||||
|
<button *ngIf="searchEnabled" ion-button icon-only (click)="openSearch()" [attr.aria-label]="'core.courses.searchcourses' | translate">
|
||||||
|
<ion-icon name="search"></ion-icon>
|
||||||
|
</button>
|
||||||
|
<!-- @todo: Context menu. -->
|
||||||
|
</ion-buttons>
|
||||||
|
</ion-navbar>
|
||||||
|
</ion-header>
|
||||||
|
<ion-content>
|
||||||
|
<ion-refresher [enabled]="coursesLoaded" (ionRefresh)="refreshCourses($event)">
|
||||||
|
<ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}"></ion-refresher-content>
|
||||||
|
</ion-refresher>
|
||||||
|
|
||||||
|
<core-loading [hideUntil]="coursesLoaded">
|
||||||
|
<ion-item *ngIf="showFilter" class="item-transparent">
|
||||||
|
<ion-icon name="funnel" class="placeholder-icon" item-start></ion-icon>
|
||||||
|
<ion-input type="text" name="filter" placeholder="{{ 'core.courses.filtermycourses' | translate }}" [(ngModel)]="filter" (ngModelChange)="filterChanged($event)"></ion-input>
|
||||||
|
</ion-item>
|
||||||
|
<core-courses-course-progress *ngFor="let course of filteredCourses" [course]="course" showSummary="true"></core-courses-course-progress>
|
||||||
|
<core-empty-box *ngIf="!courses || !courses.length" icon="ionic" [message]="'core.courses.nocourses' | translate">
|
||||||
|
<p *ngIf="searchEnabled">{{ 'core.courses.searchcoursesadvice' | translate }}</p>
|
||||||
|
</core-empty-box>
|
||||||
|
</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 { CoreCoursesMyCoursesPage } from './my-courses';
|
||||||
|
import { CoreComponentsModule } from '../../../../components/components.module';
|
||||||
|
import { CoreCoursesComponentsModule } from '../../components/components.module';
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
declarations: [
|
||||||
|
CoreCoursesMyCoursesPage,
|
||||||
|
],
|
||||||
|
imports: [
|
||||||
|
CoreComponentsModule,
|
||||||
|
CoreCoursesComponentsModule,
|
||||||
|
IonicPageModule.forChild(CoreCoursesMyCoursesPage),
|
||||||
|
TranslateModule.forChild()
|
||||||
|
],
|
||||||
|
})
|
||||||
|
export class CoreCoursesMyCoursesPageModule {}
|
|
@ -0,0 +1,3 @@
|
||||||
|
page-core-courses-my-courses {
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,154 @@
|
||||||
|
// (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, NavController } from 'ionic-angular';
|
||||||
|
import { CoreEventsProvider } from '../../../../providers/events';
|
||||||
|
import { CoreSitesProvider } from '../../../../providers/sites';
|
||||||
|
import { CoreDomUtilsProvider } from '../../../../providers/utils/dom';
|
||||||
|
import { CoreCoursesProvider } from '../../providers/courses';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Page that displays the list of courses the user is enrolled in.
|
||||||
|
*/
|
||||||
|
@IonicPage()
|
||||||
|
@Component({
|
||||||
|
selector: 'page-core-courses-my-courses',
|
||||||
|
templateUrl: 'my-courses.html',
|
||||||
|
})
|
||||||
|
export class CoreCoursesMyCoursesPage {
|
||||||
|
courses: any[];
|
||||||
|
filteredCourses: any[];
|
||||||
|
searchEnabled: boolean;
|
||||||
|
filter = '';
|
||||||
|
showFilter = false;
|
||||||
|
coursesLoaded = false;
|
||||||
|
|
||||||
|
protected prefetchIconInitialized = false;
|
||||||
|
protected myCoursesObserver;
|
||||||
|
protected siteUpdatedObserver;
|
||||||
|
|
||||||
|
constructor(private navCtrl: NavController, private coursesProvider: CoreCoursesProvider,
|
||||||
|
private domUtils: CoreDomUtilsProvider, private eventsProvider: CoreEventsProvider,
|
||||||
|
private sitesProvider: CoreSitesProvider) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* View loaded.
|
||||||
|
*/
|
||||||
|
ionViewDidLoad() {
|
||||||
|
this.searchEnabled = !this.coursesProvider.isSearchCoursesDisabledInSite();
|
||||||
|
|
||||||
|
this.fetchCourses().finally(() => {
|
||||||
|
this.coursesLoaded = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
this.myCoursesObserver = this.eventsProvider.on(CoreCoursesProvider.EVENT_MY_COURSES_UPDATED, (data) => {
|
||||||
|
if (data.siteId == this.sitesProvider.getCurrentSiteId()) {
|
||||||
|
this.fetchCourses();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
this.siteUpdatedObserver = this.eventsProvider.on(CoreEventsProvider.SITE_UPDATED, (data) => {
|
||||||
|
if (data.siteId == this.sitesProvider.getCurrentSiteId()) {
|
||||||
|
this.searchEnabled = !this.coursesProvider.isSearchCoursesDisabledInSite();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetch the user courses.
|
||||||
|
*/
|
||||||
|
protected fetchCourses() {
|
||||||
|
return this.coursesProvider.getUserCourses().then((courses) => {
|
||||||
|
|
||||||
|
const courseIds = courses.map((course) => {
|
||||||
|
return course.id;
|
||||||
|
});
|
||||||
|
|
||||||
|
return this.coursesProvider.getCoursesOptions(courseIds).then((options) => {
|
||||||
|
courses.forEach((course) => {
|
||||||
|
course.progress = isNaN(parseInt(course.progress, 10)) ? false : parseInt(course.progress, 10);
|
||||||
|
course.navOptions = options.navOptions[course.id];
|
||||||
|
course.admOptions = options.admOptions[course.id];
|
||||||
|
});
|
||||||
|
this.courses = courses;
|
||||||
|
this.filteredCourses = this.courses;
|
||||||
|
this.filter = '';
|
||||||
|
|
||||||
|
// this.initPrefetchCoursesIcon();
|
||||||
|
});
|
||||||
|
}).catch((error) => {
|
||||||
|
this.domUtils.showErrorModalDefault(error, 'core.courses.errorloadcourses', true);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Refresh the courses.
|
||||||
|
*
|
||||||
|
* @param {any} refresher Refresher.
|
||||||
|
*/
|
||||||
|
refreshCourses(refresher: any) {
|
||||||
|
let promises = [];
|
||||||
|
|
||||||
|
promises.push(this.coursesProvider.invalidateUserCourses());
|
||||||
|
// promises.push($mmCoursesDelegate.clearAndInvalidateCoursesOptions());
|
||||||
|
|
||||||
|
Promise.all(promises).finally(() => {
|
||||||
|
|
||||||
|
this.prefetchIconInitialized = false;
|
||||||
|
this.fetchCourses().finally(() => {
|
||||||
|
refresher.complete();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show or hide the filter.
|
||||||
|
*/
|
||||||
|
switchFilter() {
|
||||||
|
this.filter = '';
|
||||||
|
this.showFilter = !this.showFilter;
|
||||||
|
this.filteredCourses = this.courses;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Go to search courses.
|
||||||
|
*/
|
||||||
|
openSearch() {
|
||||||
|
this.navCtrl.push('CoreCoursesSearchPage');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The filter has changed.
|
||||||
|
*
|
||||||
|
* @param {string} newValue New filter value.
|
||||||
|
*/
|
||||||
|
filterChanged(newValue: string) {
|
||||||
|
if (!newValue || !this.courses) {
|
||||||
|
this.filteredCourses = this.courses;
|
||||||
|
} else {
|
||||||
|
this.filteredCourses = this.courses.filter((course) => {
|
||||||
|
return course.fullname.indexOf(newValue) > -1;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Page destroyed.
|
||||||
|
*/
|
||||||
|
ngOnDestroy() {
|
||||||
|
this.myCoursesObserver && this.myCoursesObserver.off();
|
||||||
|
this.siteUpdatedObserver && this.siteUpdatedObserver.off();
|
||||||
|
}
|
||||||
|
}
|
|
@ -144,7 +144,7 @@ export class CoreCoursesProvider {
|
||||||
* @param {CoreSite} [site] Site. If not defined, use current site.
|
* @param {CoreSite} [site] Site. If not defined, use current site.
|
||||||
* @return {boolean} Whether it's disabled.
|
* @return {boolean} Whether it's disabled.
|
||||||
*/
|
*/
|
||||||
isMyCoursesDisabledInSite(site: CoreSite) : boolean {
|
isMyCoursesDisabledInSite(site?: CoreSite) : boolean {
|
||||||
site = site || this.sitesProvider.getCurrentSite();
|
site = site || this.sitesProvider.getCurrentSite();
|
||||||
return site.isFeatureDisabled('$mmSideMenuDelegate_mmCourses');
|
return site.isFeatureDisabled('$mmSideMenuDelegate_mmCourses');
|
||||||
}
|
}
|
||||||
|
@ -167,7 +167,7 @@ export class CoreCoursesProvider {
|
||||||
* @param {CoreSite} [site] Site. If not defined, use current site.
|
* @param {CoreSite} [site] Site. If not defined, use current site.
|
||||||
* @return {boolean} Whether it's disabled.
|
* @return {boolean} Whether it's disabled.
|
||||||
*/
|
*/
|
||||||
isSearchCoursesDisabledInSite(site: CoreSite) : boolean {
|
isSearchCoursesDisabledInSite(site?: CoreSite) : boolean {
|
||||||
site = site || this.sitesProvider.getCurrentSite();
|
site = site || this.sitesProvider.getCurrentSite();
|
||||||
return site.isFeatureDisabled('$mmCoursesDelegate_search');
|
return site.isFeatureDisabled('$mmCoursesDelegate_search');
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,65 @@
|
||||||
|
// (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 { CoreCoursesProvider } from './courses';
|
||||||
|
import { CoreMainMenuHandler, CoreMainMenuHandlerData } from '../../mainmenu/providers/delegate';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handler to inject an option into main menu.
|
||||||
|
*/
|
||||||
|
@Injectable()
|
||||||
|
export class CoreCoursesMainMenuHandler implements CoreMainMenuHandler {
|
||||||
|
name = 'mmCourses';
|
||||||
|
priority = 1100;
|
||||||
|
|
||||||
|
constructor(private coursesProvider: CoreCoursesProvider) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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> {
|
||||||
|
let myCoursesDisabled = this.coursesProvider.isMyCoursesDisabledInSite();
|
||||||
|
|
||||||
|
// Check if overview side menu is available, so it won't show My courses.
|
||||||
|
// var $mmaMyOverview = $mmAddonManager.get('$mmaMyOverview');
|
||||||
|
// if ($mmaMyOverview) {
|
||||||
|
// return $mmaMyOverview.isSideMenuAvailable().then(function(enabled) {
|
||||||
|
// if (enabled) {
|
||||||
|
// return false;
|
||||||
|
// }
|
||||||
|
// // Addon not enabled, check my courses.
|
||||||
|
// return !myCoursesDisabled;
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
// Addon not present, check my courses.
|
||||||
|
return !myCoursesDisabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the data needed to render the handler.
|
||||||
|
*
|
||||||
|
* @return {CoreMainMenuHandlerData} Data needed to render the handler.
|
||||||
|
*/
|
||||||
|
getDisplayData(): CoreMainMenuHandlerData {
|
||||||
|
return {
|
||||||
|
icon: 'ionic',
|
||||||
|
title: 'core.courses.mycourses',
|
||||||
|
page: 'CoreCoursesMyCoursesPage',
|
||||||
|
class: 'mm-mycourses-handler'
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
|
@ -28,7 +28,7 @@ import { CoreMainMenuDelegate, CoreMainMenuHandlerData } from '../../providers/d
|
||||||
templateUrl: 'menu.html',
|
templateUrl: 'menu.html',
|
||||||
})
|
})
|
||||||
export class CoreMainMenuPage implements OnDestroy {
|
export class CoreMainMenuPage implements OnDestroy {
|
||||||
tabs: CoreMainMenuHandlerData[];
|
tabs: CoreMainMenuHandlerData[] = [];
|
||||||
loaded: boolean;
|
loaded: boolean;
|
||||||
protected subscription;
|
protected subscription;
|
||||||
protected moreTabData = {
|
protected moreTabData = {
|
||||||
|
@ -36,6 +36,7 @@ export class CoreMainMenuPage implements OnDestroy {
|
||||||
title: 'core.more',
|
title: 'core.more',
|
||||||
icon: 'more'
|
icon: 'more'
|
||||||
};
|
};
|
||||||
|
protected moreTabAdded = false;
|
||||||
protected logoutObserver;
|
protected logoutObserver;
|
||||||
|
|
||||||
constructor(private menuDelegate: CoreMainMenuDelegate, private sitesProvider: CoreSitesProvider,
|
constructor(private menuDelegate: CoreMainMenuDelegate, private sitesProvider: CoreSitesProvider,
|
||||||
|
@ -58,7 +59,31 @@ export class CoreMainMenuPage implements OnDestroy {
|
||||||
|
|
||||||
this.subscription = this.menuDelegate.getHandlers().subscribe((handlers) => {
|
this.subscription = this.menuDelegate.getHandlers().subscribe((handlers) => {
|
||||||
this.tabs = handlers.slice(0, CoreMainMenuProvider.NUM_MAIN_HANDLERS); // Get main handlers.
|
this.tabs = handlers.slice(0, CoreMainMenuProvider.NUM_MAIN_HANDLERS); // Get main handlers.
|
||||||
|
|
||||||
|
// Check if handlers are already in tabs. Add the ones that aren't.
|
||||||
|
// @todo: https://github.com/ionic-team/ionic/issues/13633
|
||||||
|
for (let i in handlers) {
|
||||||
|
let handler = handlers[i],
|
||||||
|
found = false;
|
||||||
|
|
||||||
|
for (let j in this.tabs) {
|
||||||
|
let tab = this.tabs[j];
|
||||||
|
if (tab.title == handler.title && tab.icon == handler.icon) {
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!found) {
|
||||||
|
this.tabs.push(handler);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this.moreTabAdded) {
|
||||||
|
this.moreTabAdded = true;
|
||||||
this.tabs.push(this.moreTabData); // Add "More" tab.
|
this.tabs.push(this.moreTabData); // Add "More" tab.
|
||||||
|
}
|
||||||
|
|
||||||
this.loaded = this.menuDelegate.areHandlersLoaded();
|
this.loaded = this.menuDelegate.areHandlersLoaded();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<ion-header>
|
<ion-header>
|
||||||
<ion-navbar>
|
<ion-navbar>
|
||||||
<ion-title>{{ siteInfo.sitename }}</ion-title>
|
<ion-title><core-format-text [text]="siteInfo.sitename"></core-format-text></ion-title>
|
||||||
</ion-navbar>
|
</ion-navbar>
|
||||||
</ion-header>
|
</ion-header>
|
||||||
<ion-content>
|
<ion-content>
|
||||||
|
|
|
@ -177,7 +177,8 @@ export class CoreFormatTextDirective implements OnChanges {
|
||||||
if (expandInFullview) {
|
if (expandInFullview) {
|
||||||
this.element.classList.add('mm-expand-in-fullview');
|
this.element.classList.add('mm-expand-in-fullview');
|
||||||
}
|
}
|
||||||
this.element.classList.add('mm-text-formatted mm-shortened');
|
this.element.classList.add('mm-text-formatted');
|
||||||
|
this.element.classList.add('mm-shortened');
|
||||||
this.element.style.maxHeight = this.maxHeight + 'px';
|
this.element.style.maxHeight = this.maxHeight + 'px';
|
||||||
|
|
||||||
this.element.addEventListener('click', (e) => {
|
this.element.addEventListener('click', (e) => {
|
||||||
|
|
|
@ -726,6 +726,9 @@ export class CoreDomUtilsProvider {
|
||||||
*/
|
*/
|
||||||
showErrorModalDefault(error: any, defaultError: any, needsTranslate?: boolean, autocloseTime?: number) : Alert {
|
showErrorModalDefault(error: any, defaultError: any, needsTranslate?: boolean, autocloseTime?: number) : Alert {
|
||||||
if (error != CoreConstants.dontShowError) {
|
if (error != CoreConstants.dontShowError) {
|
||||||
|
if (error && typeof error != 'string') {
|
||||||
|
error = error.message || error.error;
|
||||||
|
}
|
||||||
error = typeof error == 'string' ? error : defaultError;
|
error = typeof error == 'string' ? error : defaultError;
|
||||||
return this.showErrorModal(error, needsTranslate, autocloseTime);
|
return this.showErrorModal(error, needsTranslate, autocloseTime);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue