MOBILE-3659 course: Implement core course formats
parent
2906210242
commit
a91c042cc2
|
@ -0,0 +1,42 @@
|
|||
// (C) Copyright 2015 Moodle Pty Ltd.
|
||||
//
|
||||
// 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 { CommonModule } from '@angular/common';
|
||||
import { IonicModule } from '@ionic/angular';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
|
||||
import { CoreSharedModule } from '@/core/shared.module';
|
||||
import { CoreBlockComponentsModule } from '@features/block/components/components.module';
|
||||
import { CoreCourseModuleDescriptionComponent } from './module-description/module-description';
|
||||
import { CoreCourseUnsupportedModuleComponent } from './unsupported-module/unsupported-module';
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
CoreCourseModuleDescriptionComponent,
|
||||
CoreCourseUnsupportedModuleComponent,
|
||||
],
|
||||
imports: [
|
||||
CoreBlockComponentsModule,
|
||||
CommonModule,
|
||||
IonicModule,
|
||||
TranslateModule.forChild(),
|
||||
CoreSharedModule,
|
||||
],
|
||||
exports: [
|
||||
CoreCourseModuleDescriptionComponent,
|
||||
CoreCourseUnsupportedModuleComponent,
|
||||
],
|
||||
})
|
||||
export class CoreCourseComponentsModule {}
|
|
@ -0,0 +1,11 @@
|
|||
<ion-card *ngIf="description">
|
||||
<ion-item class="ion-text-wrap">
|
||||
<core-format-text [text]="description" [component]="component" [componentId]="componentId"
|
||||
[maxHeight]="showFull && showFull !== 'false' ? 0 : 120" fullOnClick="true" [contextLevel]="contextLevel"
|
||||
[contextInstanceId]="contextInstanceId" [courseId]="courseId">
|
||||
</core-format-text>
|
||||
</ion-item>
|
||||
<ion-item class="ion-text-wrap" *ngIf="note">
|
||||
<ion-note slot="end">{{ note }}</ion-note>
|
||||
</ion-item>
|
||||
</ion-card>
|
|
@ -0,0 +1,16 @@
|
|||
// ion-app.app-root {
|
||||
// .safe-area-page,
|
||||
// .safe-padding-horizontal {
|
||||
// core-course-module-description {
|
||||
// padding-left: 0 !important;
|
||||
// padding-right: 0 !important;
|
||||
// .item-ios.item-block {
|
||||
// @include safe-area-padding-horizontal($item-ios-padding-end / 2, null);
|
||||
|
||||
// .item-inner {
|
||||
// @include safe-area-padding-horizontal(null, $item-ios-padding-end / 2);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
|
@ -0,0 +1,48 @@
|
|||
// (C) Copyright 2015 Moodle Pty Ltd.
|
||||
//
|
||||
// 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 } from '@angular/core';
|
||||
|
||||
/**
|
||||
* Component to display the description of a module.
|
||||
*
|
||||
* This directive is meant to display a module description in a similar way throughout all the app.
|
||||
*
|
||||
* You can add a note at the right side of the description by using the 'note' attribute.
|
||||
*
|
||||
* You can also pass a component and componentId to be used in format-text.
|
||||
*
|
||||
* Module descriptions are shortened by default, allowing the user to see the full description by clicking in it.
|
||||
* If you want the whole description to be shown you can use the 'showFull' attribute.
|
||||
*
|
||||
* Example usage:
|
||||
*
|
||||
* <core-course-module-description [description]="myDescription"></core-course-module-description
|
||||
*/
|
||||
@Component({
|
||||
selector: 'core-course-module-description',
|
||||
templateUrl: 'core-course-module-description.html',
|
||||
})
|
||||
export class CoreCourseModuleDescriptionComponent {
|
||||
|
||||
@Input() description?: string; // The description to display.
|
||||
@Input() note?: string; // A note to display along with the description.
|
||||
@Input() component?: string; // Component for format text directive.
|
||||
@Input() componentId?: string | number; // Component ID to use in conjunction with the component.
|
||||
@Input() showFull?: string | boolean; // Whether to always display the full description.
|
||||
@Input() contextLevel?: string; // The context level.
|
||||
@Input() contextInstanceId?: number; // The instance ID related to the context.
|
||||
@Input() courseId?: number; // Course ID the text belongs to. It can be used to improve performance with filters.
|
||||
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
<div class="ion-padding">
|
||||
<core-course-module-description [description]="module && module.description" contextLevel="module"
|
||||
[contextInstanceId]="module.id" [courseId]="courseId">
|
||||
</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 && module.url">
|
||||
<p><strong>{{ 'core.course.useactivityonbrowser' | translate }}</strong></p>
|
||||
<ion-button expand="block" [href]="module.url" core-link>
|
||||
{{ 'core.openinbrowser' | translate }}
|
||||
<ion-icon name="open" slot="end"></ion-icon>
|
||||
</ion-button>
|
||||
</div>
|
||||
</div>
|
|
@ -0,0 +1,49 @@
|
|||
// (C) Copyright 2015 Moodle Pty Ltd.
|
||||
//
|
||||
// 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 { CoreCourse, CoreCourseModuleData } from '@features/course/services/course';
|
||||
import { CoreCourseModuleDelegate } from '@features/course/services/module-delegate';
|
||||
|
||||
/**
|
||||
* Component that displays info about an unsupported module.
|
||||
*/
|
||||
@Component({
|
||||
selector: 'core-course-unsupported-module',
|
||||
templateUrl: 'core-course-unsupported-module.html',
|
||||
})
|
||||
export class CoreCourseUnsupportedModuleComponent implements OnInit {
|
||||
|
||||
@Input() courseId?: number; // The course to module belongs to.
|
||||
@Input() module?: CoreCourseModuleData; // The module to render.
|
||||
|
||||
isDisabledInSite?: boolean;
|
||||
isSupportedByTheApp?: boolean;
|
||||
moduleName?: string;
|
||||
|
||||
/**
|
||||
* Component being initialized.
|
||||
*/
|
||||
ngOnInit(): void {
|
||||
if (!this.module) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.isDisabledInSite = CoreCourseModuleDelegate.instance.isModuleDisabledInSite(this.module.modname);
|
||||
this.isSupportedByTheApp = CoreCourseModuleDelegate.instance.hasHandler(this.module.modname);
|
||||
this.moduleName = CoreCourse.instance.translateModuleName(this.module.modname);
|
||||
}
|
||||
|
||||
}
|
|
@ -15,11 +15,16 @@
|
|||
import { NgModule } from '@angular/core';
|
||||
|
||||
import { CORE_SITE_SCHEMAS } from '@services/sites';
|
||||
|
||||
import { CoreCourseComponentsModule } from './components/components.module';
|
||||
import { CoreCourseFormatModule } from './format/formats.module';
|
||||
import { SITE_SCHEMA, OFFLINE_SITE_SCHEMA } from './services/database/course';
|
||||
import { SITE_SCHEMA as LOG_SITE_SCHEMA } from './services/database/log';
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
CoreCourseFormatModule,
|
||||
CoreCourseComponentsModule,
|
||||
],
|
||||
providers: [
|
||||
{
|
||||
provide: CORE_SITE_SCHEMAS,
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
// (C) Copyright 2015 Moodle Pty Ltd.
|
||||
//
|
||||
// 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 { CoreCourseFormatSingleActivityModule } from './singleactivity/singleactivity.module';
|
||||
import { CoreCourseFormatSocialModule } from './social/social.module';
|
||||
import { CoreCourseFormatTopicsModule } from './topics/topics.module';
|
||||
import { CoreCourseFormatWeeksModule } from './weeks/weeks.module';
|
||||
|
||||
@NgModule({
|
||||
declarations: [],
|
||||
imports: [
|
||||
CoreCourseFormatSingleActivityModule,
|
||||
CoreCourseFormatSocialModule,
|
||||
CoreCourseFormatTopicsModule,
|
||||
CoreCourseFormatWeeksModule,
|
||||
],
|
||||
providers: [],
|
||||
exports: [],
|
||||
})
|
||||
export class CoreCourseFormatModule { }
|
|
@ -0,0 +1 @@
|
|||
<core-dynamic-component [component]="componentClass" [data]="data"></core-dynamic-component>
|
|
@ -0,0 +1,104 @@
|
|||
// (C) Copyright 2015 Moodle Pty Ltd.
|
||||
//
|
||||
// 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, SimpleChange, ViewChild, Output, EventEmitter, Type } from '@angular/core';
|
||||
|
||||
import { CoreCourseModuleDelegate } from '@features/course/services/module-delegate';
|
||||
import { CoreCourseUnsupportedModuleComponent } from '@features/course/components/unsupported-module/unsupported-module';
|
||||
import { CoreDynamicComponent } from '@components/dynamic-component/dynamic-component';
|
||||
import { CoreCourseAnyCourseData } from '@features/courses/services/courses';
|
||||
import { CoreCourseSection } from '@features/course/services/course';
|
||||
import { IonRefresher } from '@ionic/angular';
|
||||
|
||||
/**
|
||||
* 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',
|
||||
templateUrl: 'core-course-format-single-activity.html',
|
||||
})
|
||||
export class CoreCourseFormatSingleActivityComponent implements OnChanges {
|
||||
|
||||
@Input() course?: CoreCourseAnyCourseData; // The course to render.
|
||||
@Input() sections?: CoreCourseSection[]; // List of course sections.
|
||||
@Input() downloadEnabled?: boolean; // Whether the download of sections and modules is enabled.
|
||||
@Input() initialSectionId?: number; // The section to load first (by ID).
|
||||
@Input() initialSectionNumber?: number; // The section to load first (by number).
|
||||
@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.
|
||||
|
||||
@ViewChild(CoreDynamicComponent) dynamicComponent?: CoreDynamicComponent;
|
||||
|
||||
componentClass?: Type<unknown>; // The class of the component to render.
|
||||
data: Record<string | number, unknown> = {}; // Data to pass to the component.
|
||||
|
||||
/**
|
||||
* Detect changes on input properties.
|
||||
*/
|
||||
async ngOnChanges(changes: { [name: string]: SimpleChange }): Promise<void> {
|
||||
if (!changes.course || !changes.sections) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.course || !this.sections || !this.sections.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
// In single activity the module should only have 1 section and 1 module. Get the module.
|
||||
const module = this.sections?.[0].modules?.[0];
|
||||
|
||||
this.data.courseId = this.course.id;
|
||||
this.data.module = module;
|
||||
|
||||
if (module && !this.componentClass) {
|
||||
// We haven't obtained the class yet. Get it now.
|
||||
const component = await CoreCourseModuleDelegate.instance.getMainComponent(this.course, module);
|
||||
this.componentClass = component || CoreCourseUnsupportedModuleComponent;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Refresh the data.
|
||||
*
|
||||
* @param refresher Refresher.
|
||||
* @param done Function to call when done.
|
||||
* @param afterCompletionChange Whether the refresh is due to a completion change.
|
||||
* @return Promise resolved when done.
|
||||
*/
|
||||
async doRefresh(refresher?: CustomEvent<IonRefresher>, done?: () => void, afterCompletionChange?: boolean): Promise<void> {
|
||||
if (afterCompletionChange) {
|
||||
// Don't refresh the view after a completion change since completion isn't displayed.
|
||||
return;
|
||||
}
|
||||
|
||||
await this.dynamicComponent?.callComponentFunction('doRefresh', [refresher, done]);
|
||||
}
|
||||
|
||||
/**
|
||||
* User entered the page that contains the component.
|
||||
*/
|
||||
ionViewDidEnter(): void {
|
||||
this.dynamicComponent?.callComponentFunction('ionViewDidEnter');
|
||||
}
|
||||
|
||||
/**
|
||||
* User left the page that contains the component.
|
||||
*/
|
||||
ionViewDidLeave(): void {
|
||||
this.dynamicComponent?.callComponentFunction('ionViewDidLeave');
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,153 @@
|
|||
// (C) Copyright 2015 Moodle Pty Ltd.
|
||||
//
|
||||
// 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, Type } from '@angular/core';
|
||||
|
||||
import { CoreCourseSection } from '@features/course/services/course';
|
||||
import { CoreCourseFormatHandler } from '@features/course/services/format-delegate';
|
||||
import { CoreCourseModuleDelegate } from '@features/course/services/module-delegate';
|
||||
import { CoreCourseAnyCourseData } from '@features/courses/services/courses';
|
||||
import { CoreCourseFormatSingleActivityComponent } from '../../components/singleactivity';
|
||||
import { makeSingleton } from '@singletons';
|
||||
|
||||
/**
|
||||
* Handler to support singleactivity course format.
|
||||
*/
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class CoreCourseFormatSingleActivityHandlerService implements CoreCourseFormatHandler {
|
||||
|
||||
name = 'CoreCourseFormatSingleActivity';
|
||||
format = 'singleactivity';
|
||||
|
||||
/**
|
||||
* Whether or not the handler is enabled on a site level.
|
||||
*
|
||||
* @return True or promise resolved with true if enabled.
|
||||
*/
|
||||
async isEnabled(): Promise<boolean> {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether it allows seeing all sections at the same time. Defaults to true.
|
||||
*
|
||||
* @param course The course to check.
|
||||
* @return Whether it can view all sections.
|
||||
*/
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
canViewAllSections(course: CoreCourseAnyCourseData): boolean {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether the option blocks should be displayed. Defaults to true.
|
||||
*
|
||||
* @param course The course to check.
|
||||
* @return Whether it can display blocks.
|
||||
*/
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
displayBlocks(course: CoreCourseAnyCourseData): boolean {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the title to use in course page. If not defined, course displayname or fullname.
|
||||
* This function will be called without sections first, and then call it again when the sections are retrieved.
|
||||
*
|
||||
* @param course The course.
|
||||
* @param sections List of sections.
|
||||
* @return Title.
|
||||
*/
|
||||
getCourseTitle(course: CoreCourseAnyCourseData, sections?: CoreCourseSection[]): string {
|
||||
if (sections?.[0]?.modules?.[0]) {
|
||||
return sections[0].modules[0].name;
|
||||
}
|
||||
|
||||
if (course.displayname) {
|
||||
return course.displayname;
|
||||
} else if (course.fullname) {
|
||||
return course.fullname;
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether the option to enable section/module download should be displayed. Defaults to true.
|
||||
*
|
||||
* @param course The course to check.
|
||||
* @return Whether the option to enable section/module download should be displayed
|
||||
*/
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
displayEnableDownload(course: CoreCourseAnyCourseData): boolean {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether the default section selector should be displayed. Defaults to true.
|
||||
*
|
||||
* @param course The course to check.
|
||||
* @return Whether the default section selector should be displayed.
|
||||
*/
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
displaySectionSelector(course: CoreCourseAnyCourseData): boolean {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether the course refresher should be displayed. If it returns false, a refresher must be included in the course format,
|
||||
* and the doRefresh method of CoreCourseSectionPage must be called on refresh. Defaults to true.
|
||||
*
|
||||
* @param course The course to check.
|
||||
* @param sections List of course sections.
|
||||
* @return Whether the refresher should be displayed.
|
||||
*/
|
||||
displayRefresher(course: CoreCourseAnyCourseData, sections: CoreCourseSection[]): boolean {
|
||||
if (sections?.[0]?.modules?.[0]) {
|
||||
return CoreCourseModuleDelegate.instance.displayRefresherInSingleActivity(sections[0].modules[0].modname);
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* It's recommended to return the class of the component, but you can also return an instance of the component.
|
||||
*
|
||||
* @param injector Injector.
|
||||
* @param course The course to render.
|
||||
* @return The component (or promise resolved with component) to use, undefined if not found.
|
||||
*/
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
async getCourseFormatComponent(course: CoreCourseAnyCourseData): Promise<Type<unknown>> {
|
||||
return CoreCourseFormatSingleActivityComponent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether the view should be refreshed when completion changes. If your course format doesn't display
|
||||
* activity completion then you should return false.
|
||||
*
|
||||
* @param course The course.
|
||||
* @return Whether course view should be refreshed when an activity completion changes.
|
||||
*/
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
async shouldRefreshWhenCompletionChanges(course: CoreCourseAnyCourseData): Promise<boolean> {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export class CoreCourseFormatSingleActivityHandler extends makeSingleton(CoreCourseFormatSingleActivityHandlerService) {}
|
|
@ -0,0 +1,43 @@
|
|||
// (C) Copyright 2015 Moodle Pty Ltd.
|
||||
//
|
||||
// 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 { APP_INITIALIZER, NgModule } from '@angular/core';
|
||||
|
||||
import { CoreSharedModule } from '@/core/shared.module';
|
||||
import { CoreCourseFormatDelegate } from '@features/course/services/format-delegate';
|
||||
import { CoreCourseFormatSingleActivityComponent } from './components/singleactivity';
|
||||
import { CoreCourseFormatSingleActivityHandler } from './services/handlers/singleactivity-format';
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
CoreCourseFormatSingleActivityComponent,
|
||||
],
|
||||
imports: [
|
||||
CoreSharedModule,
|
||||
],
|
||||
providers: [
|
||||
{
|
||||
provide: APP_INITIALIZER,
|
||||
multi: true,
|
||||
deps: [],
|
||||
useFactory: () => () => {
|
||||
CoreCourseFormatDelegate.instance.registerHandler(CoreCourseFormatSingleActivityHandler.instance);
|
||||
},
|
||||
},
|
||||
],
|
||||
exports: [
|
||||
CoreCourseFormatSingleActivityComponent,
|
||||
],
|
||||
})
|
||||
export class CoreCourseFormatSingleActivityModule {}
|
|
@ -0,0 +1,32 @@
|
|||
// (C) Copyright 2015 Moodle Pty Ltd.
|
||||
//
|
||||
// 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 { makeSingleton } from '@singletons';
|
||||
|
||||
import { CoreCourseFormatSingleActivityHandlerService } from '../../../singleactivity/services/handlers/singleactivity-format';
|
||||
|
||||
/**
|
||||
* Handler to support social course format.
|
||||
* This format is like singleactivity in the mobile app, so we'll use the same implementation for both.
|
||||
*/
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class CoreCourseFormatSocialHandlerService extends CoreCourseFormatSingleActivityHandlerService {
|
||||
|
||||
name = 'CoreCourseFormatSocial';
|
||||
format = 'social';
|
||||
|
||||
}
|
||||
|
||||
export class CoreCourseFormatSocialHandler extends makeSingleton(CoreCourseFormatSocialHandlerService) {}
|
|
@ -0,0 +1,34 @@
|
|||
// (C) Copyright 2015 Moodle Pty Ltd.
|
||||
//
|
||||
// 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 { APP_INITIALIZER, NgModule } from '@angular/core';
|
||||
|
||||
import { CoreCourseFormatDelegate } from '@features/course/services/format-delegate';
|
||||
import { CoreCourseFormatSocialHandler } from './services/handlers/social-format';
|
||||
|
||||
@NgModule({
|
||||
declarations: [],
|
||||
imports: [],
|
||||
providers: [
|
||||
{
|
||||
provide: APP_INITIALIZER,
|
||||
multi: true,
|
||||
deps: [],
|
||||
useFactory: () => () => {
|
||||
CoreCourseFormatDelegate.instance.registerHandler(CoreCourseFormatSocialHandler.instance);
|
||||
},
|
||||
},
|
||||
],
|
||||
})
|
||||
export class CoreCourseFormatSocialModule {}
|
|
@ -0,0 +1,40 @@
|
|||
// (C) Copyright 2015 Moodle Pty Ltd.
|
||||
//
|
||||
// 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 '@features/course/services/format-delegate';
|
||||
import { makeSingleton } from '@singletons';
|
||||
|
||||
/**
|
||||
* Handler to support topics course format.
|
||||
*/
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class CoreCourseFormatTopicsHandlerService implements CoreCourseFormatHandler {
|
||||
|
||||
name = 'CoreCourseFormatTopics';
|
||||
format = 'topics';
|
||||
|
||||
/**
|
||||
* Whether or not the handler is enabled on a site level.
|
||||
*
|
||||
* @return True or promise resolved with true if enabled.
|
||||
*/
|
||||
async isEnabled(): Promise<boolean> {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export class CoreCourseFormatTopicsHandler extends makeSingleton(CoreCourseFormatTopicsHandlerService) {}
|
|
@ -0,0 +1,34 @@
|
|||
// (C) Copyright 2015 Moodle Pty Ltd.
|
||||
//
|
||||
// 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 { APP_INITIALIZER, NgModule } from '@angular/core';
|
||||
|
||||
import { CoreCourseFormatDelegate } from '@features/course/services/format-delegate';
|
||||
import { CoreCourseFormatTopicsHandler } from './services/handlers/topics-format';
|
||||
|
||||
@NgModule({
|
||||
declarations: [],
|
||||
imports: [],
|
||||
providers: [
|
||||
{
|
||||
provide: APP_INITIALIZER,
|
||||
multi: true,
|
||||
deps: [],
|
||||
useFactory: () => () => {
|
||||
CoreCourseFormatDelegate.instance.registerHandler(CoreCourseFormatTopicsHandler.instance);
|
||||
},
|
||||
},
|
||||
],
|
||||
})
|
||||
export class CoreCourseFormatTopicsModule {}
|
|
@ -0,0 +1,95 @@
|
|||
// (C) Copyright 2015 Moodle Pty Ltd.
|
||||
//
|
||||
// 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 { CoreTimeUtils } from '@services/utils/time';
|
||||
import { CoreCourseFormatHandler } from '@features/course/services/format-delegate';
|
||||
import { makeSingleton } from '@singletons';
|
||||
import { CoreCourseAnyCourseData } from '@features/courses/services/courses';
|
||||
import { CoreCourseSection } from '@features/course/services/course';
|
||||
import { CoreConstants } from '@/core/constants';
|
||||
|
||||
/**
|
||||
* Handler to support weeks course format.
|
||||
*/
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class CoreCourseFormatWeeksHandlerService implements CoreCourseFormatHandler {
|
||||
|
||||
name = 'CoreCourseFormatWeeks';
|
||||
format = 'weeks';
|
||||
|
||||
/**
|
||||
* Whether or not the handler is enabled on a site level.
|
||||
*
|
||||
* @return True or promise resolved with true if enabled.
|
||||
*/
|
||||
async isEnabled(): Promise<boolean> {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a list of sections, get the "current" section that should be displayed first.
|
||||
*
|
||||
* @param course The course to get the title.
|
||||
* @param sections List of sections.
|
||||
* @return Current section (or promise resolved with current section).
|
||||
*/
|
||||
async getCurrentSection(course: CoreCourseAnyCourseData, sections: CoreCourseSection[]): Promise<CoreCourseSection> {
|
||||
const now = CoreTimeUtils.instance.timestamp();
|
||||
|
||||
if ((course.startdate && now < course.startdate) || (course.enddate && now > course.enddate)) {
|
||||
// Course hasn't started yet or it has ended already. Return all sections.
|
||||
return sections[0];
|
||||
}
|
||||
|
||||
for (let i = 0; i < sections.length; i++) {
|
||||
const section = sections[i];
|
||||
if (typeof section.section == 'undefined' || section.section < 1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const dates = this.getSectionDates(section, course.startdate || 0);
|
||||
if (now >= dates.start && now < dates.end) {
|
||||
return section;
|
||||
}
|
||||
}
|
||||
|
||||
// The section wasn't found, return all sections.
|
||||
return sections[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the start and end date of a section.
|
||||
*
|
||||
* @param section The section to treat.
|
||||
* @param startDate The course start date (in seconds).
|
||||
* @return An object with the start and end date of the section.
|
||||
*/
|
||||
protected getSectionDates(section: CoreCourseSection, startDate: number): { start: number; end: number } {
|
||||
// Hack alert. We add 2 hours to avoid possible DST problems. (e.g. we go into daylight savings and the date changes).
|
||||
startDate = startDate + 7200;
|
||||
|
||||
const dates = {
|
||||
start: startDate + (CoreConstants.SECONDS_WEEK * (section.section! - 1)),
|
||||
end: 0,
|
||||
};
|
||||
dates.end = dates.start + CoreConstants.SECONDS_WEEK;
|
||||
|
||||
return dates;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export class CoreCourseFormatWeeksHandler extends makeSingleton(CoreCourseFormatWeeksHandlerService) {}
|
|
@ -0,0 +1,34 @@
|
|||
// (C) Copyright 2015 Moodle Pty Ltd.
|
||||
//
|
||||
// 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 { APP_INITIALIZER, NgModule } from '@angular/core';
|
||||
|
||||
import { CoreCourseFormatDelegate } from '@features/course/services/format-delegate';
|
||||
import { CoreCourseFormatWeeksHandler } from './services/handlers/weeks-format';
|
||||
|
||||
@NgModule({
|
||||
declarations: [],
|
||||
imports: [],
|
||||
providers: [
|
||||
{
|
||||
provide: APP_INITIALIZER,
|
||||
multi: true,
|
||||
deps: [],
|
||||
useFactory: () => () => {
|
||||
CoreCourseFormatDelegate.instance.registerHandler(CoreCourseFormatWeeksHandler.instance);
|
||||
},
|
||||
},
|
||||
],
|
||||
})
|
||||
export class CoreCourseFormatWeeksModule {}
|
|
@ -44,7 +44,7 @@ export const SITE_SCHEMA: CoreSiteSchema = {
|
|||
{
|
||||
name: 'time',
|
||||
type: 'INTEGER',
|
||||
}
|
||||
},
|
||||
],
|
||||
primaryKeys: ['component', 'componentid', 'ws', 'time'],
|
||||
},
|
||||
|
|
Loading…
Reference in New Issue