MOBILE-3915 course: Implement new course index
parent
1dd5eba1de
commit
86365d260d
|
@ -20,7 +20,7 @@ import { CoreCourseFormatComponent } from './format/format';
|
|||
import { CoreCourseModuleComponent } from './module/module';
|
||||
import { CoreCourseModuleCompletionComponent } from './module-completion/module-completion';
|
||||
import { CoreCourseModuleDescriptionComponent } from './module-description/module-description';
|
||||
import { CoreCourseSectionSelectorComponent } from './section-selector/section-selector';
|
||||
import { CoreCourseCourseIndexComponent } from './course-index/course-index';
|
||||
import { CoreCourseTagAreaComponent } from './tag-area/tag-area';
|
||||
import { CoreCourseUnsupportedModuleComponent } from './unsupported-module/unsupported-module';
|
||||
import { CoreCourseModuleCompletionLegacyComponent } from './module-completion-legacy/module-completion-legacy';
|
||||
|
@ -37,7 +37,7 @@ import { CoreCourseModuleNavigationComponent } from './module-navigation/module-
|
|||
CoreCourseModuleDescriptionComponent,
|
||||
CoreCourseModuleInfoComponent,
|
||||
CoreCourseModuleManualCompletionComponent,
|
||||
CoreCourseSectionSelectorComponent,
|
||||
CoreCourseCourseIndexComponent,
|
||||
CoreCourseTagAreaComponent,
|
||||
CoreCourseUnsupportedModuleComponent,
|
||||
CoreCourseModuleNavigationComponent,
|
||||
|
@ -54,7 +54,7 @@ import { CoreCourseModuleNavigationComponent } from './module-navigation/module-
|
|||
CoreCourseModuleDescriptionComponent,
|
||||
CoreCourseModuleInfoComponent,
|
||||
CoreCourseModuleManualCompletionComponent,
|
||||
CoreCourseSectionSelectorComponent,
|
||||
CoreCourseCourseIndexComponent,
|
||||
CoreCourseTagAreaComponent,
|
||||
CoreCourseUnsupportedModuleComponent,
|
||||
CoreCourseModuleNavigationComponent,
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<ion-header>
|
||||
<ion-toolbar>
|
||||
<ion-title>
|
||||
<h2 id="core-course-section-selector-label">{{ 'core.course.sections' | translate }}</h2>
|
||||
<h2 id="core-course-section-selector-label">{{ 'core.course.courseindex' | translate }}</h2>
|
||||
</ion-title>
|
||||
<ion-buttons slot="end">
|
||||
<ion-button fill="clear" (click)="closeModal()" [attr.aria-label]="'core.close' | translate">
|
||||
|
@ -13,10 +13,10 @@
|
|||
<ion-content>
|
||||
<ion-list id="core-course-section-selector" role="listbox" aria-labelledby="core-course-section-selector-label">
|
||||
<ng-container *ngFor="let section of sections">
|
||||
<ion-item *ngIf="!section.hiddenbynumsections && section.id != stealthModulesSectionId" class="ion-text-wrap"
|
||||
<ion-item-divider *ngIf="!section.hiddenbynumsections && section.id != stealthModulesSectionId" class="ion-text-wrap"
|
||||
(click)="selectSection(section)" [attr.aria-current]="selected?.id == section.id ? 'page' : 'false'"
|
||||
[class.item-dimmed]="section.visible === 0 || section.uservisible === false" detail="false"
|
||||
[attr.aria-hidden]="section.uservisible === false" button>
|
||||
[attr.aria-hidden]="section.uservisible === false" button sticky="true">
|
||||
|
||||
<ion-icon name="fas-folder" slot="start" aria-hidden="true"></ion-icon>
|
||||
<ion-label>
|
||||
|
@ -39,7 +39,24 @@
|
|||
</core-format-text>
|
||||
</ion-badge>
|
||||
</ion-label>
|
||||
</ion-item-divider>
|
||||
<ng-container *ngFor="let module of section.modules">
|
||||
<ion-item *ngIf="module.visibleoncoursepage !== 0" class="ion-text-wrap">
|
||||
<!-- TODO Add Aria, styles when disabled, etc. -->
|
||||
<ion-icon name="" *ngIf="module.completionStatus === undefined" slot="start"></ion-icon>
|
||||
<ion-icon name="far-circle" *ngIf="module.completionStatus === 0" slot="start"></ion-icon>
|
||||
<ion-icon name="fas-circle" *ngIf="module.completionStatus === 1" color="success" slot="start"></ion-icon>
|
||||
<ion-icon name="fas-circle" *ngIf="module.completionStatus === 2" color="success" slot="start"></ion-icon>
|
||||
<ion-icon name="fas-circle" *ngIf="module.completionStatus === 3" color="danger" slot="start"></ion-icon>
|
||||
<ion-label>
|
||||
<p class="item-heading">
|
||||
<core-format-text [text]="module.name" contextLevel="module" [contextInstanceId]="module.id"
|
||||
[courseId]="module.courseid">
|
||||
</core-format-text>
|
||||
</p>
|
||||
</ion-label>
|
||||
</ion-item>
|
||||
</ng-container>
|
||||
</ng-container>
|
||||
</ion-list>
|
||||
</ion-content>
|
|
@ -14,7 +14,7 @@
|
|||
|
||||
import { Component, Input, OnInit } from '@angular/core';
|
||||
|
||||
import { CoreCourseSection } from '@features/course/services/course-helper';
|
||||
import { CoreCourseModuleData, CoreCourseSection, CoreCourseSectionWithStatus } from '@features/course/services/course-helper';
|
||||
import {
|
||||
CoreCourseModuleCompletionStatus,
|
||||
CoreCourseModuleCompletionTracking,
|
||||
|
@ -25,14 +25,14 @@ import { CoreUtils } from '@services/utils/utils';
|
|||
import { ModalController } from '@singletons';
|
||||
|
||||
/**
|
||||
* Component to display course section selector in a modal.
|
||||
* Component to display course index modal.
|
||||
*/
|
||||
@Component({
|
||||
selector: 'core-course-section-selector',
|
||||
templateUrl: 'section-selector.html',
|
||||
styleUrls: ['section-selector.scss'],
|
||||
selector: 'core-course-course-index',
|
||||
templateUrl: 'course-index.html',
|
||||
styleUrls: ['course-index.scss'],
|
||||
})
|
||||
export class CoreCourseSectionSelectorComponent implements OnInit {
|
||||
export class CoreCourseCourseIndexComponent implements OnInit {
|
||||
|
||||
@Input() sections?: SectionWithProgress[];
|
||||
@Input() selected?: CoreCourseSection;
|
||||
|
@ -41,7 +41,7 @@ export class CoreCourseSectionSelectorComponent implements OnInit {
|
|||
stealthModulesSectionId = CoreCourseProvider.STEALTH_MODULES_SECTION_ID;
|
||||
|
||||
/**
|
||||
* Component being initialized.
|
||||
* @inheritdoc
|
||||
*/
|
||||
ngOnInit(): void {
|
||||
|
||||
|
@ -52,7 +52,7 @@ export class CoreCourseSectionSelectorComponent implements OnInit {
|
|||
|
||||
const formatOptions = CoreUtils.objectToKeyValueMap(this.course.courseformatoptions, 'name', 'value');
|
||||
|
||||
if (!formatOptions || formatOptions.coursedisplay != 1 || formatOptions.completionusertracked === false) {
|
||||
if (!formatOptions || formatOptions.completionusertracked === false) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -60,11 +60,16 @@ export class CoreCourseSectionSelectorComponent implements OnInit {
|
|||
let complete = 0;
|
||||
let total = 0;
|
||||
section.modules.forEach((module) => {
|
||||
console.error(module);
|
||||
if (!module.uservisible || module.completiondata === undefined ||
|
||||
module.completiondata.tracking == CoreCourseModuleCompletionTracking.COMPLETION_TRACKING_NONE) {
|
||||
module.completionStatus = undefined;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
module.completionStatus = module.completiondata.state;
|
||||
|
||||
total++;
|
||||
if (module.completiondata.state == CoreCourseModuleCompletionStatus.COMPLETION_COMPLETE ||
|
||||
module.completiondata.state == CoreCourseModuleCompletionStatus.COMPLETION_COMPLETE_PASS) {
|
||||
|
@ -98,6 +103,9 @@ export class CoreCourseSectionSelectorComponent implements OnInit {
|
|||
|
||||
}
|
||||
|
||||
type SectionWithProgress = CoreCourseSection & {
|
||||
type SectionWithProgress = Omit<CoreCourseSectionWithStatus, 'modules'> & {
|
||||
progress?: number;
|
||||
modules: (CoreCourseModuleData & {
|
||||
completionStatus?: CoreCourseModuleCompletionStatus;
|
||||
})[];
|
||||
};
|
|
@ -1,8 +1,8 @@
|
|||
<!-- Buttons to add to the header. *ngIf is needed, otherwise the component is executed too soon and doesn't find the header. -->
|
||||
<core-navbar-buttons slot="end" *ngIf="loaded">
|
||||
<core-context-menu>
|
||||
<core-context-menu-item [hidden]="!displaySectionSelector || !sections || !sections.length" [priority]="500"
|
||||
[content]="'core.course.sections' | translate" (action)="showSectionSelector()" iconAction="menu">
|
||||
<core-context-menu-item [hidden]="!displayCourseIndex || !sections || !sections.length" [priority]="500"
|
||||
[content]="'core.course.courseindex' | translate" (action)="openCourseIndex()" iconAction="menu">
|
||||
</core-context-menu-item>
|
||||
</core-context-menu>
|
||||
</core-navbar-buttons>
|
||||
|
@ -32,46 +32,6 @@
|
|||
<ion-icon name="fas-info-circle" slot="icon-only" aria-hidden="true"></ion-icon>
|
||||
</ion-button>
|
||||
</ion-item>
|
||||
<ion-item *ngIf="selectedSection && selectedSection.id != allSectionsId" class="ion-text-wrap">
|
||||
<ion-icon name="fas-folder" aria-label="hidden" slot="start"></ion-icon>
|
||||
<ion-label>
|
||||
<p class="item-heading">
|
||||
<core-format-text *ngIf="selectedSection" [text]="selectedSection.name" contextLevel="course"
|
||||
[contextInstanceId]="course.id" [clean]="true" [singleLine]="true">
|
||||
</core-format-text>
|
||||
</p>
|
||||
<ion-badge color="info" class="ion-text-wrap"
|
||||
*ngIf="selectedSection.visible === 0 && selectedSection.uservisible !== false">
|
||||
{{ 'core.course.hiddenfromstudents' | translate }}
|
||||
</ion-badge>
|
||||
<ion-badge color="info" class="ion-text-wrap"
|
||||
*ngIf="selectedSection.visible === 0 && selectedSection.uservisible === false">
|
||||
{{ 'core.notavailable' | translate }}
|
||||
</ion-badge>
|
||||
<ion-badge color="info" class="ion-text-wrap" *ngIf="selectedSection.availabilityinfo">
|
||||
<core-format-text [text]="selectedSection.availabilityinfo" contextLevel="course" [contextInstanceId]="course.id">
|
||||
</core-format-text>
|
||||
</ion-badge>
|
||||
</ion-label>
|
||||
</ion-item>
|
||||
</core-dynamic-component>
|
||||
|
||||
<!-- Section selector. -->
|
||||
<core-dynamic-component [component]="sectionSelectorComponent" [data]="data">
|
||||
<div *ngIf="displaySectionSelector && sections && hasSeveralSections"
|
||||
class="ion-text-wrap ion-justify-content-between ion-align-items-center core-button-selector-row">
|
||||
<core-combobox [modalOptions]="sectionSelectorModalOptions" interface="modal" listboxId="core-course-section-button"
|
||||
icon="fas-folder" [label]="'core.course.section' | translate"
|
||||
[selection]="selectedSection ? selectedSection.name : 'core.course.sections' | translate"
|
||||
(onChange)="sectionChanged($event)">
|
||||
<span slot="text">
|
||||
<core-format-text *ngIf="selectedSection" [text]="selectedSection.name" contextLevel="course"
|
||||
[contextInstanceId]="course.id" [clean]="true" [singleLine]="true">
|
||||
</core-format-text>
|
||||
<ng-container *ngIf="!selectedSection">{{ 'core.course.sections' | translate }}</ng-container>
|
||||
</span>
|
||||
</core-combobox>
|
||||
</div>
|
||||
</core-dynamic-component>
|
||||
|
||||
<!-- Single section. -->
|
||||
|
@ -98,7 +58,7 @@
|
|||
</div>
|
||||
|
||||
<ion-buttons class="ion-padding core-course-section-nav-buttons safe-area-padding-horizontal"
|
||||
*ngIf="displaySectionSelector && sections?.length">
|
||||
*ngIf="displayCourseIndex && sections?.length">
|
||||
<ion-button *ngIf="previousSection" (click)="sectionChanged(previousSection)" fill="outline" color="primary"
|
||||
[attr.aria-label]="('core.previous' | translate) + ': ' + previousSection.name">
|
||||
<ion-icon name="fas-chevron-left" slot="icon-only" aria-hidden="true"></ion-icon>
|
||||
|
@ -115,17 +75,25 @@
|
|||
|
||||
<core-block-side-blocks-button *ngIf="course && displayBlocks && hasBlocks" [courseId]="course.id">
|
||||
</core-block-side-blocks-button>
|
||||
|
||||
</core-loading>
|
||||
</core-dynamic-component>
|
||||
|
||||
<!-- Course Index button. -->
|
||||
<ion-fab slot="fixed" core-fab vertical="bottom" horizontal="end" *ngIf="displayCourseIndex">
|
||||
<ion-fab-button (click)="openCourseIndex()" [attr.aria-label]="'core.course.courseindex' | translate">
|
||||
<ion-icon name="fas-list-ul" aria-hidden="true"></ion-icon>
|
||||
<span class="sr-only">{{'core.course.courseindex' | translate }}</span>
|
||||
</ion-fab-button>
|
||||
</ion-fab>
|
||||
|
||||
<!-- Template to render a section. -->
|
||||
<ng-template #sectionTemplate let-section="section">
|
||||
<section *ngIf="!section.hiddenbynumsections && section.id != allSectionsId && section.id != stealthModulesSectionId">
|
||||
<!-- Title is only displayed when viewing all sections. -->
|
||||
<ion-item-divider *ngIf="selectedSection?.id == allSectionsId && section.name" class="ion-text-wrap" color="light"
|
||||
[class.item-dimmed]="section.visible === 0 || section.uservisible === false">
|
||||
<ion-item-divider class="ion-text-wrap" color="light" [class.item-dimmed]="section.visible === 0 || section.uservisible === false">
|
||||
<ion-icon name="fas-folder" aria-label="hidden" slot="start"></ion-icon>
|
||||
<ion-label>
|
||||
<h2>
|
||||
<h2 *ngIf="section.name">
|
||||
<core-format-text [text]="section.name" contextLevel="course" [contextInstanceId]="course.id">
|
||||
</core-format-text>
|
||||
</h2>
|
||||
|
|
|
@ -26,7 +26,6 @@ import {
|
|||
Type,
|
||||
ElementRef,
|
||||
} from '@angular/core';
|
||||
import { ModalOptions } from '@ionic/core';
|
||||
import { CoreDomUtils } from '@services/utils/dom';
|
||||
import { CoreDynamicComponent } from '@components/dynamic-component/dynamic-component';
|
||||
import { CoreCourseAnyCourseData } from '@features/courses/services/courses';
|
||||
|
@ -45,7 +44,7 @@ import { CoreCourseFormatDelegate } from '@features/course/services/format-deleg
|
|||
import { CoreEventObserver, CoreEvents } from '@singletons/events';
|
||||
import { IonContent, IonRefresher } from '@ionic/angular';
|
||||
import { CoreUtils } from '@services/utils/utils';
|
||||
import { CoreCourseSectionSelectorComponent } from '../section-selector/section-selector';
|
||||
import { CoreCourseCourseIndexComponent } from '../course-index/course-index';
|
||||
import { CoreBlockHelper } from '@features/block/services/block-helper';
|
||||
import { CoreNavigator } from '@services/navigator';
|
||||
|
||||
|
@ -80,7 +79,6 @@ export class CoreCourseFormatComponent implements OnInit, OnChanges, OnDestroy {
|
|||
// All the possible component classes.
|
||||
courseFormatComponent?: Type<unknown>;
|
||||
courseSummaryComponent?: Type<unknown>;
|
||||
sectionSelectorComponent?: Type<unknown>;
|
||||
singleSectionComponent?: Type<unknown>;
|
||||
allSectionsComponent?: Type<unknown>;
|
||||
|
||||
|
@ -88,7 +86,7 @@ export class CoreCourseFormatComponent implements OnInit, OnChanges, OnDestroy {
|
|||
showSectionId = 0;
|
||||
data: Record<string, unknown> = {}; // Data to pass to the components.
|
||||
|
||||
displaySectionSelector = false;
|
||||
displayCourseIndex = false;
|
||||
displayBlocks = false;
|
||||
hasBlocks = false;
|
||||
selectedSection?: CoreCourseSection;
|
||||
|
@ -97,17 +95,11 @@ export class CoreCourseFormatComponent implements OnInit, OnChanges, OnDestroy {
|
|||
allSectionsId: number = CoreCourseProvider.ALL_SECTIONS_ID;
|
||||
stealthModulesSectionId: number = CoreCourseProvider.STEALTH_MODULES_SECTION_ID;
|
||||
loaded = false;
|
||||
hasSeveralSections?: boolean;
|
||||
imageThumb?: string;
|
||||
progress?: number;
|
||||
sectionSelectorModalOptions: ModalOptions = {
|
||||
component: CoreCourseSectionSelectorComponent,
|
||||
componentProps: {},
|
||||
};
|
||||
|
||||
protected selectTabObserver?: CoreEventObserver;
|
||||
protected lastCourseFormat?: string;
|
||||
protected sectionSelectorExpanded = false;
|
||||
|
||||
constructor(
|
||||
protected content: IonContent,
|
||||
|
@ -154,14 +146,12 @@ export class CoreCourseFormatComponent implements OnInit, OnChanges, OnDestroy {
|
|||
*/
|
||||
async ngOnChanges(changes: { [name: string]: SimpleChange }): Promise<void> {
|
||||
this.setInputData();
|
||||
this.sectionSelectorModalOptions.componentProps!.course = this.course;
|
||||
this.sectionSelectorModalOptions.componentProps!.sections = this.sections;
|
||||
|
||||
if (changes.course && this.course) {
|
||||
// Course has changed, try to get the components.
|
||||
this.getComponents();
|
||||
|
||||
this.displaySectionSelector = CoreCourseFormatDelegate.displaySectionSelector(this.course);
|
||||
this.displayCourseIndex = CoreCourseFormatDelegate.displaySectionSelector(this.course);
|
||||
this.displayBlocks = CoreCourseFormatDelegate.displayBlocks(this.course);
|
||||
|
||||
this.hasBlocks = await CoreBlockHelper.hasCourseBlocks(this.course.id);
|
||||
|
@ -174,7 +164,6 @@ export class CoreCourseFormatComponent implements OnInit, OnChanges, OnDestroy {
|
|||
}
|
||||
|
||||
if (changes.sections && this.sections) {
|
||||
this.sectionSelectorModalOptions.componentProps!.sections = this.sections;
|
||||
this.treatSections(this.sections);
|
||||
}
|
||||
}
|
||||
|
@ -205,7 +194,6 @@ export class CoreCourseFormatComponent implements OnInit, OnChanges, OnDestroy {
|
|||
await Promise.all([
|
||||
this.loadCourseFormatComponent(),
|
||||
this.loadCourseSummaryComponent(),
|
||||
this.loadSectionSelectorComponent(),
|
||||
this.loadSingleSectionComponent(),
|
||||
this.loadAllSectionsComponent(),
|
||||
]);
|
||||
|
@ -229,15 +217,6 @@ export class CoreCourseFormatComponent implements OnInit, OnChanges, OnDestroy {
|
|||
this.courseSummaryComponent = await CoreCourseFormatDelegate.getCourseSummaryComponent(this.course);
|
||||
}
|
||||
|
||||
/**
|
||||
* Load section selector component.
|
||||
*
|
||||
* @return Promise resolved when done.
|
||||
*/
|
||||
protected async loadSectionSelectorComponent(): Promise<void> {
|
||||
this.sectionSelectorComponent = await CoreCourseFormatDelegate.getSectionSelectorComponent(this.course);
|
||||
}
|
||||
|
||||
/**
|
||||
* Load single section component.
|
||||
*
|
||||
|
@ -264,7 +243,7 @@ export class CoreCourseFormatComponent implements OnInit, OnChanges, OnDestroy {
|
|||
*/
|
||||
protected async treatSections(sections: CoreCourseSection[]): Promise<void> {
|
||||
const hasAllSections = sections[0].id == CoreCourseProvider.ALL_SECTIONS_ID;
|
||||
this.hasSeveralSections = sections.length > 2 || (sections.length == 2 && !hasAllSections);
|
||||
const hasSeveralSections = sections.length > 2 || (sections.length == 2 && !hasAllSections);
|
||||
|
||||
if (this.selectedSection) {
|
||||
// We have a selected section, but the list has changed. Search the section in the list.
|
||||
|
@ -281,7 +260,7 @@ export class CoreCourseFormatComponent implements OnInit, OnChanges, OnDestroy {
|
|||
}
|
||||
|
||||
// There is no selected section yet, calculate which one to load.
|
||||
if (!this.hasSeveralSections) {
|
||||
if (!hasSeveralSections) {
|
||||
// Always load "All sections" to display the section title. If it isn't there just load the section.
|
||||
this.loaded = true;
|
||||
this.sectionChanged(sections[0]);
|
||||
|
@ -309,18 +288,18 @@ export class CoreCourseFormatComponent implements OnInit, OnChanges, OnDestroy {
|
|||
}
|
||||
|
||||
/**
|
||||
* Display the section selector modal.
|
||||
* Display the course index modal.
|
||||
*/
|
||||
async showSectionSelector(): Promise<void> {
|
||||
if (this.sectionSelectorExpanded) {
|
||||
return;
|
||||
}
|
||||
async openCourseIndex(): Promise<void> {
|
||||
const data = await CoreDomUtils.openModal<CoreCourseSection>({
|
||||
component: CoreCourseCourseIndexComponent,
|
||||
componentProps: {
|
||||
course: this.course,
|
||||
sections: this.sections,
|
||||
selected: this.selectedSection,
|
||||
},
|
||||
});
|
||||
|
||||
this.sectionSelectorExpanded = true;
|
||||
|
||||
const data = await CoreDomUtils.openModal<CoreCourseSection>(this.sectionSelectorModalOptions);
|
||||
|
||||
this.sectionSelectorExpanded = false;
|
||||
if (data) {
|
||||
this.sectionChanged(data);
|
||||
}
|
||||
|
@ -334,7 +313,6 @@ export class CoreCourseFormatComponent implements OnInit, OnChanges, OnDestroy {
|
|||
sectionChanged(newSection: CoreCourseSection): void {
|
||||
const previousValue = this.selectedSection;
|
||||
this.selectedSection = newSection;
|
||||
this.sectionSelectorModalOptions.componentProps!.selected = this.selectedSection;
|
||||
this.data.section = this.selectedSection;
|
||||
|
||||
if (newSection.id != this.allSectionsId) {
|
||||
|
|
|
@ -52,31 +52,29 @@ export class CoreCourseModuleCompletionLegacyComponent extends CoreCourseModuleC
|
|||
let langKey: string | undefined;
|
||||
let image: string | undefined;
|
||||
|
||||
if (this.completion.tracking === CoreCourseModuleCompletionTracking.COMPLETION_TRACKING_MANUAL &&
|
||||
this.completion.state === CoreCourseModuleCompletionStatus.COMPLETION_INCOMPLETE) {
|
||||
if (this.completion.tracking === CoreCourseModuleCompletionTracking.COMPLETION_TRACKING_MANUAL) {
|
||||
if (this.completion.state === CoreCourseModuleCompletionStatus.COMPLETION_INCOMPLETE) {
|
||||
image = 'completion-manual-n';
|
||||
langKey = 'core.completion-alt-manual-n';
|
||||
} else if (this.completion.tracking === CoreCourseModuleCompletionTracking.COMPLETION_TRACKING_MANUAL &&
|
||||
this.completion.state === CoreCourseModuleCompletionStatus.COMPLETION_COMPLETE) {
|
||||
} else if (this.completion.state === CoreCourseModuleCompletionStatus.COMPLETION_COMPLETE) {
|
||||
image = 'completion-manual-y';
|
||||
langKey = 'core.completion-alt-manual-y';
|
||||
} else if (this.completion.tracking === CoreCourseModuleCompletionTracking.COMPLETION_TRACKING_AUTOMATIC &&
|
||||
this.completion.state === CoreCourseModuleCompletionStatus.COMPLETION_INCOMPLETE) {
|
||||
}
|
||||
} else if (this.completion.tracking === CoreCourseModuleCompletionTracking.COMPLETION_TRACKING_AUTOMATIC) {
|
||||
if (this.completion.state === CoreCourseModuleCompletionStatus.COMPLETION_INCOMPLETE) {
|
||||
image = 'completion-auto-n';
|
||||
langKey = 'core.completion-alt-auto-n';
|
||||
} else if (this.completion.tracking === CoreCourseModuleCompletionTracking.COMPLETION_TRACKING_AUTOMATIC &&
|
||||
this.completion.state === CoreCourseModuleCompletionStatus.COMPLETION_COMPLETE) {
|
||||
} else if (this.completion.state === CoreCourseModuleCompletionStatus.COMPLETION_COMPLETE) {
|
||||
image = 'completion-auto-y';
|
||||
langKey = 'core.completion-alt-auto-y';
|
||||
} else if (this.completion.tracking === CoreCourseModuleCompletionTracking.COMPLETION_TRACKING_AUTOMATIC &&
|
||||
this.completion.state === CoreCourseModuleCompletionStatus.COMPLETION_COMPLETE_PASS) {
|
||||
} else if (this.completion.state === CoreCourseModuleCompletionStatus.COMPLETION_COMPLETE_PASS) {
|
||||
image = 'completion-auto-pass';
|
||||
langKey = 'core.completion-alt-auto-pass';
|
||||
} else if (this.completion.tracking === CoreCourseModuleCompletionTracking.COMPLETION_TRACKING_AUTOMATIC &&
|
||||
this.completion.state === CoreCourseModuleCompletionStatus.COMPLETION_COMPLETE_FAIL) {
|
||||
} else if (this.completion.state === CoreCourseModuleCompletionStatus.COMPLETION_COMPLETE_FAIL) {
|
||||
image = 'completion-auto-fail';
|
||||
langKey = 'core.completion-alt-auto-fail';
|
||||
}
|
||||
}
|
||||
|
||||
if (image) {
|
||||
if (this.completion.overrideby && this.completion.overrideby > 0) {
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
"confirmdownloadzerosize": "You are about to start downloading.{{availableSpace}} Are you sure you want to continue?",
|
||||
"confirmpartialdownloadsize": "You are about to download <strong>at least</strong> {{size}}.{{availableSpace}} Are you sure you want to continue?",
|
||||
"confirmlimiteddownload": "You are not currently connected to Wi-Fi. ",
|
||||
"courseindex": "Course index",
|
||||
"gotonextactivity": "Continue to next activity",
|
||||
"gotonextactivitynotfound": "Next activity not found. It's possible that it has been hidden or deleted.",
|
||||
"gotopreviousactivity": "Continue to previous activity",
|
||||
|
@ -49,7 +50,6 @@
|
|||
"overriddennotice": "Your final grade from this activity was manually adjusted.",
|
||||
"refreshcourse": "Refresh course",
|
||||
"section": "Section",
|
||||
"sections": "Sections",
|
||||
"useactivityonbrowser": "You can still use it using your device's web browser.",
|
||||
"warningmanualcompletionmodified": "The manual completion of an activity was modified on the site.",
|
||||
"warningofflinemanualcompletiondeleted": "Some offline manual completion of course '{{name}}' has been deleted. {{error}}"
|
||||
|
|
|
@ -62,7 +62,7 @@ declare module '@singletons/events' {
|
|||
}
|
||||
|
||||
/**
|
||||
* Completion status valid values.
|
||||
* Course Module completion status enumeration.
|
||||
*/
|
||||
export enum CoreCourseModuleCompletionStatus {
|
||||
COMPLETION_INCOMPLETE = 0,
|
||||
|
|
|
@ -125,15 +125,6 @@ export interface CoreCourseFormatHandler extends CoreDelegateHandler {
|
|||
*/
|
||||
getCourseSummaryComponent?(course: CoreCourseAnyCourseData): Promise<Type<unknown> | undefined>;
|
||||
|
||||
/**
|
||||
* Return the Component to use to display the section selector inside the default course format.
|
||||
* It's recommended to return the class of the component, but you can also return an instance of the component.
|
||||
*
|
||||
* @param course The course to render.
|
||||
* @return Promise resolved with component to use, undefined if not found.
|
||||
*/
|
||||
getSectionSelectorComponent?(course: CoreCourseAnyCourseData): Promise<Type<unknown> | undefined>;
|
||||
|
||||
/**
|
||||
* Return the Component to use to display a single section. This component will only be used if the user is viewing a
|
||||
* single section. If all the sections are displayed at once then it won't be used.
|
||||
|
@ -302,20 +293,6 @@ export class CoreCourseFormatDelegateService extends CoreDelegate<CoreCourseForm
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the component to use to display the section selector inside the default course format.
|
||||
*
|
||||
* @param course The course to render.
|
||||
* @return Promise resolved with component to use, undefined if not found.
|
||||
*/
|
||||
async getSectionSelectorComponent(course: CoreCourseAnyCourseData): Promise<Type<unknown> | undefined> {
|
||||
try {
|
||||
return await this.executeFunctionOnEnabled<Type<unknown>>(course.format || '', 'getSectionSelectorComponent', [course]);
|
||||
} catch (error) {
|
||||
this.logger.error('Error getting section selector component', error);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the component to use to display a single section. This component will only be used if the user is viewing
|
||||
* a single section. If all the sections are displayed at once then it won't be used.
|
||||
|
|
Loading…
Reference in New Issue