MOBILE-2324 course: Use core-tabs in section and render addon components
This commit is contained in:
		
							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) {
 | 
				
			||||||
 | 
				
			|||||||
@ -10,17 +10,27 @@
 | 
				
			|||||||
        </ion-buttons>
 | 
					        </ion-buttons>
 | 
				
			||||||
    </ion-navbar>
 | 
					    </ion-navbar>
 | 
				
			||||||
</ion-header>
 | 
					</ion-header>
 | 
				
			||||||
 | 
					<ion-content>
 | 
				
			||||||
 | 
					    <core-tabs>
 | 
				
			||||||
 | 
					        <!-- Course contents tab. -->
 | 
				
			||||||
 | 
					        <core-tab [title]="'core.course.contents' | translate">
 | 
				
			||||||
 | 
					            <ng-template>
 | 
				
			||||||
                <ion-content>
 | 
					                <ion-content>
 | 
				
			||||||
                    <ion-refresher [enabled]="dataLoaded" (ionRefresh)="doRefresh($event)">
 | 
					                    <ion-refresher [enabled]="dataLoaded" (ionRefresh)="doRefresh($event)">
 | 
				
			||||||
                        <ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}"></ion-refresher-content>
 | 
					                        <ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}"></ion-refresher-content>
 | 
				
			||||||
                    </ion-refresher>
 | 
					                    </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. -->
 | 
					 | 
				
			||||||
        <div class="core-tabs-bar">
 | 
					 | 
				
			||||||
            <a aria-selected="true"  [title]="'core.course.contents' | translate">{{ 'core.course.contents' | translate }}</a>
 | 
					 | 
				
			||||||
            <a *ngFor="let handler of courseHandlers" (click)="handler.data.action(course)" [title]="handler.data.title | translate">{{ handler.data.title | translate }}</a>
 | 
					 | 
				
			||||||
        </div>
 | 
					 | 
				
			||||||
                        <core-course-format [course]="course" [sections]="sections" [initialSectionId]="sectionId" [initialSectionNumber]="sectionNumber" [downloadEnabled]="downloadEnabled" (completionChanged)="onCompletionChange()"></core-course-format>
 | 
					                        <core-course-format [course]="course" [sections]="sections" [initialSectionId]="sectionId" [initialSectionNumber]="sectionNumber" [downloadEnabled]="downloadEnabled" (completionChanged)="onCompletionChange()"></core-course-format>
 | 
				
			||||||
                    </core-loading>
 | 
					                    </core-loading>
 | 
				
			||||||
                </ion-content>
 | 
					                </ion-content>
 | 
				
			||||||
 | 
					            </ng-template>
 | 
				
			||||||
 | 
					        </core-tab>
 | 
				
			||||||
 | 
					        <!-- One tab per handler. -->
 | 
				
			||||||
 | 
					        <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>
 | 
				
			||||||
 | 
				
			|||||||
@ -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 {}
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										25
									
								
								src/core/user/components/participants/participants.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								src/core/user/components/participants/participants.html
									
									
									
									
									
										Normal file
									
								
							@ -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>
 | 
				
			||||||
							
								
								
									
										103
									
								
								src/core/user/components/participants/participants.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										103
									
								
								src/core/user/components/participants/participants.ts
									
									
									
									
									
										Normal file
									
								
							@ -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…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user