MOBILE-2335 book: Support single activity format with book

main
Dani Palou 2018-02-02 08:57:34 +01:00
parent 4bcecc81dd
commit aa95a20287
9 changed files with 80 additions and 8 deletions

View File

@ -20,6 +20,7 @@ import { CoreDomUtilsProvider } from '../../../../../providers/utils/dom';
import { CoreTextUtilsProvider } from '../../../../../providers/utils/text';
import { CoreCourseProvider } from '../../../../../core/course/providers/course';
import { CoreCourseHelperProvider } from '../../../../../core/course/providers/helper';
import { CoreCourseModuleMainComponent } from '../../../../../core/course/providers/module-delegate';
import { AddonModBookProvider, AddonModBookContentsMap, AddonModBookTocChapter } from '../../providers/book';
import { AddonModBookPrefetchHandler } from '../../providers/prefetch-handler';
import { AddonModBookTocPopoverComponent } from '../../components/toc-popover/toc-popover';
@ -31,7 +32,7 @@ import { AddonModBookTocPopoverComponent } from '../../components/toc-popover/to
selector: 'addon-mod-book-index',
templateUrl: 'index.html',
})
export class AddonModBookIndexComponent implements OnInit {
export class AddonModBookIndexComponent implements OnInit, CoreCourseModuleMainComponent {
@Input() module: any; // The module of the book.
@Input() courseId: number; // Course ID the book belongs to.
@Output() bookRetrieved?: EventEmitter<any>;

View File

@ -15,6 +15,7 @@
import { Injectable } from '@angular/core';
import { NavController, NavOptions } from 'ionic-angular';
import { AddonModBookProvider } from './book';
import { AddonModBookIndexComponent } from '../components/index/index';
import { CoreCourseModuleHandler, CoreCourseModuleHandlerData } from '../../../../core/course/providers/module-delegate';
import { CoreCourseProvider } from '../../../../core/course/providers/course';
@ -57,12 +58,13 @@ export class AddonModBookModuleHandler implements CoreCourseModuleHandler {
/**
* Get the component to render the module. This is needed to support singleactivity course format.
* The component returned must implement CoreCourseModuleMainComponent.
*
* @param {any} course The course object.
* @param {any} module The module object.
* @return {any} The component to use, undefined if not found.
*/
getMainComponent(course: any, module: any): any {
// @todo
return AddonModBookIndexComponent;
}
}

View File

@ -57,6 +57,7 @@ export class AddonModLabelModuleHandler implements CoreCourseModuleHandler {
/**
* Get the component to render the module. This is needed to support singleactivity course format.
* The component returned must implement CoreCourseModuleMainComponent.
*
* @param {any} course The course object.
* @param {any} module The module object.

View File

@ -134,7 +134,7 @@ export class CoreDelegate {
if (handler && handler[fnName]) {
return handler[fnName].apply(handler, params);
} else if (this.defaultHandler && this.defaultHandler[fnName]) {
return this.defaultHandler[fnName].apply(this, params);
return this.defaultHandler[fnName].apply(this.defaultHandler, params);
}
}

View File

@ -99,6 +99,19 @@ export class CoreDynamicComponent implements OnInit, OnChanges, DoCheck {
}
}
/**
* Call a certain function on the component.
*
* @param {string} name Name of the function to call.
* @param {any[]} params List of params to send to the function.
* @return {any} Result of the call. Undefined if no component instance or the function doesn't exist.
*/
callComponentFunction(name: string, params: any[]): any {
if (this.instance && typeof this.instance[name] == 'function') {
return this.instance[name].apply(this.instance, params);
}
}
/**
* Create a component, add it to a container and set the input data.
*

View File

@ -12,7 +12,9 @@
// See the License for the specific language governing permissions and
// limitations under the License.
import { Component, Input, OnInit, OnChanges, OnDestroy, SimpleChange, Output, EventEmitter } from '@angular/core';
import {
Component, Input, OnInit, OnChanges, OnDestroy, SimpleChange, Output, EventEmitter, ViewChildren, QueryList
} from '@angular/core';
import { Content } from 'ionic-angular';
import { TranslateService } from '@ngx-translate/core';
import { CoreEventsProvider } from '../../../../providers/events';
@ -22,6 +24,7 @@ import { CoreCourseProvider } from '../../../course/providers/course';
import { CoreCourseHelperProvider } from '../../../course/providers/helper';
import { CoreCourseFormatDelegate } from '../../../course/providers/format-delegate';
import { CoreCourseModulePrefetchDelegate } from '../../../course/providers/module-prefetch-delegate';
import { CoreDynamicComponent } from '../../../../components/dynamic-component/dynamic-component';
/**
* Component to display course contents using a certain format. If the format isn't found, use default one.
@ -46,6 +49,8 @@ export class CoreCourseFormatComponent implements OnInit, OnChanges, OnDestroy {
@Input() moduleId?: number; // The module ID to scroll to. Must be inside the initial selected section.
@Output() completionChanged?: EventEmitter<void>; // Will emit an event when any module completion changes.
@ViewChildren(CoreDynamicComponent) dynamicComponents: QueryList<CoreDynamicComponent>;
// All the possible component classes.
courseFormatComponent: any;
courseSummaryComponent: any;
@ -286,6 +291,23 @@ export class CoreCourseFormatComponent implements OnInit, OnChanges, OnDestroy {
});
}
/**
* Refresh the data.
*
* @param {any} [refresher] Refresher.
* @param {Function} [done] Function to call when done.
* @return {Promise<any>} Promise resolved when done.
*/
doRefresh(refresher?: any, done?: () => void): Promise<any> {
const promises = [];
this.dynamicComponents.forEach((component) => {
promises.push(Promise.resolve(component.callComponentFunction('doRefresh', [refresher, done])));
});
return Promise.all(promises);
}
/**
* Component destroyed.
*/

View File

@ -12,9 +12,10 @@
// See the License for the specific language governing permissions and
// limitations under the License.
import { Component, Input, OnChanges, SimpleChange } from '@angular/core';
import { Component, Input, OnChanges, SimpleChange, ViewChild } from '@angular/core';
import { CoreCourseModuleDelegate } from '../../../providers/module-delegate';
import { CoreCourseUnsupportedModuleComponent } from '../../../components/unsupported-module/unsupported-module';
import { CoreDynamicComponent } from '../../../../../components/dynamic-component/dynamic-component';
/**
* Component to display single activity format. It will determine the right component to use and instantiate it.
@ -30,6 +31,8 @@ export class CoreCourseFormatSingleActivityComponent implements OnChanges {
@Input() sections: any[]; // List of course sections.
@Input() downloadEnabled?: boolean; // Whether the download of sections and modules is enabled.
@ViewChild(CoreDynamicComponent) dynamicComponent: CoreDynamicComponent;
componentClass: any; // The class of the component to render.
data: any = {}; // Data to pass to the component.
@ -52,4 +55,15 @@ export class CoreCourseFormatSingleActivityComponent implements OnChanges {
this.data.module = module;
}
}
/**
* Refresh the data.
*
* @param {any} [refresher] Refresher.
* @param {Function} [done] Function to call when done.
* @return {Promise<any>} Promise resolved when done.
*/
doRefresh(refresher?: any, done?: () => void): Promise<any> {
return Promise.resolve(this.dynamicComponent.callComponentFunction('doRefresh', [refresher, done]));
}
}

View File

@ -24,6 +24,7 @@ import { CoreCourseHelperProvider } from '../../providers/helper';
import { CoreCourseFormatDelegate } from '../../providers/format-delegate';
import { CoreCourseModulePrefetchDelegate } from '../../providers/module-prefetch-delegate';
import { CoreCourseOptionsDelegate, CoreCourseOptionsHandlerToDisplay } from '../../providers/options-delegate';
import { CoreCourseFormatComponent } from '../../components/format/format';
import { CoreCoursesProvider } from '../../../courses/providers/courses';
/**
@ -36,6 +37,7 @@ import { CoreCoursesProvider } from '../../../courses/providers/courses';
})
export class CoreCourseSectionPage implements OnDestroy {
@ViewChild(Content) content: Content;
@ViewChild(CoreCourseFormatComponent) formatComponent: CoreCourseFormatComponent;
title: string;
course: any;
@ -150,7 +152,7 @@ export class CoreCourseSectionPage implements OnDestroy {
promises.push(promise.then((completionStatus) => {
// Get all the sections.
promises.push(this.courseProvider.getSections(this.course.id, false, true).then((sections) => {
return this.courseProvider.getSections(this.course.id, false, true).then((sections) => {
if (refresh) {
// Invalidate the recently downloaded module list. To ensure info can be prefetched.
const modules = this.courseProvider.getSectionsModules(sections);
@ -185,7 +187,7 @@ export class CoreCourseSectionPage implements OnDestroy {
// Get the title again now that we have sections.
this.title = this.courseFormatDelegate.getCourseTitle(this.course, this.sections);
}));
});
}));
// Load the course handlers.
@ -207,7 +209,9 @@ export class CoreCourseSectionPage implements OnDestroy {
doRefresh(refresher: any): void {
this.invalidateData().finally(() => {
this.loadData(true).finally(() => {
refresher.complete();
this.formatComponent.doRefresh(refresher).finally(() => {
refresher.complete();
});
});
});
}

View File

@ -37,6 +37,7 @@ export interface CoreCourseModuleHandler extends CoreDelegateHandler {
/**
* Get the component to render the module. This is needed to support singleactivity course format.
* The component returned must implement CoreCourseModuleMainComponent.
*
* @param {any} course The course object.
* @param {any} module The module object.
@ -91,6 +92,20 @@ export interface CoreCourseModuleHandlerData {
action?(event: Event, navCtrl: NavController, module: any, courseId: number, options?: NavOptions): void;
}
/**
* Interface that all the components to render the module in singleactivity must implement.
*/
export interface CoreCourseModuleMainComponent {
/**
* Refresh the data.
*
* @param {any} [refresher] Refresher.
* @param {Function} [done] Function to call when done.
* @return {Promise<any>} Promise resolved when done.
*/
doRefresh(refresher?: any, done?: () => void): Promise<any>;
}
/**
* A button to display in a module item.
*/