MOBILE-4442 course: Manage subsections on course index page
parent
aad989982d
commit
cb9580b73e
|
@ -488,6 +488,7 @@ export class CoreCourseFormatComponent implements OnInit, OnChanges, OnDestroy {
|
||||||
componentProps: {
|
componentProps: {
|
||||||
course: this.course,
|
course: this.course,
|
||||||
sections: this.sections,
|
sections: this.sections,
|
||||||
|
subSections: this.subSections,
|
||||||
selectedId: selectedId,
|
selectedId: selectedId,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
@ -495,12 +496,25 @@ export class CoreCourseFormatComponent implements OnInit, OnChanges, OnDestroy {
|
||||||
if (!data) {
|
if (!data) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const section = this.sections.find((section) => section.id === data.sectionId);
|
let section = this.sections.find((section) => section.id === data.sectionId);
|
||||||
if (!section) {
|
if (!section) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.sectionChanged(section);
|
this.sectionChanged(section);
|
||||||
|
|
||||||
|
if (data.subSectionId) {
|
||||||
|
section = this.subSections.find((section) => section.id === data.subSectionId);
|
||||||
|
if (!section) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use this section to find the module.
|
||||||
|
this.setSectionExpanded(section);
|
||||||
|
|
||||||
|
// Scroll to the subsection (later it may be scrolled to the module).
|
||||||
|
this.scrollInCourse(section.id, true);
|
||||||
|
}
|
||||||
|
|
||||||
if (!data.moduleId) {
|
if (!data.moduleId) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -515,7 +529,7 @@ export class CoreCourseFormatComponent implements OnInit, OnChanges, OnDestroy {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (CoreCourseHelper.canUserViewModule(module, section)) {
|
if (CoreCourseHelper.canUserViewModule(module, section)) {
|
||||||
this.scrollToModule(module.id);
|
this.scrollInCourse(module.id);
|
||||||
|
|
||||||
module.handlerData?.action?.(data.event, module, module.course);
|
module.handlerData?.action?.(data.event, module, module.course);
|
||||||
}
|
}
|
||||||
|
@ -585,7 +599,7 @@ export class CoreCourseFormatComponent implements OnInit, OnChanges, OnDestroy {
|
||||||
// Scroll to module if needed. Give more priority to the input.
|
// Scroll to module if needed. Give more priority to the input.
|
||||||
const moduleIdToScroll = this.moduleId && previousValue === undefined ? this.moduleId : moduleId;
|
const moduleIdToScroll = this.moduleId && previousValue === undefined ? this.moduleId : moduleId;
|
||||||
if (moduleIdToScroll) {
|
if (moduleIdToScroll) {
|
||||||
this.scrollToModule(moduleIdToScroll);
|
this.scrollInCourse(moduleIdToScroll);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!previousValue || previousValue.id !== newSection.id) {
|
if (!previousValue || previousValue.id !== newSection.id) {
|
||||||
|
@ -600,16 +614,14 @@ export class CoreCourseFormatComponent implements OnInit, OnChanges, OnDestroy {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Scroll to a certain module.
|
* Scroll to a certain module or section.
|
||||||
*
|
*
|
||||||
* @param moduleId Module ID.
|
* @param id ID of the module or section to scroll to.
|
||||||
|
* @param isSection Whether to scroll to a module or a subsection.
|
||||||
*/
|
*/
|
||||||
protected scrollToModule(moduleId: number): void {
|
protected scrollInCourse(id: number, isSection = false): void {
|
||||||
CoreDom.scrollToElement(
|
const elementId = isSection ? `#core-section-name-${id}` : `#core-course-module-${id}`;
|
||||||
this.elementRef.nativeElement,
|
CoreDom.scrollToElement(this.elementRef.nativeElement, elementId,{ addYAxis: -10 });
|
||||||
'#core-course-module-' + moduleId,
|
|
||||||
{ addYAxis: -10 },
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -24,16 +24,23 @@
|
||||||
</ion-label>
|
</ion-label>
|
||||||
</ion-item>
|
</ion-item>
|
||||||
<ng-container *ngIf="allSectionId !== section.id">
|
<ng-container *ngIf="allSectionId !== section.id">
|
||||||
|
<ng-container *ngTemplateOutlet="sectionTemplate; context: {section}" />
|
||||||
|
</ng-container>
|
||||||
|
</ng-container>
|
||||||
|
</ion-list>
|
||||||
|
</core-loading>
|
||||||
|
</ion-content>
|
||||||
|
|
||||||
|
|
||||||
|
<ng-template #sectionTemplate let-section="section">
|
||||||
<ion-item class="divider section" (click)="selectSectionOrModule($event, section.id)" button
|
<ion-item class="divider section" (click)="selectSectionOrModule($event, section.id)" button
|
||||||
[class.item-current]="selectedId === section.id" [class.item-dimmed]="!section.visible"
|
[class.item-current]="selectedId === section.id" [class.item-dimmed]="!section.visible"
|
||||||
[class.item-hightlighted]="section.highlighted" [detail]="false">
|
[class.item-hightlighted]="section.highlighted" [detail]="false">
|
||||||
<ion-icon *ngIf="section.hasVisibleModules" name="fas-chevron-right" flip-rtl slot="start"
|
<ion-icon *ngIf="section.hasVisibleModules" name="fas-chevron-right" flip-rtl slot="start" class="expandable-status-icon"
|
||||||
class="expandable-status-icon" (ariaButtonClick)="toggleExpand($event, section)"
|
(ariaButtonClick)="toggleExpand($event, section)"
|
||||||
[attr.aria-label]="(section.expanded ? 'core.collapse' : 'core.expand') | translate"
|
[attr.aria-label]="(section.expanded ? 'core.collapse' : 'core.expand') | translate" [attr.aria-expanded]="section.expanded"
|
||||||
[attr.aria-expanded]="section.expanded" [attr.aria-controls]="'core-course-index-section-' + section.id"
|
[attr.aria-controls]="'core-course-index-section-' + section.id" [class.expandable-status-icon-expanded]="section.expanded" />
|
||||||
[class.expandable-status-icon-expanded]="section.expanded" />
|
<ion-icon *ngIf="!section.hasVisibleModules" name="" slot="start" aria-hidden="true" class="expandable-status-icon" />
|
||||||
<ion-icon *ngIf="!section.hasVisibleModules" name="" slot="start" aria-hidden="true"
|
|
||||||
class="expandable-status-icon" />
|
|
||||||
<ion-label>
|
<ion-label>
|
||||||
<h2>
|
<h2>
|
||||||
<core-format-text [text]="section.name" contextLevel="course" [contextInstanceId]="course?.id" />
|
<core-format-text [text]="section.name" contextLevel="course" [contextInstanceId]="course?.id" />
|
||||||
|
@ -47,22 +54,25 @@
|
||||||
<ion-icon name="fas-eye-slash" *ngIf="!section.visible && section.uservisible" slot="end" class="restricted"
|
<ion-icon name="fas-eye-slash" *ngIf="!section.visible && section.uservisible" slot="end" class="restricted"
|
||||||
[attr.aria-label]="'core.course.hiddenfromstudents' | translate" />
|
[attr.aria-label]="'core.course.hiddenfromstudents' | translate" />
|
||||||
</ion-item>
|
</ion-item>
|
||||||
<div id="core-course-index-section-{{section.id}}">
|
<div id="core-course-index-section-{{section.id}}" class="core-course-index-section-content">
|
||||||
<ng-container *ngIf="section.expanded">
|
<ng-container *ngIf="section.expanded">
|
||||||
<ng-container *ngFor="let module of section.modules">
|
<ng-container *ngFor="let module of section.modules">
|
||||||
|
@if (module.subSection) {
|
||||||
|
<div class="core-course-index-subsection">
|
||||||
|
<ng-container *ngTemplateOutlet="sectionTemplate; context: {section: module.subSection}" />
|
||||||
|
</div>
|
||||||
|
} @else {
|
||||||
<ion-item class="module" [class.item-dimmed]="!module.visible" [class.indented]="module.indented"
|
<ion-item class="module" [class.item-dimmed]="!module.visible" [class.indented]="module.indented"
|
||||||
[class.item-hightlighted]="section.highlighted"
|
[class.item-hightlighted]="section.highlighted" (click)="selectSectionOrModule($event, section.id, module.id)" button>
|
||||||
(click)="selectSectionOrModule($event, section.id, module.id)" button>
|
<ion-icon class="completioninfo completion_none" name="" *ngIf="module.completionStatus === undefined" slot="start"
|
||||||
<ion-icon class="completioninfo completion_none" name="" *ngIf="module.completionStatus === undefined"
|
aria-hidden="true" />
|
||||||
slot="start" aria-hidden="true" />
|
<ion-icon class="completioninfo completion_incomplete" name="far-circle" *ngIf="module.completionStatus === 0"
|
||||||
<ion-icon class="completioninfo completion_incomplete" name="far-circle"
|
slot="start" [attr.aria-label]="'core.course.todo' | translate" />
|
||||||
*ngIf="module.completionStatus === 0" slot="start"
|
|
||||||
[attr.aria-label]="'core.course.todo' | translate" />
|
|
||||||
<ion-icon class="completioninfo completion_complete" name="fas-circle"
|
<ion-icon class="completioninfo completion_complete" name="fas-circle"
|
||||||
*ngIf="module.completionStatus === 1 || module.completionStatus === 2" color="success" slot="start"
|
*ngIf="module.completionStatus === 1 || module.completionStatus === 2" color="success" slot="start"
|
||||||
[attr.aria-label]="'core.course.done' | translate" />
|
[attr.aria-label]="'core.course.done' | translate" />
|
||||||
<ion-icon class="completioninfo completion_fail" name="fas-xmark" *ngIf="module.completionStatus === 3"
|
<ion-icon class="completioninfo completion_fail" name="fas-xmark" *ngIf="module.completionStatus === 3" color="danger"
|
||||||
color="danger" slot="start" [attr.aria-label]="'core.course.failed' | translate" />
|
slot="start" [attr.aria-label]="'core.course.failed' | translate" />
|
||||||
<ion-label>
|
<ion-label>
|
||||||
<p class="item-heading">
|
<p class="item-heading">
|
||||||
<core-format-text [text]="module.name" contextLevel="module" [contextInstanceId]="module.id"
|
<core-format-text [text]="module.name" contextLevel="module" [contextInstanceId]="module.id"
|
||||||
|
@ -72,11 +82,8 @@
|
||||||
<ion-icon name="fas-lock" *ngIf="!module.uservisible" slot="end" class="restricted"
|
<ion-icon name="fas-lock" *ngIf="!module.uservisible" slot="end" class="restricted"
|
||||||
[attr.aria-label]="'core.restricted' | translate" />
|
[attr.aria-label]="'core.restricted' | translate" />
|
||||||
</ion-item>
|
</ion-item>
|
||||||
|
}
|
||||||
</ng-container>
|
</ng-container>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
</div>
|
</div>
|
||||||
</ng-container>
|
</ng-template>
|
||||||
</ng-container>
|
|
||||||
</ion-list>
|
|
||||||
</core-loading>
|
|
||||||
</ion-content>
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
@use "theme/globals" as *;
|
@use "theme/globals" as *;
|
||||||
core-progress-bar {
|
core-progress-bar {
|
||||||
--bar-margin: 8px 0 4px 0;
|
--bar-margin: 8px 0px 4px 0px;
|
||||||
--line-height: 20px;
|
--line-height: 20px;
|
||||||
--background: var(--contrast-background);
|
--background: var(--contrast-background);
|
||||||
}
|
}
|
||||||
|
@ -19,7 +19,7 @@ ion-item.item {
|
||||||
&.item-current {
|
&.item-current {
|
||||||
--background: var(--primary-tint);
|
--background: var(--primary-tint);
|
||||||
--color: var(--gray-900);
|
--color: var(--gray-900);
|
||||||
border: 0;
|
border: 0px;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.item-hightlighted {
|
&.item-hightlighted {
|
||||||
|
@ -56,7 +56,7 @@ ion-item.item {
|
||||||
|
|
||||||
&.module {
|
&.module {
|
||||||
&::part(native) {
|
&::part(native) {
|
||||||
--padding-start: 0;
|
--padding-start: 0px;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.item-hightlighted ion-icon.completioninfo {
|
&.item-hightlighted ion-icon.completioninfo {
|
||||||
|
@ -70,7 +70,7 @@ ion-item.item {
|
||||||
}
|
}
|
||||||
|
|
||||||
ion-icon {
|
ion-icon {
|
||||||
margin: 0;
|
margin: 0px;
|
||||||
padding: 12px 16px;
|
padding: 12px 16px;
|
||||||
|
|
||||||
&.completioninfo {
|
&.completioninfo {
|
||||||
|
@ -87,3 +87,7 @@ ion-item.item {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
div.core-course-index-subsection {
|
||||||
|
@include padding-horizontal(16px, null);
|
||||||
|
}
|
||||||
|
|
|
@ -20,7 +20,7 @@ import {
|
||||||
CoreCourseProvider,
|
CoreCourseProvider,
|
||||||
} from '@features/course/services/course';
|
} from '@features/course/services/course';
|
||||||
import { CoreCourseHelper, CoreCourseModuleData, CoreCourseSection } from '@features/course/services/course-helper';
|
import { CoreCourseHelper, CoreCourseModuleData, CoreCourseSection } from '@features/course/services/course-helper';
|
||||||
import { CoreCourseFormatDelegate } from '@features/course/services/format-delegate';
|
import { CoreCourseFormatCurrentSectionData, CoreCourseFormatDelegate } from '@features/course/services/format-delegate';
|
||||||
import { CoreCourseAnyCourseData } from '@features/courses/services/courses';
|
import { CoreCourseAnyCourseData } from '@features/courses/services/courses';
|
||||||
import { CoreCoursesHelper } from '@features/courses/services/courses-helper';
|
import { CoreCoursesHelper } from '@features/courses/services/courses-helper';
|
||||||
import { CoreSites } from '@services/sites';
|
import { CoreSites } from '@services/sites';
|
||||||
|
@ -43,6 +43,7 @@ import { CoreDom } from '@singletons/dom';
|
||||||
export class CoreCourseCourseIndexComponent implements OnInit {
|
export class CoreCourseCourseIndexComponent implements OnInit {
|
||||||
|
|
||||||
@Input() sections: CoreCourseSection[] = [];
|
@Input() sections: CoreCourseSection[] = [];
|
||||||
|
@Input() subSections: CoreCourseSection[] = [];
|
||||||
@Input() selectedId?: number;
|
@Input() selectedId?: number;
|
||||||
@Input() course?: CoreCourseAnyCourseData;
|
@Input() course?: CoreCourseAnyCourseData;
|
||||||
|
|
||||||
|
@ -87,38 +88,8 @@ export class CoreCourseCourseIndexComponent implements OnInit {
|
||||||
const enableIndentation = await CoreCourse.isCourseIndentationEnabled(site, this.course.id);
|
const enableIndentation = await CoreCourse.isCourseIndentationEnabled(site, this.course.id);
|
||||||
|
|
||||||
this.sectionsToRender = this.sections
|
this.sectionsToRender = this.sections
|
||||||
.filter((section) => !CoreCourseHelper.isSectionStealth(section))
|
.filter((section) => section.component !== 'mod_subsection' && !CoreCourseHelper.isSectionStealth(section))
|
||||||
.map((section) => {
|
.map((section) => this.mapSectionToRender(section, completionEnabled, enableIndentation, currentSectionData));
|
||||||
const modules = section.modules
|
|
||||||
.filter((module) => this.renderModule(section, module))
|
|
||||||
.map((module) => {
|
|
||||||
const completionStatus = completionEnabled
|
|
||||||
? CoreCourseHelper.getCompletionStatus(module.completiondata)
|
|
||||||
: undefined;
|
|
||||||
|
|
||||||
return {
|
|
||||||
id: module.id,
|
|
||||||
name: module.name,
|
|
||||||
course: module.course,
|
|
||||||
visible: !!module.visible,
|
|
||||||
uservisible: CoreCourseHelper.canUserViewModule(module, section),
|
|
||||||
indented: enableIndentation && module.indent > 0,
|
|
||||||
completionStatus,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
return {
|
|
||||||
id: section.id,
|
|
||||||
name: section.name,
|
|
||||||
availabilityinfo: !!section.availabilityinfo,
|
|
||||||
visible: !!section.visible,
|
|
||||||
uservisible: CoreCourseHelper.canUserViewSection(section),
|
|
||||||
expanded: section.id === this.selectedId,
|
|
||||||
highlighted: currentSectionData.section.id === section.id,
|
|
||||||
hasVisibleModules: modules.length > 0,
|
|
||||||
modules: modules,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
this.highlighted = CoreCourseFormatDelegate.getSectionHightlightedName(this.course);
|
this.highlighted = CoreCourseFormatDelegate.getSectionHightlightedName(this.course);
|
||||||
|
|
||||||
|
@ -163,7 +134,26 @@ export class CoreCourseCourseIndexComponent implements OnInit {
|
||||||
* @param moduleId Selected module id, if any.
|
* @param moduleId Selected module id, if any.
|
||||||
*/
|
*/
|
||||||
selectSectionOrModule(event: Event, sectionId: number, moduleId?: number): void {
|
selectSectionOrModule(event: Event, sectionId: number, moduleId?: number): void {
|
||||||
ModalController.dismiss({ event, sectionId, moduleId });
|
let subSectionId: number | undefined;
|
||||||
|
this.sectionsToRender.some((section) => {
|
||||||
|
if (section.id === sectionId) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return section.modules.some((module) => {
|
||||||
|
if (module.subSection?.id === sectionId) {
|
||||||
|
// Always use the parent section.
|
||||||
|
subSectionId = sectionId;
|
||||||
|
sectionId = section.id;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
ModalController.dismiss({ event, sectionId, subSectionId, moduleId });
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -187,6 +177,69 @@ export class CoreCourseCourseIndexComponent implements OnInit {
|
||||||
return !module.noviewlink;
|
return !module.noviewlink;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Map a section to the format needed to render it.
|
||||||
|
*
|
||||||
|
* @param section Section to map.
|
||||||
|
* @param completionEnabled Whether completion is enabled.
|
||||||
|
* @param enableIndentation Whether indentation is enabled.
|
||||||
|
* @param currentSectionData Current section data.
|
||||||
|
* @returns Mapped section.
|
||||||
|
*/
|
||||||
|
protected mapSectionToRender(
|
||||||
|
section: CoreCourseSection,
|
||||||
|
completionEnabled: boolean,
|
||||||
|
enableIndentation: boolean,
|
||||||
|
currentSectionData?: CoreCourseFormatCurrentSectionData<CoreCourseSection>,
|
||||||
|
): CourseIndexSection {
|
||||||
|
const modules = section.modules
|
||||||
|
.filter((module) => module.modname === 'subsection' || this.renderModule(section, module))
|
||||||
|
.map((module) => {
|
||||||
|
if (module.modname === 'subsection') {
|
||||||
|
const subSectionFound = this.subSections.find((subSection) => subSection.itemid === module.instance);
|
||||||
|
const subSection = subSectionFound
|
||||||
|
? this.mapSectionToRender(subSectionFound, completionEnabled, enableIndentation)
|
||||||
|
: undefined;
|
||||||
|
|
||||||
|
return {
|
||||||
|
id: module.id,
|
||||||
|
name: module.name,
|
||||||
|
course: module.course,
|
||||||
|
visible: !!module.visible,
|
||||||
|
uservisible: CoreCourseHelper.canUserViewModule(module, section),
|
||||||
|
indented: true,
|
||||||
|
subSection,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const completionStatus = completionEnabled
|
||||||
|
? CoreCourseHelper.getCompletionStatus(module.completiondata)
|
||||||
|
: undefined;
|
||||||
|
|
||||||
|
return {
|
||||||
|
id: module.id,
|
||||||
|
name: module.name,
|
||||||
|
course: module.course,
|
||||||
|
visible: !!module.visible,
|
||||||
|
uservisible: CoreCourseHelper.canUserViewModule(module, section),
|
||||||
|
indented: enableIndentation && module.indent > 0,
|
||||||
|
completionStatus,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
id: section.id,
|
||||||
|
name: section.name,
|
||||||
|
availabilityinfo: !!section.availabilityinfo,
|
||||||
|
visible: !!section.visible,
|
||||||
|
uservisible: CoreCourseHelper.canUserViewSection(section),
|
||||||
|
expanded: section.id === this.selectedId,
|
||||||
|
highlighted: currentSectionData?.section.id === section.id,
|
||||||
|
hasVisibleModules: modules.length > 0,
|
||||||
|
modules,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type CourseIndexSection = {
|
type CourseIndexSection = {
|
||||||
|
@ -205,11 +258,13 @@ type CourseIndexSection = {
|
||||||
indented: boolean;
|
indented: boolean;
|
||||||
uservisible: boolean;
|
uservisible: boolean;
|
||||||
completionStatus?: CoreCourseModuleCompletionStatus;
|
completionStatus?: CoreCourseModuleCompletionStatus;
|
||||||
|
subSection?: CourseIndexSection;
|
||||||
}[];
|
}[];
|
||||||
};
|
};
|
||||||
|
|
||||||
export type CoreCourseIndexSectionWithModule = {
|
export type CoreCourseIndexSectionWithModule = {
|
||||||
event: Event;
|
event: Event;
|
||||||
sectionId: number;
|
sectionId: number;
|
||||||
|
subSectionId?: number;
|
||||||
moduleId?: number;
|
moduleId?: number;
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,6 +1,23 @@
|
||||||
<ion-accordion *ngIf="collapsible" class="core-course-module-list-wrapper" [id]="section.id"
|
@if (collapsible) {
|
||||||
|
<ion-accordion class="core-course-module-list-wrapper" [id]="section.id"
|
||||||
[attr.aria-labelledby]="section.name ? 'core-section-name-' + section.id : null" [value]="section.id" toggleIconSlot="start">
|
[attr.aria-labelledby]="section.name ? 'core-section-name-' + section.id : null" [value]="section.id" toggleIconSlot="start">
|
||||||
|
<ng-container *ngTemplateOutlet="sectionHeader" />
|
||||||
|
|
||||||
|
<div slot="content">
|
||||||
|
<ng-container *ngIf="section.expanded">
|
||||||
|
<ng-container *ngTemplateOutlet="sectionContent" />
|
||||||
|
</ng-container>
|
||||||
|
</div>
|
||||||
|
</ion-accordion>
|
||||||
|
} @else {
|
||||||
|
<div class="core-course-module-list-wrapper" [id]="section.id"
|
||||||
|
[attr.aria-labelledby]="section.name ? 'core-section-name-' + section.id : null">
|
||||||
|
<ng-container *ngTemplateOutlet="sectionHeader" />
|
||||||
|
<ng-container *ngTemplateOutlet="sectionContent" />
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
<ng-template #sectionHeader>
|
||||||
<ion-item class="course-section divider" [class.item-dimmed]="section.visible === 0 || section.uservisible === false" slot="header">
|
<ion-item class="course-section divider" [class.item-dimmed]="section.visible === 0 || section.uservisible === false" slot="header">
|
||||||
<ion-label class="ion-text-wrap">
|
<ion-label class="ion-text-wrap">
|
||||||
<h2 *ngIf="section.name" class="big" [id]="'core-section-name-' + section.id">
|
<h2 *ngIf="section.name" class="big" [id]="'core-section-name-' + section.id">
|
||||||
|
@ -27,9 +44,9 @@
|
||||||
</ion-label>
|
</ion-label>
|
||||||
<ion-badge *ngIf="section.highlighted && highlightedName" slot="end">{{highlightedName}}</ion-badge>
|
<ion-badge *ngIf="section.highlighted && highlightedName" slot="end">{{highlightedName}}</ion-badge>
|
||||||
</ion-item>
|
</ion-item>
|
||||||
|
</ng-template>
|
||||||
|
|
||||||
<div slot="content">
|
<ng-template #sectionContent>
|
||||||
<ng-container *ngIf="section.expanded">
|
|
||||||
<ion-item class="ion-text-wrap section-summary" *ngIf="section.summary">
|
<ion-item class="ion-text-wrap section-summary" *ngIf="section.summary">
|
||||||
<ion-label>
|
<ion-label>
|
||||||
<core-format-text [text]="section.summary" contextLevel="course" [contextInstanceId]="course.id" />
|
<core-format-text [text]="section.summary" contextLevel="course" [contextInstanceId]="course.id" />
|
||||||
|
@ -48,57 +65,4 @@
|
||||||
(!module.completiondata || module.completiondata.state === completionStatusIncomplete)" />
|
(!module.completiondata || module.completiondata.state === completionStatusIncomplete)" />
|
||||||
}
|
}
|
||||||
</ng-container>
|
</ng-container>
|
||||||
</ng-container>
|
</ng-template>
|
||||||
</div>
|
|
||||||
</ion-accordion>
|
|
||||||
|
|
||||||
|
|
||||||
<div *ngIf="!collapsible" class="core-course-module-list-wrapper" [id]="section.id"
|
|
||||||
[attr.aria-labelledby]="section.name ? 'core-section-name-' + section.id : null">
|
|
||||||
|
|
||||||
<ion-item class="course-section divider" [class.item-dimmed]="section.visible === 0 || section.uservisible === false">
|
|
||||||
<ion-label class="ion-text-wrap">
|
|
||||||
<h2 *ngIf="section.name" class="big" [id]="'core-section-name-' + section.id">
|
|
||||||
<core-format-text [text]="section.name" contextLevel="course" [contextInstanceId]="course.id" />
|
|
||||||
</h2>
|
|
||||||
<div *ngIf="section.visible === 0 && section.uservisible !== false">
|
|
||||||
<ion-badge color="warning">
|
|
||||||
{{ 'core.course.hiddenfromstudents' | translate }}
|
|
||||||
</ion-badge>
|
|
||||||
</div>
|
|
||||||
<div *ngIf="section.visible === 0 && section.uservisible === false">
|
|
||||||
<ion-badge color="warning">
|
|
||||||
{{ 'core.notavailable' | translate }}
|
|
||||||
</ion-badge>
|
|
||||||
</div>
|
|
||||||
<div *ngIf="section.availabilityinfo">
|
|
||||||
<ion-chip class="clickable">
|
|
||||||
<ion-icon name="fas-lock" [attr.aria-label]="'core.restricted' | translate" />
|
|
||||||
<ion-label>
|
|
||||||
<core-format-text [text]=" section.availabilityinfo" contextLevel="course" [contextInstanceId]="course.id" />
|
|
||||||
</ion-label>
|
|
||||||
</ion-chip>
|
|
||||||
</div>
|
|
||||||
</ion-label>
|
|
||||||
<ion-badge *ngIf="section.highlighted && highlightedName" slot="end">{{highlightedName}}</ion-badge>
|
|
||||||
</ion-item>
|
|
||||||
|
|
||||||
<ion-item class="ion-text-wrap section-summary" *ngIf="section.summary">
|
|
||||||
<ion-label>
|
|
||||||
<core-format-text [text]="section.summary" contextLevel="course" [contextInstanceId]="course.id" />
|
|
||||||
</ion-label>
|
|
||||||
</ion-item>
|
|
||||||
|
|
||||||
<ng-container *ngFor="let module of modules">
|
|
||||||
@if (module.subsection) {
|
|
||||||
<core-course-section [course]="course" [section]="module.subsection" [lastModuleViewed]="lastModuleViewed"
|
|
||||||
[viewedModules]="viewedModules" [collapsible]="true" />
|
|
||||||
} @else {
|
|
||||||
<core-course-module *ngIf="module.visibleoncoursepage !== 0" [module]="module" [section]="section"
|
|
||||||
[showActivityDates]="course.showactivitydates" [showCompletionConditions]="course.showcompletionconditions"
|
|
||||||
[isLastViewed]="lastModuleViewed && lastModuleViewed.cmId === module.id" [class.core-course-module-not-viewed]="
|
|
||||||
!viewedModules[module.id] &&
|
|
||||||
(!module.completiondata || module.completiondata.state === completionStatusIncomplete)" />
|
|
||||||
}
|
|
||||||
</ng-container>
|
|
||||||
</div>
|
|
||||||
|
|
Loading…
Reference in New Issue