MOBILE-3095 core: Make easier to support label site plugins

main
Dani Palou 2019-10-25 14:23:03 +02:00
parent ec2a93adc1
commit 82eded5e5f
11 changed files with 113 additions and 30 deletions

View File

@ -69,7 +69,7 @@ export class AddonBlockMyOverviewComponent extends CoreBlockBaseComponent implem
future: 'show',
favourite: 'show',
hidden: 'show',
custom: 'hidden', // True or false to show or hide.
custom: 'hidden',
};
showFilter = false;
showSelectorFilter = false;

View File

@ -82,7 +82,7 @@ export class AddonBlockSiteMainMenuComponent extends CoreBlockBaseComponent impl
if (this.mainMenuBlock) {
this.mainMenuBlock.hasContent = this.courseHelper.sectionHasContent(this.mainMenuBlock);
this.courseHelper.addHandlerDataForModules([this.mainMenuBlock], this.siteHomeId);
this.courseHelper.addHandlerDataForModules([this.mainMenuBlock], this.siteHomeId, undefined, undefined, true);
// Check if Site Home displays announcements. If so, remove it from the main menu block.
const currentSite = this.sitesProvider.getCurrentSite(),

View File

@ -1,4 +1,4 @@
<ion-item *ngIf="module && module.visibleoncoursepage !== 0" text-wrap id="core-course-module-{{module.id}}" class="core-course-module-handler {{module.handlerData.class}}" (click)="moduleClicked($event)" [ngClass]="{'item-media': module.handlerData.icon, 'core-not-clickable': !module.handlerData.action || module.uservisible === false, 'item-dimmed': module.visible === 0 || module.uservisible === false}" [title]="module.handlerData.a11yTitle" detail-none>
<ion-item *ngIf="module && module.visibleoncoursepage !== 0 && !module.handlerData.loading" text-wrap id="core-course-module-{{module.id}}" class="core-course-module-handler {{module.handlerData.class}}" (click)="moduleClicked($event)" [ngClass]="{'item-media': module.handlerData.icon, 'core-not-clickable': !module.handlerData.action || module.uservisible === false, 'item-dimmed': module.visible === 0 || module.uservisible === false}" [title]="module.handlerData.a11yTitle" detail-none>
<img item-start *ngIf="module.handlerData.icon" [src]="module.handlerData.icon" [alt]="module.modnametranslated" class="core-module-icon">
<div class="core-module-title">
@ -32,4 +32,9 @@
<ion-badge item-end *ngIf="module.completiondata && module.completiondata.offline" color="warning" text-wrap>{{ 'core.course.manualcompletionnotsynced' | translate }}</ion-badge>
</div>
<core-format-text class="core-module-description" *ngIf="module.description" maxHeight="80" [text]="module.description" contextLevel="module" [contextInstanceId]="module.id" [courseId]="courseId"></core-format-text>
</ion-item>
</ion-item>
<!-- Loading. -->
<ion-item *ngIf="module && module.visibleoncoursepage !== 0 && module.handlerData.loading" role="status" text-wrap id="core-course-module-{{module.id}}" [ngClass]="['core-course-module-handler', 'core-module-loading', module.handlerData.class]" [title]="module.handlerData.a11yTitle" detail-none>
<ion-spinner></ion-spinner>
</ion-item>

View File

@ -87,6 +87,16 @@ ion-app.app-root core-course-module {
}
}
.core-module-loading {
width: 100%;
text-align: center;
padding-top: 10px;
clear: both;
@include darkmode() {
color: $core-dark-text-color;
}
}
@include darkmode() {
.item.core-course-module-handler {
background: $core-dark-item-bg-color;

View File

@ -259,7 +259,8 @@ export class CoreCourseSectionPage implements OnDestroy {
}
return promise.then((completionStatus) => {
this.courseHelper.addHandlerDataForModules(sections, this.course.id, completionStatus, this.course.fullname);
this.courseHelper.addHandlerDataForModules(sections, this.course.id, completionStatus, this.course.fullname,
true);
// Format the name of each section and check if it has content.
this.sections = sections.map((section) => {

View File

@ -143,9 +143,12 @@ export class CoreCourseHelperProvider {
* @param courseId Course ID of the modules.
* @param completionStatus List of completion status.
* @param courseName Course name. Recommended if completionStatus is supplied.
* @param forCoursePage Whether the data will be used to render the course page.
* @return Whether the sections have content.
*/
addHandlerDataForModules(sections: any[], courseId: number, completionStatus?: any, courseName?: string): boolean {
addHandlerDataForModules(sections: any[], courseId: number, completionStatus?: any, courseName?: string,
forCoursePage?: boolean): boolean {
let hasContent = false;
sections.forEach((section) => {
@ -156,7 +159,8 @@ export class CoreCourseHelperProvider {
hasContent = true;
section.modules.forEach((module) => {
module.handlerData = this.moduleDelegate.getModuleDataFor(module.modname, module, courseId, section.id);
module.handlerData = this.moduleDelegate.getModuleDataFor(module.modname, module, courseId, section.id,
forCoursePage);
if (module.completiondata && module.completion > 0) {
module.completiondata.courseId = courseId;
@ -1197,7 +1201,7 @@ export class CoreCourseHelperProvider {
// Get the module.
return this.courseProvider.getModule(moduleId, courseId, sectionId, false, false, siteId, modName);
}).then((module) => {
module.handlerData = this.moduleDelegate.getModuleDataFor(module.modname, module, courseId, sectionId);
module.handlerData = this.moduleDelegate.getModuleDataFor(module.modname, module, courseId, sectionId, false);
if (navCtrl && module.handlerData && module.handlerData.action) {
// If the link handler for this module passed through navCtrl, we can use the module's handler to navigate cleanly.
@ -1246,7 +1250,7 @@ export class CoreCourseHelperProvider {
*/
openModule(navCtrl: NavController, module: any, courseId: number, sectionId?: number, modParams?: any): boolean {
if (!module.handlerData) {
module.handlerData = this.moduleDelegate.getModuleDataFor(module.modname, module, courseId, sectionId);
module.handlerData = this.moduleDelegate.getModuleDataFor(module.modname, module, courseId, sectionId, false);
}
if (module.handlerData && module.handlerData.action) {

View File

@ -45,9 +45,10 @@ export interface CoreCourseModuleHandler extends CoreDelegateHandler {
* @param module The module object.
* @param courseId The course ID.
* @param sectionId The section ID.
* @param forCoursePage Whether the data will be used to render the course page.
* @return Data to render the module.
*/
getData(module: any, courseId: number, sectionId: number): CoreCourseModuleHandlerData;
getData(module: any, courseId: number, sectionId: number, forCoursePage: boolean): CoreCourseModuleHandlerData;
/**
* Get the component to render the module. This is needed to support singleactivity course format.
@ -133,10 +134,15 @@ export interface CoreCourseModuleHandlerData {
buttons?: CoreCourseModuleHandlerButton[];
/**
* Whether to display a spinner in the module item.
* Whether to display a spinner where the download button is displayed. The module icon, title, etc. will be displayed.
*/
spinner?: boolean;
/**
* Whether the data is being loaded. If true, it will display a spinner in the whole module, nothing else will be shown.
*/
loading?: boolean;
/**
* Action to perform when the module is clicked.
*
@ -251,10 +257,12 @@ export class CoreCourseModuleDelegate extends CoreDelegate {
* @param module The module object.
* @param courseId The course ID.
* @param sectionId The section ID.
* @param forCoursePage Whether the data will be used to render the course page.
* @return Data to render the module.
*/
getModuleDataFor(modname: string, module: any, courseId: number, sectionId: number): CoreCourseModuleHandlerData {
return this.executeFunctionOnEnabled(modname, 'getData', [module, courseId, sectionId]);
getModuleDataFor(modname: string, module: any, courseId: number, sectionId: number, forCoursePage?: boolean)
: CoreCourseModuleHandlerData {
return this.executeFunctionOnEnabled(modname, 'getData', [module, courseId, sectionId, forCoursePage]);
}
/**

View File

@ -134,7 +134,8 @@ export class CoreSiteHomeIndexComponent implements OnInit {
this.section = config.numsections ? sections.find((section) => section.section == 1) : false;
if (this.section) {
this.section.hasContent = this.courseHelper.sectionHasContent(this.section);
this.hasContent = this.courseHelper.addHandlerDataForModules([this.section], this.siteHomeId) || this.hasContent;
this.hasContent = this.courseHelper.addHandlerDataForModules([this.section], this.siteHomeId, undefined,
undefined, true) || this.hasContent;
}
// Add log in Moodle.

View File

@ -53,7 +53,7 @@ export class CoreSiteHomeNewsComponent implements OnInit {
return this.courseProvider.getModuleBasicInfo(forum.cmid).then((module) => {
this.show = true;
this.module = module;
module.handlerData = this.moduleDelegate.getModuleDataFor(module.modname, module, siteHomeId, module.section);
module.handlerData = this.moduleDelegate.getModuleDataFor(module.modname, module, siteHomeId, module.section, true);
});
}).catch(() => {
// Ignore errors.

View File

@ -14,9 +14,11 @@
import { Injector } from '@angular/core';
import { NavController, NavOptions } from 'ionic-angular';
import { CoreLoggerProvider } from '@providers/logger';
import { CoreCourseModuleHandler, CoreCourseModuleHandlerData } from '@core/course/providers/module-delegate';
import { CoreSitePluginsBaseHandler } from './base-handler';
import { CoreSitePluginsModuleIndexComponent } from '../../components/module-index/module-index';
import { CoreSitePluginsProvider } from '../../providers/siteplugins';
/**
* Handler to support a module using a site plugin.
@ -26,9 +28,18 @@ export class CoreSitePluginsModuleHandler extends CoreSitePluginsBaseHandler imp
supportedFeatures: {[name: string]: any};
supportsFeature: (feature: string) => any;
constructor(name: string, public modName: string, protected handlerSchema: any, protected initResult: any) {
protected logger: any;
constructor(name: string,
public modName: string,
protected plugin: any,
protected handlerSchema: any,
protected initResult: any,
protected sitePluginsProvider: CoreSitePluginsProvider,
loggerProvider: CoreLoggerProvider) {
super(name);
this.logger = loggerProvider.getInstance('CoreSitePluginsModuleHandler');
this.supportedFeatures = handlerSchema.supportedfeatures;
if (initResult && initResult.jsResult && initResult.jsResult.supportsFeature) {
@ -43,18 +54,38 @@ export class CoreSitePluginsModuleHandler extends CoreSitePluginsBaseHandler imp
* @param module The module object.
* @param courseId The course ID.
* @param sectionId The section ID.
* @param forCoursePage Whether the data will be used to render the course page.
* @return Data to render the module.
*/
getData(module: any, courseId: number, sectionId: number): CoreCourseModuleHandlerData {
const hasOffline = !!(this.handlerSchema.offlinefunctions && Object.keys(this.handlerSchema.offlinefunctions).length),
showDowloadButton = this.handlerSchema.downloadbutton;
getData(module: any, courseId: number, sectionId: number, forCoursePage: boolean): CoreCourseModuleHandlerData {
const callMethod = forCoursePage && this.handlerSchema.coursepagemethod;
return {
title: module.name,
icon: this.handlerSchema.displaydata.icon,
class: this.handlerSchema.displaydata.class,
showDownloadButton: typeof showDowloadButton != 'undefined' ? showDowloadButton : hasOffline,
action: (event: Event, navCtrl: NavController, module: any, courseId: number, options: NavOptions): void => {
if (module.noviewlink && !callMethod) {
// The module doesn't link to a new page (similar to label). Only display the description.
const title = module.description;
module.description = '';
return {
icon: this.handlerSchema.displaydata.icon,
title: title,
a11yTitle: '',
class: this.handlerSchema.displaydata.class
};
}
const hasOffline = !!(this.handlerSchema.offlinefunctions && Object.keys(this.handlerSchema.offlinefunctions).length),
showDowloadButton = this.handlerSchema.downloadbutton,
handlerData: CoreCourseModuleHandlerData = {
title: module.name,
icon: this.handlerSchema.displaydata.icon,
class: this.handlerSchema.displaydata.class,
showDownloadButton: typeof showDowloadButton != 'undefined' ? showDowloadButton : hasOffline,
};
if (this.handlerSchema.method) {
// There is a method, add an action.
handlerData.action = (event: Event, navCtrl: NavController, module: any, courseId: number, options: NavOptions)
: void => {
event.preventDefault();
event.stopPropagation();
@ -63,8 +94,30 @@ export class CoreSitePluginsModuleHandler extends CoreSitePluginsBaseHandler imp
module: module,
courseId: courseId
}, options);
}
};
};
}
if (callMethod && module.visibleoncoursepage !== 0) {
// Call the method to get the course page template.
handlerData.loading = true;
const args = {
courseid: courseId,
cmid: module.id
};
this.sitePluginsProvider.getContent(this.plugin.component, this.handlerSchema.coursepagemethod, args).then((result) => {
// Use the html returned.
handlerData.title = result.templates && result.templates[0] ? result.templates[0].html : '';
module.description = '';
}).catch((error) => {
this.logger.error('Error calling course page method:', error);
}).finally(() => {
handlerData.loading = false;
});
}
return handlerData;
}
/**

View File

@ -85,7 +85,7 @@ export class CoreSitePluginsHelperProvider {
protected logger;
protected courseRestrictHandlers = {};
constructor(logger: CoreLoggerProvider,
constructor(protected loggerProvider: CoreLoggerProvider,
private sitesProvider: CoreSitesProvider,
private domUtils: CoreDomUtilsProvider,
private mainMenuDelegate: CoreMainMenuDelegate,
@ -119,7 +119,7 @@ export class CoreSitePluginsHelperProvider {
private blockDelegate: CoreBlockDelegate,
private filterHelper: CoreFilterHelperProvider) {
this.logger = logger.getInstance('CoreSitePluginsHelperProvider');
this.logger = loggerProvider.getInstance('CoreSitePluginsHelperProvider');
// Fetch the plugins on login.
eventsProvider.on(CoreEventsProvider.LOGIN, (data) => {
@ -834,7 +834,8 @@ export class CoreSitePluginsHelperProvider {
const uniqueName = this.sitePluginsProvider.getHandlerUniqueName(plugin, handlerName),
modName = (handlerSchema.moodlecomponent || plugin.component).replace('mod_', '');
this.moduleDelegate.registerHandler(new CoreSitePluginsModuleHandler(uniqueName, modName, handlerSchema, initResult));
this.moduleDelegate.registerHandler(new CoreSitePluginsModuleHandler(uniqueName, modName, plugin, handlerSchema,
initResult, this.sitePluginsProvider, this.loggerProvider));
if (handlerSchema.offlinefunctions && Object.keys(handlerSchema.offlinefunctions).length) {
// Register the prefetch handler.