MOBILE-2324 course: Use core-tabs in section and render addon components
parent
a856b5c90e
commit
9843da3fb0
|
@ -1,6 +1,5 @@
|
||||||
<ion-split-pane (ionChange)="onSplitPaneChanged($event._visible);" [when]="when">
|
<ion-split-pane (ionChange)="onSplitPaneChanged($event._visible);" [when]="when">
|
||||||
<ion-menu [content]="detailNav" type="push">
|
<ion-menu [content]="detailNav" type="push">
|
||||||
<ion-header><ion-toolbar><ion-title></ion-title></ion-toolbar></ion-header>
|
|
||||||
<ng-content></ng-content>
|
<ng-content></ng-content>
|
||||||
</ion-menu>
|
</ion-menu>
|
||||||
<ion-nav [root]="detailPage" #detailNav main></ion-nav>
|
<ion-nav [root]="detailPage" #detailNav main></ion-nav>
|
||||||
|
|
|
@ -36,10 +36,20 @@ core-tabs {
|
||||||
core-tab {
|
core-tab {
|
||||||
display: none;
|
display: none;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
position: relative;
|
||||||
|
|
||||||
&.selected {
|
&.selected {
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ion-header {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fixed-content, .scroll-content {
|
||||||
|
margin-top: 0 !important;
|
||||||
|
margin-bottom: 0 !important;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -43,7 +43,7 @@ import { Content } from 'ionic-angular';
|
||||||
})
|
})
|
||||||
export class CoreTabsComponent implements OnInit, AfterViewInit, OnChanges {
|
export class CoreTabsComponent implements OnInit, AfterViewInit, OnChanges {
|
||||||
@Input() selectedIndex = 0; // Index of the tab to select.
|
@Input() selectedIndex = 0; // Index of the tab to select.
|
||||||
@Input() hideUntil: boolean; // Determine when should the contents be shown.
|
@Input() hideUntil = true; // Determine when should the contents be shown.
|
||||||
@Output() ionChange: EventEmitter<CoreTabComponent> = new EventEmitter<CoreTabComponent>(); // Emitted when the tab changes.
|
@Output() ionChange: EventEmitter<CoreTabComponent> = new EventEmitter<CoreTabComponent>(); // Emitted when the tab changes.
|
||||||
@ViewChild('originalTabs') originalTabsRef: ElementRef;
|
@ViewChild('originalTabs') originalTabsRef: ElementRef;
|
||||||
@ViewChild('topTabs') topTabs: ElementRef;
|
@ViewChild('topTabs') topTabs: ElementRef;
|
||||||
|
@ -148,7 +148,7 @@ export class CoreTabsComponent implements OnInit, AfterViewInit, OnChanges {
|
||||||
let selectedIndex = this.selectedIndex || 0,
|
let selectedIndex = this.selectedIndex || 0,
|
||||||
selectedTab = this.tabs[selectedIndex];
|
selectedTab = this.tabs[selectedIndex];
|
||||||
|
|
||||||
if (!selectedTab.enabled || !selectedTab.show) {
|
if (!selectedTab || !selectedTab.enabled || !selectedTab.show) {
|
||||||
// The tab is not enabled or not shown. Get the first tab that is enabled.
|
// The tab is not enabled or not shown. Get the first tab that is enabled.
|
||||||
selectedTab = this.tabs.find((tab, index) => {
|
selectedTab = this.tabs.find((tab, index) => {
|
||||||
if (tab.enabled && tab.show) {
|
if (tab.enabled && tab.show) {
|
||||||
|
|
|
@ -11,16 +11,26 @@
|
||||||
</ion-navbar>
|
</ion-navbar>
|
||||||
</ion-header>
|
</ion-header>
|
||||||
<ion-content>
|
<ion-content>
|
||||||
<ion-refresher [enabled]="dataLoaded" (ionRefresh)="doRefresh($event)">
|
<core-tabs>
|
||||||
<ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}"></ion-refresher-content>
|
<!-- Course contents tab. -->
|
||||||
</ion-refresher>
|
<core-tab [title]="'core.course.contents' | translate">
|
||||||
|
<ng-template>
|
||||||
|
<ion-content>
|
||||||
|
<ion-refresher [enabled]="dataLoaded" (ionRefresh)="doRefresh($event)">
|
||||||
|
<ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}"></ion-refresher-content>
|
||||||
|
</ion-refresher>
|
||||||
|
|
||||||
<core-loading [hideUntil]="dataLoaded">
|
<core-loading [hideUntil]="dataLoaded">
|
||||||
<!-- @todo: Use core-tabs or a new component. core-tabs might initialize all tabs at start, so we might require a new component. -->
|
<core-course-format [course]="course" [sections]="sections" [initialSectionId]="sectionId" [initialSectionNumber]="sectionNumber" [downloadEnabled]="downloadEnabled" (completionChanged)="onCompletionChange()"></core-course-format>
|
||||||
<div class="core-tabs-bar">
|
</core-loading>
|
||||||
<a aria-selected="true" [title]="'core.course.contents' | translate">{{ 'core.course.contents' | translate }}</a>
|
</ion-content>
|
||||||
<a *ngFor="let handler of courseHandlers" (click)="handler.data.action(course)" [title]="handler.data.title | translate">{{ handler.data.title | translate }}</a>
|
</ng-template>
|
||||||
</div>
|
</core-tab>
|
||||||
<core-course-format [course]="course" [sections]="sections" [initialSectionId]="sectionId" [initialSectionNumber]="sectionNumber" [downloadEnabled]="downloadEnabled" (completionChanged)="onCompletionChange()"></core-course-format>
|
<!-- One tab per handler. -->
|
||||||
</core-loading>
|
<core-tab *ngFor="let handler of courseHandlers" [title]="handler.data.title | translate" class="{{handler.data.class}}">
|
||||||
|
<ng-template>
|
||||||
|
<core-dynamic-component [component]="handler.data.component" [data]="handlerData"></core-dynamic-component>
|
||||||
|
</ng-template>
|
||||||
|
</core-tab>
|
||||||
|
</core-tabs>
|
||||||
</ion-content>
|
</ion-content>
|
||||||
|
|
|
@ -43,6 +43,7 @@ export class CoreCourseSectionPage implements OnDestroy {
|
||||||
sectionId: number;
|
sectionId: number;
|
||||||
sectionNumber: number;
|
sectionNumber: number;
|
||||||
courseHandlers: CoreCourseOptionsHandlerToDisplay[];
|
courseHandlers: CoreCourseOptionsHandlerToDisplay[];
|
||||||
|
handlerData: any = {}; // Data to send to the handlers components.
|
||||||
dataLoaded: boolean;
|
dataLoaded: boolean;
|
||||||
downloadEnabled: boolean;
|
downloadEnabled: boolean;
|
||||||
downloadEnabledIcon = 'square-outline'; // Disabled by default.
|
downloadEnabledIcon = 'square-outline'; // Disabled by default.
|
||||||
|
@ -63,6 +64,7 @@ export class CoreCourseSectionPage implements OnDestroy {
|
||||||
this.course = navParams.get('course');
|
this.course = navParams.get('course');
|
||||||
this.sectionId = navParams.get('sectionId');
|
this.sectionId = navParams.get('sectionId');
|
||||||
this.sectionNumber = navParams.get('sectionNumber');
|
this.sectionNumber = navParams.get('sectionNumber');
|
||||||
|
this.handlerData.courseId = this.course.id;
|
||||||
|
|
||||||
// Get the title to display. We dont't have sections yet.
|
// Get the title to display. We dont't have sections yet.
|
||||||
this.title = courseFormatDelegate.getCourseTitle(this.course);
|
this.title = courseFormatDelegate.getCourseTitle(this.course);
|
||||||
|
|
|
@ -91,12 +91,6 @@ export interface CoreCourseOptionsHandlerData {
|
||||||
*/
|
*/
|
||||||
title: string;
|
title: string;
|
||||||
|
|
||||||
/**
|
|
||||||
* Name of the icon to display for the handler.
|
|
||||||
* @type {string}
|
|
||||||
*/
|
|
||||||
icon: string;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class to add to the displayed handler.
|
* Class to add to the displayed handler.
|
||||||
* @type {string}
|
* @type {string}
|
||||||
|
@ -104,11 +98,10 @@ export interface CoreCourseOptionsHandlerData {
|
||||||
class?: string;
|
class?: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Action to perform when the handler is clicked.
|
* The component to render the handler. It must be the component class, not the name or an instance.
|
||||||
*
|
* When the component is created, it will receive the courseId as input.
|
||||||
* @param {any} course The course.
|
|
||||||
*/
|
*/
|
||||||
action(course: any): void;
|
component: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -16,23 +16,33 @@ import { NgModule } from '@angular/core';
|
||||||
import { CommonModule } from '@angular/common';
|
import { CommonModule } from '@angular/common';
|
||||||
import { IonicModule } from 'ionic-angular';
|
import { IonicModule } from 'ionic-angular';
|
||||||
import { TranslateModule } from '@ngx-translate/core';
|
import { TranslateModule } from '@ngx-translate/core';
|
||||||
|
import { CoreUserParticipantsComponent } from './participants/participants';
|
||||||
import { CoreUserProfileFieldComponent } from './user-profile-field/user-profile-field';
|
import { CoreUserProfileFieldComponent } from './user-profile-field/user-profile-field';
|
||||||
import { CoreComponentsModule } from '../../../components/components.module';
|
import { CoreComponentsModule } from '../../../components/components.module';
|
||||||
|
import { CoreDirectivesModule } from '../../../directives/directives.module';
|
||||||
|
import { CorePipesModule } from '../../../pipes/pipes.module';
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
declarations: [
|
declarations: [
|
||||||
|
CoreUserParticipantsComponent,
|
||||||
CoreUserProfileFieldComponent
|
CoreUserProfileFieldComponent
|
||||||
],
|
],
|
||||||
imports: [
|
imports: [
|
||||||
CommonModule,
|
CommonModule,
|
||||||
IonicModule,
|
IonicModule,
|
||||||
TranslateModule.forChild(),
|
TranslateModule.forChild(),
|
||||||
CoreComponentsModule
|
CoreComponentsModule,
|
||||||
|
CoreDirectivesModule,
|
||||||
|
CorePipesModule
|
||||||
],
|
],
|
||||||
providers: [
|
providers: [
|
||||||
],
|
],
|
||||||
exports: [
|
exports: [
|
||||||
|
CoreUserParticipantsComponent,
|
||||||
CoreUserProfileFieldComponent
|
CoreUserProfileFieldComponent
|
||||||
|
],
|
||||||
|
entryComponents: [
|
||||||
|
CoreUserParticipantsComponent
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
export class CoreUserComponentsModule {}
|
export class CoreUserComponentsModule {}
|
||||||
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
<core-split-view>
|
||||||
|
<ion-content>
|
||||||
|
<ion-refresher [enabled]="participantsLoaded" (ionRefresh)="refreshParticipants($event)">
|
||||||
|
<ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}"></ion-refresher-content>
|
||||||
|
</ion-refresher>
|
||||||
|
<core-loading [hideUntil]="participantsLoaded">
|
||||||
|
<core-empty-box *ngIf="participants && participants.length == 0" icon="person" [message]="'core.user.noparticipants' | translate">
|
||||||
|
</core-empty-box>
|
||||||
|
|
||||||
|
<ion-list *ngIf="participants && participants.length > 0">
|
||||||
|
<a ion-item text-wrap *ngFor="let participant of participants" [title]="participant.fullname" (click)="gotoParticipant(participant.id)" [class.core-split-item-selected]="participant.id == participantId">
|
||||||
|
<ion-avatar item-start>
|
||||||
|
<img src="{{participant.profileimageurl}}" [alt]="'core.pictureof' | translate:{$a: participant.fullname}" core-external-content>
|
||||||
|
</ion-avatar>
|
||||||
|
<h2><core-format-text [text]="participant.fullname"></core-format-text></h2>
|
||||||
|
<p *ngIf="participant.lastaccess"><strong>{{ 'core.lastaccess' | translate }}: </strong>{{ participant.lastaccess * 1000 | coreFormatDate:"dfmediumdate"}}</p>
|
||||||
|
</a>
|
||||||
|
</ion-list>
|
||||||
|
|
||||||
|
<ion-infinite-scroll [enabled]="canLoadMore" (ionInfinite)="$event.waitFor(fetchData())">
|
||||||
|
<ion-infinite-scroll-content></ion-infinite-scroll-content>
|
||||||
|
</ion-infinite-scroll>
|
||||||
|
</core-loading>
|
||||||
|
</ion-content>
|
||||||
|
</core-split-view>
|
|
@ -0,0 +1,103 @@
|
||||||
|
// (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, OnInit } from '@angular/core';
|
||||||
|
import { Content, NavParams } from 'ionic-angular';
|
||||||
|
import { CoreUserProvider } from '../../providers/user';
|
||||||
|
import { CoreDomUtilsProvider } from '../../../../providers/utils/dom';
|
||||||
|
import { CoreSplitViewComponent } from '../../../../components/split-view/split-view';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Component that displays the list of course participants.
|
||||||
|
*/
|
||||||
|
@Component({
|
||||||
|
selector: 'core-user-participants',
|
||||||
|
templateUrl: 'participants.html',
|
||||||
|
})
|
||||||
|
export class CoreUserParticipantsComponent implements OnInit {
|
||||||
|
@ViewChild(Content) content: Content;
|
||||||
|
@ViewChild(CoreSplitViewComponent) splitviewCtrl: CoreSplitViewComponent;
|
||||||
|
|
||||||
|
@Input() courseId: number;
|
||||||
|
|
||||||
|
participantId: number;
|
||||||
|
participants = [];
|
||||||
|
canLoadMore = false;
|
||||||
|
participantsLoaded = false;
|
||||||
|
|
||||||
|
constructor(private userProvider: CoreUserProvider, private domUtils: CoreDomUtilsProvider) { }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* View loaded.
|
||||||
|
*/
|
||||||
|
ngOnInit(): void {
|
||||||
|
// Get first participants.
|
||||||
|
this.fetchData(true).then(() => {
|
||||||
|
if (!this.participantId && this.splitviewCtrl.isOn() && this.participants.length > 0) {
|
||||||
|
// Take first and load it.
|
||||||
|
this.gotoParticipant(this.participants[0].id);
|
||||||
|
}
|
||||||
|
// Add log in Moodle.
|
||||||
|
this.userProvider.logView(this.courseId).catch(() => {
|
||||||
|
// Ignore errors.
|
||||||
|
});
|
||||||
|
}).finally(() => {
|
||||||
|
this.participantsLoaded = true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetch all the data required for the view.
|
||||||
|
*
|
||||||
|
* @param {boolean} [refresh] Empty events array first.
|
||||||
|
* @return {Promise<any>} Resolved when done.
|
||||||
|
*/
|
||||||
|
fetchData(refresh: boolean = false): Promise<any> {
|
||||||
|
const firstToGet = refresh ? 0 : this.participants.length;
|
||||||
|
|
||||||
|
return this.userProvider.getParticipants(this.courseId, firstToGet).then((data) => {
|
||||||
|
if (refresh) {
|
||||||
|
this.participants = data.participants;
|
||||||
|
} else {
|
||||||
|
this.participants = this.participants.concat(data.participants);
|
||||||
|
}
|
||||||
|
this.canLoadMore = data.canLoadMore;
|
||||||
|
}).catch((error) => {
|
||||||
|
this.domUtils.showErrorModalDefault(error, 'Error loading participants');
|
||||||
|
this.canLoadMore = false; // Set to false to prevent infinite calls with infinite-loading.
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Refresh data.
|
||||||
|
*
|
||||||
|
* @param {any} refresher Refresher.
|
||||||
|
*/
|
||||||
|
refreshParticipants(refresher: any): void {
|
||||||
|
this.userProvider.invalidateParticipantsList(this.courseId).finally(() => {
|
||||||
|
this.fetchData(true).finally(() => {
|
||||||
|
refresher.complete();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Navigate to a particular user profile.
|
||||||
|
* @param {number} userId User Id where to navigate.
|
||||||
|
*/
|
||||||
|
gotoParticipant(userId: number): void {
|
||||||
|
this.participantId = userId;
|
||||||
|
this.splitviewCtrl.push('CoreUserProfilePage', {userId: userId, courseId: this.courseId});
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,28 +3,4 @@
|
||||||
<ion-title>{{ 'core.user.participants' | translate }}</ion-title>
|
<ion-title>{{ 'core.user.participants' | translate }}</ion-title>
|
||||||
</ion-navbar>
|
</ion-navbar>
|
||||||
</ion-header>
|
</ion-header>
|
||||||
<core-split-view>
|
<core-user-participants [courseId]="courseId"></core-user-participants>
|
||||||
<ion-content>
|
|
||||||
<ion-refresher [enabled]="participantsLoaded" (ionRefresh)="refreshParticipants($event)">
|
|
||||||
<ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}"></ion-refresher-content>
|
|
||||||
</ion-refresher>
|
|
||||||
<core-loading [hideUntil]="participantsLoaded">
|
|
||||||
<core-empty-box *ngIf="participants && participants.length == 0" icon="person" [message]="'core.user.noparticipants' | translate">
|
|
||||||
</core-empty-box>
|
|
||||||
|
|
||||||
<ion-list *ngIf="participants && participants.length > 0">
|
|
||||||
<a ion-item text-wrap *ngFor="let participant of participants" [title]="participant.fullname" (click)="gotoParticipant(participant.id)" [class.core-split-item-selected]="participant.id == participantId">
|
|
||||||
<ion-avatar item-start>
|
|
||||||
<img src="{{participant.profileimageurl}}" [alt]="'core.pictureof' | translate:{$a: participant.fullname}" core-external-content>
|
|
||||||
</ion-avatar>
|
|
||||||
<h2><core-format-text [text]="participant.fullname"></core-format-text></h2>
|
|
||||||
<p *ngIf="participant.lastaccess"><strong>{{ 'core.lastaccess' | translate }}: </strong>{{ participant.lastaccess * 1000 | coreFormatDate:"dfmediumdate"}}</p>
|
|
||||||
</a>
|
|
||||||
</ion-list>
|
|
||||||
|
|
||||||
<ion-infinite-scroll [enabled]="canLoadMore" (ionInfinite)="$event.waitFor(fetchData())">
|
|
||||||
<ion-infinite-scroll-content></ion-infinite-scroll-content>
|
|
||||||
</ion-infinite-scroll>
|
|
||||||
</core-loading>
|
|
||||||
</ion-content>
|
|
||||||
</core-split-view>
|
|
|
@ -15,9 +15,7 @@
|
||||||
import { NgModule } from '@angular/core';
|
import { NgModule } from '@angular/core';
|
||||||
import { IonicPageModule } from 'ionic-angular';
|
import { IonicPageModule } from 'ionic-angular';
|
||||||
import { TranslateModule } from '@ngx-translate/core';
|
import { TranslateModule } from '@ngx-translate/core';
|
||||||
import { CoreComponentsModule } from '../../../../components/components.module';
|
import { CoreUserComponentsModule } from '../../components/components.module';
|
||||||
import { CoreDirectivesModule } from '../../../../directives/directives.module';
|
|
||||||
import { CorePipesModule } from '../../../../pipes/pipes.module';
|
|
||||||
import { CoreUserParticipantsPage } from './participants';
|
import { CoreUserParticipantsPage } from './participants';
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
|
@ -25,9 +23,7 @@ import { CoreUserParticipantsPage } from './participants';
|
||||||
CoreUserParticipantsPage,
|
CoreUserParticipantsPage,
|
||||||
],
|
],
|
||||||
imports: [
|
imports: [
|
||||||
CoreComponentsModule,
|
CoreUserComponentsModule,
|
||||||
CoreDirectivesModule,
|
|
||||||
CorePipesModule,
|
|
||||||
IonicPageModule.forChild(CoreUserParticipantsPage),
|
IonicPageModule.forChild(CoreUserParticipantsPage),
|
||||||
TranslateModule.forChild()
|
TranslateModule.forChild()
|
||||||
],
|
],
|
||||||
|
|
|
@ -12,11 +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 } from '@angular/core';
|
import { Component } from '@angular/core';
|
||||||
import { IonicPage, Content, NavParams } from 'ionic-angular';
|
import { IonicPage, NavParams } from 'ionic-angular';
|
||||||
import { CoreUserProvider } from '../../providers/user';
|
|
||||||
import { CoreDomUtilsProvider } from '../../../../providers/utils/dom';
|
|
||||||
import { CoreSplitViewComponent } from '../../../../components/split-view/split-view';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Page that displays the list of course participants.
|
* Page that displays the list of course participants.
|
||||||
|
@ -27,78 +24,9 @@ import { CoreSplitViewComponent } from '../../../../components/split-view/split-
|
||||||
templateUrl: 'participants.html',
|
templateUrl: 'participants.html',
|
||||||
})
|
})
|
||||||
export class CoreUserParticipantsPage {
|
export class CoreUserParticipantsPage {
|
||||||
@ViewChild(Content) content: Content;
|
|
||||||
@ViewChild(CoreSplitViewComponent) splitviewCtrl: CoreSplitViewComponent;
|
|
||||||
|
|
||||||
courseId: number;
|
courseId: number;
|
||||||
participantId: number;
|
|
||||||
participants = [];
|
|
||||||
canLoadMore = false;
|
|
||||||
participantsLoaded = false;
|
|
||||||
|
|
||||||
constructor(private userProvider: CoreUserProvider, private domUtils: CoreDomUtilsProvider,
|
constructor(navParams: NavParams) {
|
||||||
navParams: NavParams) {
|
|
||||||
this.courseId = navParams.get('courseId');
|
this.courseId = navParams.get('courseId');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* View loaded.
|
|
||||||
*/
|
|
||||||
ionViewDidLoad(): void {
|
|
||||||
// Get first participants.
|
|
||||||
this.fetchData(true).then(() => {
|
|
||||||
if (!this.participantId && this.splitviewCtrl.isOn() && this.participants.length > 0) {
|
|
||||||
// Take first and load it.
|
|
||||||
this.gotoParticipant(this.participants[0].id);
|
|
||||||
}
|
|
||||||
// Add log in Moodle.
|
|
||||||
this.userProvider.logView(this.courseId);
|
|
||||||
}).finally(() => {
|
|
||||||
this.participantsLoaded = true;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Fetch all the data required for the view.
|
|
||||||
*
|
|
||||||
* @param {boolean} [refresh] Empty events array first.
|
|
||||||
* @return {Promise<any>} Resolved when done.
|
|
||||||
*/
|
|
||||||
fetchData(refresh: boolean = false): Promise<any> {
|
|
||||||
const firstToGet = refresh ? 0 : this.participants.length;
|
|
||||||
|
|
||||||
return this.userProvider.getParticipants(this.courseId, firstToGet).then((data) => {
|
|
||||||
if (refresh) {
|
|
||||||
this.participants = data.participants;
|
|
||||||
} else {
|
|
||||||
this.participants = this.participants.concat(data.participants);
|
|
||||||
}
|
|
||||||
this.canLoadMore = data.canLoadMore;
|
|
||||||
}).catch((error) => {
|
|
||||||
this.domUtils.showErrorModalDefault(error, 'Error loading participants');
|
|
||||||
this.canLoadMore = false; // Set to false to prevent infinite calls with infinite-loading.
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Refresh data.
|
|
||||||
*
|
|
||||||
* @param {any} refresher Refresher.
|
|
||||||
*/
|
|
||||||
refreshParticipants(refresher: any): void {
|
|
||||||
this.userProvider.invalidateParticipantsList(this.courseId).finally(() => {
|
|
||||||
this.fetchData(true).finally(() => {
|
|
||||||
refresher.complete();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Navigate to a particular user profile.
|
|
||||||
* @param {number} userId User Id where to navigate.
|
|
||||||
*/
|
|
||||||
gotoParticipant(userId: number): void {
|
|
||||||
this.participantId = userId;
|
|
||||||
this.splitviewCtrl.push('CoreUserProfilePage', {userId: userId, courseId: this.courseId});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,7 @@ import { CoreCourseOptionsHandler, CoreCourseOptionsHandlerData } from '../../co
|
||||||
import { CoreCourseProvider } from '../../course/providers/course';
|
import { CoreCourseProvider } from '../../course/providers/course';
|
||||||
import { CoreUserProvider } from './user';
|
import { CoreUserProvider } from './user';
|
||||||
import { CoreLoginHelperProvider } from '../../login/providers/helper';
|
import { CoreLoginHelperProvider } from '../../login/providers/helper';
|
||||||
|
import { CoreUserParticipantsComponent } from '../components/participants/participants';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Course nav handler.
|
* Course nav handler.
|
||||||
|
@ -102,16 +103,9 @@ export class CoreUserParticipantsCourseOptionHandler implements CoreCourseOption
|
||||||
*/
|
*/
|
||||||
getDisplayData(): CoreCourseOptionsHandlerData {
|
getDisplayData(): CoreCourseOptionsHandlerData {
|
||||||
return {
|
return {
|
||||||
icon: 'person',
|
|
||||||
title: 'core.user.participants',
|
title: 'core.user.participants',
|
||||||
class: 'core-user-participants-handler',
|
class: 'core-user-participants-handler',
|
||||||
action: (course: any): void => {
|
component: CoreUserParticipantsComponent
|
||||||
const pageParams = {
|
|
||||||
courseId: course.id
|
|
||||||
};
|
|
||||||
// Always use redirect to make it the new history root (to avoid "loops" in history).
|
|
||||||
this.loginHelper.redirect('CoreUserParticipantsPage', pageParams);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,11 +25,13 @@ import { CoreUserProfileLinkHandler } from './providers/user-link-handler';
|
||||||
import { CoreUserParticipantsCourseOptionHandler } from './providers/course-option-handler';
|
import { CoreUserParticipantsCourseOptionHandler } from './providers/course-option-handler';
|
||||||
import { CoreUserParticipantsLinkHandler } from './providers/participants-link-handler';
|
import { CoreUserParticipantsLinkHandler } from './providers/participants-link-handler';
|
||||||
import { CoreCourseOptionsDelegate } from '../course/providers/options-delegate';
|
import { CoreCourseOptionsDelegate } from '../course/providers/options-delegate';
|
||||||
|
import { CoreUserComponentsModule } from './components/components.module';
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
declarations: [
|
declarations: [
|
||||||
],
|
],
|
||||||
imports: [
|
imports: [
|
||||||
|
CoreUserComponentsModule
|
||||||
],
|
],
|
||||||
providers: [
|
providers: [
|
||||||
CoreUserDelegate,
|
CoreUserDelegate,
|
||||||
|
|
Loading…
Reference in New Issue