MOBILE-2310 course: Implement singleactivity format
parent
398e7c2bf4
commit
514e9bf132
|
@ -22,13 +22,15 @@ import { CoreCourseFormatComponent } from './format/format';
|
||||||
import { CoreCourseModuleComponent } from './module/module';
|
import { CoreCourseModuleComponent } from './module/module';
|
||||||
import { CoreCourseModuleCompletionComponent } from './module-completion/module-completion';
|
import { CoreCourseModuleCompletionComponent } from './module-completion/module-completion';
|
||||||
import { CoreCourseModuleDescriptionComponent } from './module-description/module-description';
|
import { CoreCourseModuleDescriptionComponent } from './module-description/module-description';
|
||||||
|
import { CoreCourseUnsupportedModuleComponent } from './unsupported-module/unsupported-module';
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
declarations: [
|
declarations: [
|
||||||
CoreCourseFormatComponent,
|
CoreCourseFormatComponent,
|
||||||
CoreCourseModuleComponent,
|
CoreCourseModuleComponent,
|
||||||
CoreCourseModuleCompletionComponent,
|
CoreCourseModuleCompletionComponent,
|
||||||
CoreCourseModuleDescriptionComponent
|
CoreCourseModuleDescriptionComponent,
|
||||||
|
CoreCourseUnsupportedModuleComponent
|
||||||
],
|
],
|
||||||
imports: [
|
imports: [
|
||||||
CommonModule,
|
CommonModule,
|
||||||
|
@ -43,7 +45,11 @@ import { CoreCourseModuleDescriptionComponent } from './module-description/modul
|
||||||
CoreCourseFormatComponent,
|
CoreCourseFormatComponent,
|
||||||
CoreCourseModuleComponent,
|
CoreCourseModuleComponent,
|
||||||
CoreCourseModuleCompletionComponent,
|
CoreCourseModuleCompletionComponent,
|
||||||
CoreCourseModuleDescriptionComponent
|
CoreCourseModuleDescriptionComponent,
|
||||||
|
CoreCourseUnsupportedModuleComponent
|
||||||
|
],
|
||||||
|
entryComponents: [
|
||||||
|
CoreCourseUnsupportedModuleComponent
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
export class CoreCourseComponentsModule {}
|
export class CoreCourseComponentsModule {}
|
||||||
|
|
|
@ -210,16 +210,17 @@ export class CoreCourseFormatComponent implements OnInit, OnChanges, OnDestroy {
|
||||||
|
|
||||||
this.componentContainers[type] = container;
|
this.componentContainers[type] = container;
|
||||||
this.componentInstances[type] = componentRef.instance;
|
this.componentInstances[type] = componentRef.instance;
|
||||||
this.cdr.detectChanges(); // The instances are used in ngIf, tell Angular that something has changed.
|
|
||||||
|
|
||||||
// Set the Input data.
|
// Set the Input data.
|
||||||
this.componentInstances[type].course = this.course;
|
this.componentInstances[type].course = this.course;
|
||||||
this.componentInstances[type].sections = this.sections;
|
this.componentInstances[type].sections = this.sections;
|
||||||
this.componentInstances[type].downloadEnabled = this.downloadEnabled;
|
this.componentInstances[type].downloadEnabled = this.downloadEnabled;
|
||||||
|
|
||||||
|
this.cdr.detectChanges(); // The instances are used in ngIf, tell Angular that something has changed.
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
} catch(ex) {
|
} catch(ex) {
|
||||||
this.logger.error('Error creating component', type, ex, componentClass);
|
this.logger.error('Error creating component', type, ex);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
<div padding>
|
||||||
|
<core-course-module-description [description]="module.description"></core-course-module-description>
|
||||||
|
<h2 *ngIf="!isDisabledInSite && isSupportedByTheApp">{{ 'core.whoops' | translate }}</h2>
|
||||||
|
<h2 *ngIf="isDisabledInSite || !isSupportedByTheApp">{{ 'core.uhoh' | translate }}</h2>
|
||||||
|
|
||||||
|
<p class="core-big" *ngIf="isDisabledInSite">{{ 'core.course.activitydisabled' | translate }}</p>
|
||||||
|
<p class="core-big" *ngIf="!isDisabledInSite && isSupportedByTheApp">{{ 'core.course.activitynotyetviewablesiteupgradeneeded' | translate }}</p>
|
||||||
|
<p class="core-big" *ngIf="!isDisabledInSite && !isSupportedByTheApp">{{ 'core.course.activitynotyetviewableremoteaddon' | translate }}</p>
|
||||||
|
<p *ngIf="isDisabledInSite || !isSupportedByTheApp"><strong>{{ 'core.course.askadmintosupport' | translate }}</strong></p>
|
||||||
|
|
||||||
|
<div *ngIf="module.url">
|
||||||
|
<p><strong>{{ 'core.course.useactivityonbrowser' | translate }}</strong></p>
|
||||||
|
<a ion-button block icon-end [href]="module.url" core-link>
|
||||||
|
{{ 'core.openinbrowser' | translate }}
|
||||||
|
<ion-icon name="open"></ion-icon>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
|
@ -0,0 +1,48 @@
|
||||||
|
// (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, OnInit } from '@angular/core';
|
||||||
|
import { IonicPage, NavParams } from 'ionic-angular';
|
||||||
|
import { TranslateService } from '@ngx-translate/core';
|
||||||
|
import { CoreTextUtilsProvider } from '../../../../providers/utils/text';
|
||||||
|
import { CoreCourseProvider } from '../../providers/course';
|
||||||
|
import { CoreCourseModuleDelegate } from '../../providers/module-delegate';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Component that displays info about an unsupported module.
|
||||||
|
*/
|
||||||
|
@Component({
|
||||||
|
selector: 'core-course-unsupported-module',
|
||||||
|
templateUrl: 'unsupported-module.html',
|
||||||
|
})
|
||||||
|
export class CoreCourseUnsupportedModuleComponent implements OnInit {
|
||||||
|
@Input() course: any; // The course to module belongs to.
|
||||||
|
@Input() module: any; // The module to render.
|
||||||
|
|
||||||
|
isDisabledInSite: boolean;
|
||||||
|
isSupportedByTheApp: boolean;
|
||||||
|
moduleName: string;
|
||||||
|
|
||||||
|
constructor(navParams: NavParams, private translate: TranslateService, private textUtils: CoreTextUtilsProvider,
|
||||||
|
private courseProvider: CoreCourseProvider, private moduleDelegate: CoreCourseModuleDelegate) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Component being initialized.
|
||||||
|
*/
|
||||||
|
ngOnInit() {
|
||||||
|
this.isDisabledInSite = this.moduleDelegate.isModuleDisabledInSite(this.module.modname);
|
||||||
|
this.isSupportedByTheApp = this.moduleDelegate.hasHandler(this.module.modname);
|
||||||
|
this.moduleName = this.courseProvider.translateModuleName(this.module.modname);
|
||||||
|
}
|
||||||
|
}
|
|
@ -19,12 +19,14 @@ import { CoreCourseFormatDelegate } from './providers/format-delegate';
|
||||||
import { CoreCourseModuleDelegate } from './providers/module-delegate';
|
import { CoreCourseModuleDelegate } from './providers/module-delegate';
|
||||||
import { CoreCourseModulePrefetchDelegate } from './providers/module-prefetch-delegate';
|
import { CoreCourseModulePrefetchDelegate } from './providers/module-prefetch-delegate';
|
||||||
import { CoreCourseFormatDefaultHandler } from './providers/default-format';
|
import { CoreCourseFormatDefaultHandler } from './providers/default-format';
|
||||||
|
import { CoreCourseFormatSingleActivityModule } from './formats/singleactivity/singleactivity.module';
|
||||||
import { CoreCourseFormatTopicsModule} from './formats/topics/topics.module';
|
import { CoreCourseFormatTopicsModule} from './formats/topics/topics.module';
|
||||||
import { CoreCourseFormatWeeksModule } from './formats/weeks/weeks.module';
|
import { CoreCourseFormatWeeksModule } from './formats/weeks/weeks.module';
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
declarations: [],
|
declarations: [],
|
||||||
imports: [
|
imports: [
|
||||||
|
CoreCourseFormatSingleActivityModule,
|
||||||
CoreCourseFormatTopicsModule,
|
CoreCourseFormatTopicsModule,
|
||||||
CoreCourseFormatWeeksModule
|
CoreCourseFormatWeeksModule
|
||||||
],
|
],
|
||||||
|
|
|
@ -0,0 +1,119 @@
|
||||||
|
// (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, OnChanges, ViewContainerRef, ComponentFactoryResolver, ChangeDetectorRef,
|
||||||
|
SimpleChange } from '@angular/core';
|
||||||
|
import { CoreLoggerProvider } from '../../../../../providers/logger';
|
||||||
|
import { CoreCourseModuleDelegate } from '../../../providers/module-delegate';
|
||||||
|
import { CoreCourseUnsupportedModuleComponent } from '../../../components/unsupported-module/unsupported-module';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Component to display single activity format. It will determine the right component to use and instantiate it.
|
||||||
|
*
|
||||||
|
* The instantiated component will receive the course and the module as inputs.
|
||||||
|
*/
|
||||||
|
@Component({
|
||||||
|
selector: 'core-course-format-single-activity',
|
||||||
|
template: ''
|
||||||
|
})
|
||||||
|
export class CoreCourseFormatSingleActivityComponent implements OnChanges {
|
||||||
|
@Input() course: any; // The course to render.
|
||||||
|
@Input() sections: any[]; // List of course sections.
|
||||||
|
@Input() downloadEnabled?: boolean; // Whether the download of sections and modules is enabled.
|
||||||
|
|
||||||
|
protected logger: any;
|
||||||
|
protected module: any;
|
||||||
|
protected componentInstance: any;
|
||||||
|
|
||||||
|
constructor(logger: CoreLoggerProvider, private viewRef: ViewContainerRef, private factoryResolver: ComponentFactoryResolver,
|
||||||
|
private cdr: ChangeDetectorRef, private moduleDelegate: CoreCourseModuleDelegate) {
|
||||||
|
this.logger = logger.getInstance('CoreCourseFormatSingleActivityComponent');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Detect changes on input properties.
|
||||||
|
*/
|
||||||
|
ngOnChanges(changes: {[name: string]: SimpleChange}) {
|
||||||
|
if (this.course && this.sections && this.sections.length) {
|
||||||
|
// In single activity the module should only have 1 section and 1 module. Get the module.
|
||||||
|
let module = this.sections[0] && this.sections[0].modules && this.sections[0].modules[0];
|
||||||
|
if (module && !this.componentInstance) {
|
||||||
|
// We haven't created the component yet. Create it now.
|
||||||
|
this.createComponent(module);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.componentInstance && this.componentInstance.ngOnChanges) {
|
||||||
|
// Call ngOnChanges of the component.
|
||||||
|
let newChanges: {[name: string]: SimpleChange} = {};
|
||||||
|
|
||||||
|
// Check if course has changed.
|
||||||
|
if (changes.course) {
|
||||||
|
newChanges.course = changes.course
|
||||||
|
this.componentInstance.course = this.course;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if module has changed.
|
||||||
|
if (changes.sections && module != this.module) {
|
||||||
|
newChanges.module = {
|
||||||
|
currentValue: module,
|
||||||
|
firstChange: changes.sections.firstChange,
|
||||||
|
previousValue: this.module,
|
||||||
|
isFirstChange: () => {
|
||||||
|
return newChanges.module.firstChange;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
this.componentInstance.module = module;
|
||||||
|
this.module = module;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Object.keys(newChanges).length) {
|
||||||
|
this.componentInstance.ngOnChanges(newChanges);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create the component, add it to the container and set the input data.
|
||||||
|
*
|
||||||
|
* @param {any} module The module.
|
||||||
|
* @return {boolean} Whether the component was successfully created.
|
||||||
|
*/
|
||||||
|
protected createComponent(module: any) : boolean {
|
||||||
|
let componentClass = this.moduleDelegate.getMainComponent(this.course, module) || CoreCourseUnsupportedModuleComponent;
|
||||||
|
if (!componentClass) {
|
||||||
|
// No component to instantiate.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Create the component and add it to the container.
|
||||||
|
const factory = this.factoryResolver.resolveComponentFactory(componentClass),
|
||||||
|
componentRef = this.viewRef.createComponent(factory);
|
||||||
|
|
||||||
|
this.componentInstance = componentRef.instance;
|
||||||
|
|
||||||
|
// Set the Input data.
|
||||||
|
this.componentInstance.courseId = this.course.id;
|
||||||
|
this.componentInstance.module = module;
|
||||||
|
|
||||||
|
// this.cdr.detectChanges(); // The instances are used in ngIf, tell Angular that something has changed.
|
||||||
|
|
||||||
|
return true;
|
||||||
|
} catch(ex) {
|
||||||
|
this.logger.error('Error creating component', ex);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,83 @@
|
||||||
|
// (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 { CoreCourseFormatHandler } from '../../../providers/format-delegate';
|
||||||
|
import { CoreCourseFormatSingleActivityComponent } from '../components/format';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handler to support weeks course format.
|
||||||
|
*/
|
||||||
|
@Injectable()
|
||||||
|
export class CoreCourseFormatSingleActivityHandler implements CoreCourseFormatHandler {
|
||||||
|
name = 'singleactivity';
|
||||||
|
|
||||||
|
constructor() {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether or not the handler is enabled on a site level.
|
||||||
|
*
|
||||||
|
* @return {boolean|Promise<boolean>} True or promise resolved with true if enabled.
|
||||||
|
*/
|
||||||
|
isEnabled() : boolean|Promise<boolean> {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether it allows seeing all sections at the same time. Defaults to true.
|
||||||
|
*
|
||||||
|
* @param {any} course The course to check.
|
||||||
|
* @type {boolean} Whether it can view all sections.
|
||||||
|
*/
|
||||||
|
canViewAllSections(course: any) : boolean {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the title to use in course page. If not defined, course fullname.
|
||||||
|
* This function will be called without sections first, and then call it again when the sections are retrieved.
|
||||||
|
*
|
||||||
|
* @param {any} course The course.
|
||||||
|
* @param {any[]} [sections] List of sections.
|
||||||
|
* @return {string} Title.
|
||||||
|
*/
|
||||||
|
getCourseTitle(course: any, sections?: any[]) : string {
|
||||||
|
if (sections && sections[0] && sections[0].modules && sections[0].modules[0]) {
|
||||||
|
return sections[0].modules[0].name;
|
||||||
|
}
|
||||||
|
return course.fullname || '';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether the default section selector should be displayed. Defaults to true.
|
||||||
|
*
|
||||||
|
* @param {any} course The course to check.
|
||||||
|
* @type {boolean} Whether the default section selector should be displayed.
|
||||||
|
*/
|
||||||
|
displaySectionSelector(course: any) : boolean {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the Component to use to display the course format instead of using the default one.
|
||||||
|
* Use it if you want to display a format completely different from the default one.
|
||||||
|
* If you want to customize the default format there are several methods to customize parts of it.
|
||||||
|
*
|
||||||
|
* @param {any} course The course to render.
|
||||||
|
* @return {any} The component to use, undefined if not found.
|
||||||
|
*/
|
||||||
|
getCourseFormatComponent(course: any) : any {
|
||||||
|
return CoreCourseFormatSingleActivityComponent;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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 { CoreCourseFormatSingleActivityComponent } from './components/format';
|
||||||
|
import { CoreCourseFormatSingleActivityHandler } from './providers/handler';
|
||||||
|
import { CoreCourseFormatDelegate } from '../../providers/format-delegate';
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
declarations: [
|
||||||
|
CoreCourseFormatSingleActivityComponent
|
||||||
|
],
|
||||||
|
imports: [
|
||||||
|
],
|
||||||
|
providers: [
|
||||||
|
CoreCourseFormatSingleActivityHandler
|
||||||
|
],
|
||||||
|
exports: [
|
||||||
|
CoreCourseFormatSingleActivityComponent
|
||||||
|
],
|
||||||
|
entryComponents: [
|
||||||
|
CoreCourseFormatSingleActivityComponent
|
||||||
|
]
|
||||||
|
})
|
||||||
|
export class CoreCourseFormatSingleActivityModule {
|
||||||
|
constructor(formatDelegate: CoreCourseFormatDelegate, handler: CoreCourseFormatSingleActivityHandler) {
|
||||||
|
formatDelegate.registerHandler(handler);
|
||||||
|
}
|
||||||
|
}
|
|
@ -16,9 +16,10 @@
|
||||||
</ion-refresher>
|
</ion-refresher>
|
||||||
|
|
||||||
<core-loading [hideUntil]="dataLoaded">
|
<core-loading [hideUntil]="dataLoaded">
|
||||||
<div class="tabs tabs-striped tabs-free mm-tabs-color">
|
<!-- @todo: Use core-tabs or a new component. core-tabs might initialize all tabs at start, so we might require a new component. -->
|
||||||
<a ion-button class="tab-item">{{ 'core.course.contents' || translate }}</a>
|
<div class="core-tabs-bar">
|
||||||
<a *ngFor="let handler of courseHandlers" ion-button class="tab-item">{{ handler.data.title || translate }}</a>
|
<a aria-selected="true">{{ 'core.course.contents' | translate }}</a>
|
||||||
|
<a *ngFor="let handler of courseHandlers">{{ handler.data.title || translate }}</a>
|
||||||
</div>
|
</div>
|
||||||
<core-course-format [course]="course" [sections]="sections" [downloadEnabled]="downloadEnabled" (completionChanged)="onCompletionChange()"></core-course-format>
|
<core-course-format [course]="course" [sections]="sections" [downloadEnabled]="downloadEnabled" (completionChanged)="onCompletionChange()"></core-course-format>
|
||||||
</core-loading>
|
</core-loading>
|
||||||
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
page-core-course-section {
|
||||||
|
.core-tabs-bar {
|
||||||
|
@include position(null, null, 0, 0);
|
||||||
|
|
||||||
|
z-index: $z-index-toolbar;
|
||||||
|
display: flex;
|
||||||
|
width: 100%;
|
||||||
|
background: $core-top-tabs-background;
|
||||||
|
|
||||||
|
> a {
|
||||||
|
@extend .tab-button;
|
||||||
|
|
||||||
|
background: $core-top-tabs-background;
|
||||||
|
color: $core-top-tabs-color !important;
|
||||||
|
border-bottom: 1px solid $core-top-tabs-border;
|
||||||
|
font-size: 1.6rem;
|
||||||
|
|
||||||
|
&[aria-selected=true] {
|
||||||
|
color: $core-top-tabs-color-active !important;
|
||||||
|
border-bottom: 2px solid $core-top-tabs-color-active;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -58,9 +58,11 @@ export class CoreCourseSectionPage implements OnDestroy {
|
||||||
private textUtils: CoreTextUtilsProvider, private coursesProvider: CoreCoursesProvider,
|
private textUtils: CoreTextUtilsProvider, private coursesProvider: CoreCoursesProvider,
|
||||||
sitesProvider: CoreSitesProvider) {
|
sitesProvider: CoreSitesProvider) {
|
||||||
this.course = navParams.get('course');
|
this.course = navParams.get('course');
|
||||||
this.title = courseFormatDelegate.getCourseTitle(this.course);
|
|
||||||
this.moduleId = navParams.get('moduleId');
|
this.moduleId = navParams.get('moduleId');
|
||||||
|
|
||||||
|
// Get the title to display. We dont't have sections yet.
|
||||||
|
this.title = courseFormatDelegate.getCourseTitle(this.course);
|
||||||
|
|
||||||
this.completionObserver = eventsProvider.on(CoreEventsProvider.COMPLETION_MODULE_VIEWED, (data) => {
|
this.completionObserver = eventsProvider.on(CoreEventsProvider.COMPLETION_MODULE_VIEWED, (data) => {
|
||||||
if (data && data.courseId == this.course.id) {
|
if (data && data.courseId == this.course.id) {
|
||||||
this.refreshAfterCompletionChange();
|
this.refreshAfterCompletionChange();
|
||||||
|
@ -150,6 +152,9 @@ export class CoreCourseSectionPage implements OnDestroy {
|
||||||
id: CoreCourseProvider.ALL_SECTIONS_ID
|
id: CoreCourseProvider.ALL_SECTIONS_ID
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get the title again now that we have sections.
|
||||||
|
this.title = this.courseFormatDelegate.getCourseTitle(this.course, this.sections);
|
||||||
}));
|
}));
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
|
|
@ -10,21 +10,6 @@
|
||||||
</ion-buttons>
|
</ion-buttons>
|
||||||
</ion-navbar>
|
</ion-navbar>
|
||||||
</ion-header>
|
</ion-header>
|
||||||
<ion-content padding>
|
<ion-content>
|
||||||
<core-course-module-description [description]="module.description"></core-course-module-description>
|
<core-course-unsupported-module [module]="module"></core-course-unsupported-module>
|
||||||
<h2 *ngIf="!isDisabledInSite && isSupportedByTheApp">{{ 'core.whoops' | translate }}</h2>
|
|
||||||
<h2 *ngIf="isDisabledInSite || !isSupportedByTheApp">{{ 'core.uhoh' | translate }}</h2>
|
|
||||||
|
|
||||||
<p class="core-big" *ngIf="isDisabledInSite">{{ 'core.course.activitydisabled' | translate }}</p>
|
|
||||||
<p class="core-big" *ngIf="!isDisabledInSite && isSupportedByTheApp">{{ 'core.course.activitynotyetviewablesiteupgradeneeded' | translate }}</p>
|
|
||||||
<p class="core-big" *ngIf="!isDisabledInSite && !isSupportedByTheApp">{{ 'core.course.activitynotyetviewableremoteaddon' | translate }}</p>
|
|
||||||
<p *ngIf="isDisabledInSite || !isSupportedByTheApp"><strong>{{ 'core.course.askadmintosupport' | translate }}</strong></p>
|
|
||||||
|
|
||||||
<div *ngIf="module.url">
|
|
||||||
<p><strong>{{ 'core.course.useactivityonbrowser' | translate }}</strong></p>
|
|
||||||
<a ion-button block icon-end [href]="module.url" core-link>
|
|
||||||
{{ 'core.openinbrowser' | translate }}
|
|
||||||
<ion-icon name="open"></ion-icon>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</ion-content>
|
</ion-content>
|
||||||
|
|
|
@ -13,11 +13,9 @@
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
import { Component } from '@angular/core';
|
import { Component } from '@angular/core';
|
||||||
import { IonicPage, NavParams } from 'ionic-angular';
|
import { IonicPage, NavParams, NavController } from 'ionic-angular';
|
||||||
import { TranslateService } from '@ngx-translate/core';
|
import { TranslateService } from '@ngx-translate/core';
|
||||||
import { CoreTextUtilsProvider } from '../../../../providers/utils/text';
|
import { CoreTextUtilsProvider } from '../../../../providers/utils/text';
|
||||||
import { CoreCourseProvider } from '../../providers/course';
|
|
||||||
import { CoreCourseModuleDelegate } from '../../providers/module-delegate';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Page that displays info about an unsupported module.
|
* Page that displays info about an unsupported module.
|
||||||
|
@ -28,30 +26,18 @@ import { CoreCourseModuleDelegate } from '../../providers/module-delegate';
|
||||||
templateUrl: 'unsupported-module.html',
|
templateUrl: 'unsupported-module.html',
|
||||||
})
|
})
|
||||||
export class CoreCourseUnsupportedModulePage {
|
export class CoreCourseUnsupportedModulePage {
|
||||||
|
|
||||||
module: any;
|
module: any;
|
||||||
isDisabledInSite: boolean;
|
|
||||||
isSupportedByTheApp: boolean;
|
|
||||||
moduleName: string;
|
|
||||||
|
|
||||||
constructor(navParams: NavParams, private translate: TranslateService, private textUtils: CoreTextUtilsProvider,
|
constructor(navParams: NavParams, private translate: TranslateService, private textUtils: CoreTextUtilsProvider,
|
||||||
private moduleDelegate: CoreCourseModuleDelegate, private courseProvider: CoreCourseProvider) {
|
private navCtrl: NavController) {
|
||||||
this.module = navParams.get('module') || {};
|
this.module = navParams.get('module') || {};
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* View loaded.
|
|
||||||
*/
|
|
||||||
ionViewDidLoad() {
|
|
||||||
this.isDisabledInSite = this.moduleDelegate.isModuleDisabledInSite(this.module.modname);
|
|
||||||
this.isSupportedByTheApp = this.moduleDelegate.hasHandler(this.module.modname);
|
|
||||||
this.moduleName = this.courseProvider.translateModuleName(this.module.modname);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Expand the description.
|
* Expand the description.
|
||||||
*/
|
*/
|
||||||
expandDescription() {
|
expandDescription() {
|
||||||
this.textUtils.expandText(this.translate.instant('core.description'), this.module.description, false);
|
this.textUtils.expandText(this.translate.instant('core.description'), this.module.description, false,
|
||||||
|
undefined, undefined, this.navCtrl);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,11 +39,13 @@ export interface CoreCourseFormatHandler {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the title to use in course page. If not defined, course fullname.
|
* Get the title to use in course page. If not defined, course fullname.
|
||||||
|
* This function will be called without sections first, and then call it again when the sections are retrieved.
|
||||||
*
|
*
|
||||||
* @param {any} course The course.
|
* @param {any} course The course.
|
||||||
|
* @param {any[]} [sections] List of sections.
|
||||||
* @return {string} Title.
|
* @return {string} Title.
|
||||||
*/
|
*/
|
||||||
getCourseTitle?(course: any) : string;
|
getCourseTitle?(course: any, sections?: any[]) : string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether it allows seeing all sections at the same time. Defaults to true.
|
* Whether it allows seeing all sections at the same time. Defaults to true.
|
||||||
|
@ -227,10 +229,11 @@ export class CoreCourseFormatDelegate {
|
||||||
* Given a course, return the title to use in the course page.
|
* Given a course, return the title to use in the course page.
|
||||||
*
|
*
|
||||||
* @param {any} course The course to get the title.
|
* @param {any} course The course to get the title.
|
||||||
|
* @param {any[]} [sections] List of sections.
|
||||||
* @return {string} Course title.
|
* @return {string} Course title.
|
||||||
*/
|
*/
|
||||||
getCourseTitle(course: any) : string {
|
getCourseTitle(course: any, sections?: any[]) : string {
|
||||||
return this.executeFunction(course.format, 'getCourseTitle', [course]);
|
return this.executeFunction(course.format, 'getCourseTitle', [course, sections]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -52,6 +52,15 @@ export interface CoreCourseModuleHandler {
|
||||||
* @return {CoreCourseModuleHandlerData} Data to render the module.
|
* @return {CoreCourseModuleHandlerData} Data to render the module.
|
||||||
*/
|
*/
|
||||||
getData(module: any, courseId: number, sectionId: number) : CoreCourseModuleHandlerData;
|
getData(module: any, courseId: number, sectionId: number) : CoreCourseModuleHandlerData;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the component to render the module. This is needed to support singleactivity course format.
|
||||||
|
*
|
||||||
|
* @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;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -163,6 +172,23 @@ export class CoreCourseModuleDelegate {
|
||||||
eventsProvider.on(CoreEventsProvider.REMOTE_ADDONS_LOADED, this.updateHandlers.bind(this));
|
eventsProvider.on(CoreEventsProvider.REMOTE_ADDONS_LOADED, this.updateHandlers.bind(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the component to render the module.
|
||||||
|
*
|
||||||
|
* @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 {
|
||||||
|
let handler = this.enabledHandlers[module.modname];
|
||||||
|
if (handler && handler.getMainComponent) {
|
||||||
|
let component = handler.getMainComponent(course, module);
|
||||||
|
if (component) {
|
||||||
|
return component;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the data required to display the module in the course contents view.
|
* Get the data required to display the module in the course contents view.
|
||||||
*
|
*
|
||||||
|
|
|
@ -165,7 +165,7 @@ export class CoreFileUploaderDelegate {
|
||||||
protected lastUpdateHandlersStart: number;
|
protected lastUpdateHandlersStart: number;
|
||||||
|
|
||||||
constructor(logger: CoreLoggerProvider, private sitesProvider: CoreSitesProvider, eventsProvider: CoreEventsProvider) {
|
constructor(logger: CoreLoggerProvider, private sitesProvider: CoreSitesProvider, eventsProvider: CoreEventsProvider) {
|
||||||
this.logger = logger.getInstance('CoreCourseModuleDelegate');
|
this.logger = logger.getInstance('CoreFileUploaderDelegate');
|
||||||
|
|
||||||
eventsProvider.on(CoreEventsProvider.LOGIN, this.updateHandlers.bind(this));
|
eventsProvider.on(CoreEventsProvider.LOGIN, this.updateHandlers.bind(this));
|
||||||
eventsProvider.on(CoreEventsProvider.SITE_UPDATED, this.updateHandlers.bind(this));
|
eventsProvider.on(CoreEventsProvider.SITE_UPDATED, this.updateHandlers.bind(this));
|
||||||
|
|
|
@ -251,7 +251,7 @@ export class CoreTextUtilsProvider {
|
||||||
* @param {boolean} [isModal] Whether it should be opened in a modal (true) or in a new page (false).
|
* @param {boolean} [isModal] Whether it should be opened in a modal (true) or in a new page (false).
|
||||||
* @param {string} [component] Component to link the embedded files to.
|
* @param {string} [component] Component to link the embedded files to.
|
||||||
* @param {string|number} [componentId] An ID to use in conjunction with the component.
|
* @param {string|number} [componentId] An ID to use in conjunction with the component.
|
||||||
* @param {NavController} [navCtrl] The NavController instance to use.
|
* @param {NavController} [navCtrl] The NavController instance to use. Required if isModal is false.
|
||||||
*/
|
*/
|
||||||
expandText(title: string, text: string, isModal?: boolean, component?: string, componentId?: string|number,
|
expandText(title: string, text: string, isModal?: boolean, component?: string, componentId?: string|number,
|
||||||
navCtrl?: NavController) : void {
|
navCtrl?: NavController) : void {
|
||||||
|
|
Loading…
Reference in New Issue