MOBILE-3757 course: Display dates and completion inside activity
parent
3f825db799
commit
61a908216d
|
@ -30,6 +30,11 @@
|
||||||
<!-- Content. -->
|
<!-- Content. -->
|
||||||
<core-loading [hideUntil]="loaded" class="core-loading-center">
|
<core-loading [hideUntil]="loaded" class="core-loading-center">
|
||||||
|
|
||||||
|
<!-- Activity info. -->
|
||||||
|
<core-course-module-info *ngIf="showCompletion" [module]="module" [showManualCompletion]="true"
|
||||||
|
(completionChanged)="onCompletionChange()">
|
||||||
|
</core-course-module-info>
|
||||||
|
|
||||||
<!-- Description and intro attachments. -->
|
<!-- Description and intro attachments. -->
|
||||||
<ion-card *ngIf="description">
|
<ion-card *ngIf="description">
|
||||||
<ion-item class="ion-text-wrap">
|
<ion-item class="ion-text-wrap">
|
||||||
|
@ -141,5 +146,4 @@
|
||||||
<addon-mod-assign-submission *ngIf="loaded && !canViewAllSubmissions && canViewOwnSubmission" [courseId]="courseId"
|
<addon-mod-assign-submission *ngIf="loaded && !canViewAllSubmissions && canViewOwnSubmission" [courseId]="courseId"
|
||||||
[moduleId]="module.id">
|
[moduleId]="module.id">
|
||||||
</addon-mod-assign-submission>
|
</addon-mod-assign-submission>
|
||||||
|
|
||||||
</core-loading>
|
</core-loading>
|
||||||
|
|
|
@ -120,7 +120,7 @@ export class AddonModAssignIndexComponent extends CoreCourseModuleMainActivityCo
|
||||||
AddonModAssignProvider.SUBMITTED_FOR_GRADING_EVENT,
|
AddonModAssignProvider.SUBMITTED_FOR_GRADING_EVENT,
|
||||||
(data) => {
|
(data) => {
|
||||||
if (this.assign && data.assignmentId == this.assign.id && data.userId == this.currentUserId) {
|
if (this.assign && data.assignmentId == this.assign.id && data.userId == this.currentUserId) {
|
||||||
// Assignment submitted, check completion.
|
// Assignment submitted, check completion.
|
||||||
CoreCourse.checkModuleCompletion(this.courseId, this.module.completiondata);
|
CoreCourse.checkModuleCompletion(this.courseId, this.module.completiondata);
|
||||||
|
|
||||||
// Reload data since it can have offline data now.
|
// Reload data since it can have offline data now.
|
||||||
|
|
|
@ -54,7 +54,7 @@
|
||||||
</ion-label>
|
</ion-label>
|
||||||
</ion-item>
|
</ion-item>
|
||||||
|
|
||||||
<ion-item class="ion-text-wrap" *ngIf="fromDate && !isSubmittedForGrading">
|
<ion-item class="ion-text-wrap" *ngIf="showDates && fromDate && !isSubmittedForGrading">
|
||||||
<ion-label>
|
<ion-label>
|
||||||
<p *ngIf="assign!.intro"
|
<p *ngIf="assign!.intro"
|
||||||
[innerHTML]="'addon.mod_assign.allowsubmissionsfromdatesummary' | translate: {'$a': fromDate}">
|
[innerHTML]="'addon.mod_assign.allowsubmissionsfromdatesummary' | translate: {'$a': fromDate}">
|
||||||
|
@ -66,7 +66,7 @@
|
||||||
</ion-label>
|
</ion-label>
|
||||||
</ion-item>
|
</ion-item>
|
||||||
|
|
||||||
<ion-item class="ion-text-wrap" *ngIf="assign!.duedate && !isSubmittedForGrading">
|
<ion-item class="ion-text-wrap" *ngIf="showDates && assign!.duedate && !isSubmittedForGrading">
|
||||||
<ion-label>
|
<ion-label>
|
||||||
<h2>{{ 'addon.mod_assign.duedate' | translate }}</h2>
|
<h2>{{ 'addon.mod_assign.duedate' | translate }}</h2>
|
||||||
<p *ngIf="assign!.duedate" >{{ assign!.duedate * 1000 | coreFormatDate }}</p>
|
<p *ngIf="assign!.duedate" >{{ assign!.duedate * 1000 | coreFormatDate }}</p>
|
||||||
|
|
|
@ -122,6 +122,7 @@ export class AddonModAssignSubmissionComponent implements OnInit, OnDestroy, Can
|
||||||
allowAddAttempt = false; // Allow adding a new attempt when grading.
|
allowAddAttempt = false; // Allow adding a new attempt when grading.
|
||||||
gradeUrl?: string; // URL to grade in browser.
|
gradeUrl?: string; // URL to grade in browser.
|
||||||
isPreviousAttemptEmpty = true; // Whether the previous attempt contains an empty submission.
|
isPreviousAttemptEmpty = true; // Whether the previous attempt contains an empty submission.
|
||||||
|
showDates = false; // Whether to show some dates.
|
||||||
|
|
||||||
// Some constants.
|
// Some constants.
|
||||||
statusNew = AddonModAssignProvider.SUBMISSION_STATUS_NEW;
|
statusNew = AddonModAssignProvider.SUBMISSION_STATUS_NEW;
|
||||||
|
@ -181,6 +182,7 @@ export class AddonModAssignSubmissionComponent implements OnInit, OnDestroy, Can
|
||||||
*/
|
*/
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
this.isSubmittedForGrading = !!this.submitId;
|
this.isSubmittedForGrading = !!this.submitId;
|
||||||
|
this.showDates = !CoreSites.getCurrentSite()?.isVersionGreaterEqualThan('3.11');
|
||||||
|
|
||||||
this.loadData(true);
|
this.loadData(true);
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,6 +23,11 @@
|
||||||
<!-- Content. -->
|
<!-- Content. -->
|
||||||
<core-loading [hideUntil]="loaded" class="core-loading-center">
|
<core-loading [hideUntil]="loaded" class="core-loading-center">
|
||||||
|
|
||||||
|
<!-- Activity info. -->
|
||||||
|
<core-course-module-info *ngIf="showCompletion" [module]="module" [showManualCompletion]="true"
|
||||||
|
(completionChanged)="onCompletionChange()">
|
||||||
|
</core-course-module-info>
|
||||||
|
|
||||||
<core-course-module-description [description]="description" [component]="component" [componentId]="componentId"
|
<core-course-module-description [description]="description" [component]="component" [componentId]="componentId"
|
||||||
contextLevel="module" [contextInstanceId]="module.id" [courseId]="courseId"></core-course-module-description>
|
contextLevel="module" [contextInstanceId]="module.id" [courseId]="courseId"></core-course-module-description>
|
||||||
|
|
||||||
|
|
|
@ -26,6 +26,11 @@
|
||||||
<!-- Content. -->
|
<!-- Content. -->
|
||||||
<core-loading [hideUntil]="loaded" class="core-loading-center safe-area-page">
|
<core-loading [hideUntil]="loaded" class="core-loading-center safe-area-page">
|
||||||
|
|
||||||
|
<!-- Activity info. -->
|
||||||
|
<core-course-module-info *ngIf="showCompletion" [module]="module" [showManualCompletion]="true"
|
||||||
|
(completionChanged)="onCompletionChange()">
|
||||||
|
</core-course-module-info>
|
||||||
|
|
||||||
<core-course-module-description [description]="description" [component]="component" [componentId]="componentId"
|
<core-course-module-description [description]="description" [component]="component" [componentId]="componentId"
|
||||||
contextLevel="module" [contextInstanceId]="module.id" [courseId]="courseId">
|
contextLevel="module" [contextInstanceId]="module.id" [courseId]="courseId">
|
||||||
</core-course-module-description>
|
</core-course-module-description>
|
||||||
|
|
|
@ -28,6 +28,11 @@
|
||||||
<!-- Content. -->
|
<!-- Content. -->
|
||||||
<core-loading [hideUntil]="loaded" class="core-loading-center">
|
<core-loading [hideUntil]="loaded" class="core-loading-center">
|
||||||
|
|
||||||
|
<!-- Activity info. -->
|
||||||
|
<core-course-module-info *ngIf="showCompletion" [module]="module" [showManualCompletion]="true"
|
||||||
|
(completionChanged)="onCompletionChange()">
|
||||||
|
</core-course-module-info>
|
||||||
|
|
||||||
<core-course-module-description [description]="description" [component]="component" [componentId]="componentId"
|
<core-course-module-description [description]="description" [component]="component" [componentId]="componentId"
|
||||||
contextLevel="module" [contextInstanceId]="module.id" [courseId]="courseId">
|
contextLevel="module" [contextInstanceId]="module.id" [courseId]="courseId">
|
||||||
</core-course-module-description>
|
</core-course-module-description>
|
||||||
|
|
|
@ -39,6 +39,11 @@
|
||||||
<!-- Content. -->
|
<!-- Content. -->
|
||||||
<core-loading [hideUntil]="loaded" class="core-loading-center">
|
<core-loading [hideUntil]="loaded" class="core-loading-center">
|
||||||
|
|
||||||
|
<!-- Activity info. -->
|
||||||
|
<core-course-module-info *ngIf="showCompletion" [module]="module" [showManualCompletion]="true"
|
||||||
|
(completionChanged)="onCompletionChange()">
|
||||||
|
</core-course-module-info>
|
||||||
|
|
||||||
<core-course-module-description [description]="description" [component]="component" [componentId]="componentId"
|
<core-course-module-description [description]="description" [component]="component" [componentId]="componentId"
|
||||||
contextLevel="module" [contextInstanceId]="module.id" [courseId]="courseId">
|
contextLevel="module" [contextInstanceId]="module.id" [courseId]="courseId">
|
||||||
</core-course-module-description>
|
</core-course-module-description>
|
||||||
|
|
|
@ -28,6 +28,11 @@
|
||||||
<!-- Content. -->
|
<!-- Content. -->
|
||||||
<core-loading [hideUntil]="loaded" class="core-loading-center">
|
<core-loading [hideUntil]="loaded" class="core-loading-center">
|
||||||
|
|
||||||
|
<!-- Activity info. -->
|
||||||
|
<core-course-module-info *ngIf="showCompletion" [module]="module" [showManualCompletion]="true"
|
||||||
|
(completionChanged)="onCompletionChange()">
|
||||||
|
</core-course-module-info>
|
||||||
|
|
||||||
<core-course-module-description [description]="description" [component]="component" [componentId]="componentId"
|
<core-course-module-description [description]="description" [component]="component" [componentId]="componentId"
|
||||||
contextLevel="module" [contextInstanceId]="module.id" [courseId]="courseId">
|
contextLevel="module" [contextInstanceId]="module.id" [courseId]="courseId">
|
||||||
</core-course-module-description>
|
</core-course-module-description>
|
||||||
|
|
|
@ -25,6 +25,11 @@
|
||||||
<!-- Content. -->
|
<!-- Content. -->
|
||||||
<core-loading [hideUntil]="loaded" class="core-loading-center">
|
<core-loading [hideUntil]="loaded" class="core-loading-center">
|
||||||
|
|
||||||
|
<!-- Activity info. -->
|
||||||
|
<core-course-module-info *ngIf="showCompletion" [module]="module" [showManualCompletion]="true"
|
||||||
|
(completionChanged)="onCompletionChange()">
|
||||||
|
</core-course-module-info>
|
||||||
|
|
||||||
<core-course-module-description [description]="description" [component]="component" [componentId]="componentId"
|
<core-course-module-description [description]="description" [component]="component" [componentId]="componentId"
|
||||||
contextLevel="module" [contextInstanceId]="module.id" [courseId]="courseId">
|
contextLevel="module" [contextInstanceId]="module.id" [courseId]="courseId">
|
||||||
</core-course-module-description>
|
</core-course-module-description>
|
||||||
|
|
|
@ -42,6 +42,11 @@
|
||||||
</ion-refresher>
|
</ion-refresher>
|
||||||
|
|
||||||
<core-loading [hideUntil]="discussions.loaded" class="core-loading-center">
|
<core-loading [hideUntil]="discussions.loaded" class="core-loading-center">
|
||||||
|
<!-- Activity info. -->
|
||||||
|
<core-course-module-info *ngIf="showCompletion" [module]="module" [showManualCompletion]="true"
|
||||||
|
(completionChanged)="onCompletionChange()">
|
||||||
|
</core-course-module-info>
|
||||||
|
|
||||||
<core-course-module-description *ngIf="forum && forum.type != 'single'"
|
<core-course-module-description *ngIf="forum && forum.type != 'single'"
|
||||||
[description]="description" [component]="component" [componentId]="componentId" [note]="descriptionNote"
|
[description]="description" [component]="component" [componentId]="componentId" [note]="descriptionNote"
|
||||||
contextLevel="module" [contextInstanceId]="module && module.id" [courseId]="courseId">
|
contextLevel="module" [contextInstanceId]="module && module.id" [courseId]="courseId">
|
||||||
|
|
|
@ -50,6 +50,11 @@
|
||||||
</core-search-box>
|
</core-search-box>
|
||||||
|
|
||||||
<core-loading [hideUntil]="entries.loaded" class="core-loading-center">
|
<core-loading [hideUntil]="entries.loaded" class="core-loading-center">
|
||||||
|
<!-- Activity info. -->
|
||||||
|
<core-course-module-info *ngIf="showCompletion" [module]="module" [showManualCompletion]="true"
|
||||||
|
(completionChanged)="onCompletionChange()">
|
||||||
|
</core-course-module-info>
|
||||||
|
|
||||||
<core-course-module-description [description]="description" [component]="component" [componentId]="componentId"
|
<core-course-module-description [description]="description" [component]="component" [componentId]="componentId"
|
||||||
contextLevel="module" [contextInstanceId]="module.id" [courseId]="courseId">
|
contextLevel="module" [contextInstanceId]="module.id" [courseId]="courseId">
|
||||||
</core-course-module-description>
|
</core-course-module-description>
|
||||||
|
|
|
@ -32,6 +32,11 @@
|
||||||
<!-- Content. -->
|
<!-- Content. -->
|
||||||
<core-loading [hideUntil]="loaded" class="core-loading-center safe-area-page">
|
<core-loading [hideUntil]="loaded" class="core-loading-center safe-area-page">
|
||||||
|
|
||||||
|
<!-- Activity info. -->
|
||||||
|
<core-course-module-info *ngIf="showCompletion" [module]="module" [showManualCompletion]="true"
|
||||||
|
(completionChanged)="onCompletionChange()">
|
||||||
|
</core-course-module-info>
|
||||||
|
|
||||||
<core-course-module-description [description]="description" [component]="component" [componentId]="componentId"
|
<core-course-module-description [description]="description" [component]="component" [componentId]="componentId"
|
||||||
contextLevel="module" [contextInstanceId]="module.id" [courseId]="courseId">
|
contextLevel="module" [contextInstanceId]="module.id" [courseId]="courseId">
|
||||||
</core-course-module-description>
|
</core-course-module-description>
|
||||||
|
|
|
@ -28,6 +28,11 @@
|
||||||
<!-- Content. -->
|
<!-- Content. -->
|
||||||
<core-loading [hideUntil]="loaded" class="core-loading-center safe-area-page">
|
<core-loading [hideUntil]="loaded" class="core-loading-center safe-area-page">
|
||||||
|
|
||||||
|
<!-- Activity info. -->
|
||||||
|
<core-course-module-info *ngIf="showCompletion" [module]="module" [showManualCompletion]="true"
|
||||||
|
(completionChanged)="onCompletionChange()">
|
||||||
|
</core-course-module-info>
|
||||||
|
|
||||||
<ion-card class="core-warning-card" *ngIf="warning">
|
<ion-card class="core-warning-card" *ngIf="warning">
|
||||||
<ion-item>
|
<ion-item>
|
||||||
<ion-icon name="fas-exclamation-triangle" slot="start" aria-hidden="true"></ion-icon>
|
<ion-icon name="fas-exclamation-triangle" slot="start" aria-hidden="true"></ion-icon>
|
||||||
|
|
|
@ -31,6 +31,12 @@
|
||||||
<!-- Index/Preview tab. -->
|
<!-- Index/Preview tab. -->
|
||||||
<core-tab [title]="'addon.mod_lesson.preview' | translate" (ionSelect)="indexSelected()">
|
<core-tab [title]="'addon.mod_lesson.preview' | translate" (ionSelect)="indexSelected()">
|
||||||
<ng-template>
|
<ng-template>
|
||||||
|
|
||||||
|
<!-- Activity info. -->
|
||||||
|
<core-course-module-info *ngIf="showCompletion" [module]="module" [showManualCompletion]="true"
|
||||||
|
(completionChanged)="onCompletionChange()">
|
||||||
|
</core-course-module-info>
|
||||||
|
|
||||||
<core-course-module-description [description]="description" [component]="component" [componentId]="componentId"
|
<core-course-module-description [description]="description" [component]="component" [componentId]="componentId"
|
||||||
contextLevel="module" [contextInstanceId]="module.id" [courseId]="courseId">
|
contextLevel="module" [contextInstanceId]="module.id" [courseId]="courseId">
|
||||||
</core-course-module-description>
|
</core-course-module-description>
|
||||||
|
|
|
@ -18,6 +18,12 @@
|
||||||
|
|
||||||
<!-- Content. -->
|
<!-- Content. -->
|
||||||
<core-loading [hideUntil]="loaded" class="core-loading-center safe-area-page">
|
<core-loading [hideUntil]="loaded" class="core-loading-center safe-area-page">
|
||||||
|
|
||||||
|
<!-- Activity info. -->
|
||||||
|
<core-course-module-info *ngIf="showCompletion" [module]="module" [showManualCompletion]="true"
|
||||||
|
(completionChanged)="onCompletionChange()">
|
||||||
|
</core-course-module-info>
|
||||||
|
|
||||||
<core-course-module-description *ngIf="lti && lti.showdescriptionlaunch" [description]="description" [component]="component"
|
<core-course-module-description *ngIf="lti && lti.showdescriptionlaunch" [description]="description" [component]="component"
|
||||||
[componentId]="componentId" contextLevel="module" [contextInstanceId]="module.id" [courseId]="courseId">
|
[componentId]="componentId" contextLevel="module" [contextInstanceId]="module.id" [courseId]="courseId">
|
||||||
</core-course-module-description>
|
</core-course-module-description>
|
||||||
|
|
|
@ -25,6 +25,11 @@
|
||||||
<!-- Content. -->
|
<!-- Content. -->
|
||||||
<core-loading [hideUntil]="loaded" class="core-loading-center safe-area-page">
|
<core-loading [hideUntil]="loaded" class="core-loading-center safe-area-page">
|
||||||
|
|
||||||
|
<!-- Activity info. -->
|
||||||
|
<core-course-module-info *ngIf="showCompletion" [module]="module" [showManualCompletion]="true"
|
||||||
|
(completionChanged)="onCompletionChange()">
|
||||||
|
</core-course-module-info>
|
||||||
|
|
||||||
<core-course-module-description *ngIf="displayDescription" [description]="description" [component]="component"
|
<core-course-module-description *ngIf="displayDescription" [description]="description" [component]="component"
|
||||||
[componentId]="componentId" contextLevel="module" [contextInstanceId]="module.id" [courseId]="courseId">
|
[componentId]="componentId" contextLevel="module" [contextInstanceId]="module.id" [courseId]="courseId">
|
||||||
</core-course-module-description>
|
</core-course-module-description>
|
||||||
|
|
|
@ -27,6 +27,12 @@
|
||||||
|
|
||||||
<!-- Content. -->
|
<!-- Content. -->
|
||||||
<core-loading [hideUntil]="loaded" class="core-loading-center">
|
<core-loading [hideUntil]="loaded" class="core-loading-center">
|
||||||
|
|
||||||
|
<!-- Activity info. -->
|
||||||
|
<core-course-module-info *ngIf="showCompletion" [module]="module" [showManualCompletion]="true"
|
||||||
|
(completionChanged)="onCompletionChange()">
|
||||||
|
</core-course-module-info>
|
||||||
|
|
||||||
<core-course-module-description [description]="description" [component]="component" [componentId]="componentId"
|
<core-course-module-description [description]="description" [component]="component" [componentId]="componentId"
|
||||||
contextLevel="module" [contextInstanceId]="module.id" [courseId]="courseId">
|
contextLevel="module" [contextInstanceId]="module.id" [courseId]="courseId">
|
||||||
</core-course-module-description>
|
</core-course-module-description>
|
||||||
|
|
|
@ -20,6 +20,11 @@
|
||||||
<!-- Content. -->
|
<!-- Content. -->
|
||||||
<core-loading [hideUntil]="loaded" class="core-loading-center safe-area-page">
|
<core-loading [hideUntil]="loaded" class="core-loading-center safe-area-page">
|
||||||
|
|
||||||
|
<!-- Activity info. -->
|
||||||
|
<core-course-module-info *ngIf="showCompletion" [module]="module" [showManualCompletion]="true"
|
||||||
|
(completionChanged)="onCompletionChange()">
|
||||||
|
</core-course-module-info>
|
||||||
|
|
||||||
<core-course-module-description *ngIf="mode != 'iframe' && (mode != 'embedded' || displayDescription)"
|
<core-course-module-description *ngIf="mode != 'iframe' && (mode != 'embedded' || displayDescription)"
|
||||||
[description]="description" [component]="component" [componentId]="componentId" contextLevel="module"
|
[description]="description" [component]="component" [componentId]="componentId" contextLevel="module"
|
||||||
[contextInstanceId]="module.id" [courseId]="courseId">
|
[contextInstanceId]="module.id" [courseId]="courseId">
|
||||||
|
|
|
@ -28,6 +28,11 @@
|
||||||
<!-- Content. -->
|
<!-- Content. -->
|
||||||
<core-loading [hideUntil]="loaded" class="core-loading-center">
|
<core-loading [hideUntil]="loaded" class="core-loading-center">
|
||||||
|
|
||||||
|
<!-- Activity info. -->
|
||||||
|
<core-course-module-info *ngIf="showCompletion" [module]="module" [showManualCompletion]="true"
|
||||||
|
(completionChanged)="onCompletionChange()">
|
||||||
|
</core-course-module-info>
|
||||||
|
|
||||||
<core-course-module-description [description]="description" [component]="component" [componentId]="componentId"
|
<core-course-module-description [description]="description" [component]="component" [componentId]="componentId"
|
||||||
contextLevel="module" [contextInstanceId]="module.id" [courseId]="courseId">
|
contextLevel="module" [contextInstanceId]="module.id" [courseId]="courseId">
|
||||||
</core-course-module-description>
|
</core-course-module-description>
|
||||||
|
|
|
@ -29,6 +29,11 @@
|
||||||
<!-- Content. -->
|
<!-- Content. -->
|
||||||
<core-loading [hideUntil]="loaded" class="core-loading-center safe-area-page">
|
<core-loading [hideUntil]="loaded" class="core-loading-center safe-area-page">
|
||||||
|
|
||||||
|
<!-- Activity info. -->
|
||||||
|
<core-course-module-info *ngIf="showCompletion" [module]="module" [showManualCompletion]="true"
|
||||||
|
(completionChanged)="onCompletionChange()">
|
||||||
|
</core-course-module-info>
|
||||||
|
|
||||||
<core-course-module-description *ngIf="survey && !survey.surveydone && !hasOffline" [description]="description"
|
<core-course-module-description *ngIf="survey && !survey.surveydone && !hasOffline" [description]="description"
|
||||||
[component]="component" [componentId]="componentId" contextLevel="module" [contextInstanceId]="module.id"
|
[component]="component" [componentId]="componentId" contextLevel="module" [contextInstanceId]="module.id"
|
||||||
[courseId]="courseId">
|
[courseId]="courseId">
|
||||||
|
|
|
@ -15,6 +15,11 @@
|
||||||
<!-- Content. -->
|
<!-- Content. -->
|
||||||
<core-loading [hideUntil]="loaded" class="core-loading-center">
|
<core-loading [hideUntil]="loaded" class="core-loading-center">
|
||||||
|
|
||||||
|
<!-- Activity info. -->
|
||||||
|
<core-course-module-info *ngIf="showCompletion" [module]="module" [showManualCompletion]="true"
|
||||||
|
(completionChanged)="onCompletionChange()">
|
||||||
|
</core-course-module-info>
|
||||||
|
|
||||||
<core-course-module-description *ngIf="displayDescription" [description]="description" [component]="component"
|
<core-course-module-description *ngIf="displayDescription" [description]="description" [component]="component"
|
||||||
[componentId]="componentId" contextLevel="module" [contextInstanceId]="module.id" [courseId]="courseId">
|
[componentId]="componentId" contextLevel="module" [contextInstanceId]="module.id" [courseId]="courseId">
|
||||||
</core-course-module-description>
|
</core-course-module-description>
|
||||||
|
|
|
@ -47,6 +47,12 @@
|
||||||
|
|
||||||
<!-- Content. -->
|
<!-- Content. -->
|
||||||
<core-loading [hideUntil]="loaded" class="core-loading-center">
|
<core-loading [hideUntil]="loaded" class="core-loading-center">
|
||||||
|
|
||||||
|
<!-- Activity info. -->
|
||||||
|
<core-course-module-info *ngIf="showCompletion" [module]="module" [showManualCompletion]="true"
|
||||||
|
(completionChanged)="onCompletionChange()">
|
||||||
|
</core-course-module-info>
|
||||||
|
|
||||||
<div *ngIf="description || pageIsOffline || hasOffline || pageWarning">
|
<div *ngIf="description || pageIsOffline || hasOffline || pageWarning">
|
||||||
<core-course-module-description [description]="description" [component]="component" [componentId]="componentId"
|
<core-course-module-description [description]="description" [component]="component" [componentId]="componentId"
|
||||||
contextLevel="module" [contextInstanceId]="module.id" [courseId]="courseId">
|
contextLevel="module" [contextInstanceId]="module.id" [courseId]="courseId">
|
||||||
|
|
|
@ -27,6 +27,12 @@
|
||||||
|
|
||||||
<!-- Content. -->
|
<!-- Content. -->
|
||||||
<core-loading [hideUntil]="loaded" class="core-loading-center">
|
<core-loading [hideUntil]="loaded" class="core-loading-center">
|
||||||
|
|
||||||
|
<!-- Activity info. -->
|
||||||
|
<core-course-module-info *ngIf="showCompletion" [module]="module" [showManualCompletion]="true"
|
||||||
|
(completionChanged)="onCompletionChange()">
|
||||||
|
</core-course-module-info>
|
||||||
|
|
||||||
<ion-card class="with-borders" *ngIf="phases">
|
<ion-card class="with-borders" *ngIf="phases">
|
||||||
<ion-item button (click)="viewPhaseInfo()" detail="true">
|
<ion-item button (click)="viewPhaseInfo()" detail="true">
|
||||||
<ion-label>
|
<ion-label>
|
||||||
|
|
|
@ -122,7 +122,14 @@ export class CoreCourseModuleMainActivityComponent extends CoreCourseModuleMainR
|
||||||
this.syncIcon = CoreConstants.ICON_LOADING;
|
this.syncIcon = CoreConstants.ICON_LOADING;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await CoreUtils.ignoreErrors(this.invalidateContent());
|
await CoreUtils.ignoreErrors(Promise.all([
|
||||||
|
this.invalidateContent(),
|
||||||
|
this.showCompletion ? CoreCourse.invalidateModule(this.module.id) : undefined,
|
||||||
|
]));
|
||||||
|
|
||||||
|
if (this.showCompletion) {
|
||||||
|
this.module = await CoreCourse.getModule(this.module.id, this.courseId);
|
||||||
|
}
|
||||||
|
|
||||||
await this.loadContent(true, sync, showErrors);
|
await this.loadContent(true, sync, showErrors);
|
||||||
} finally {
|
} finally {
|
||||||
|
|
|
@ -70,12 +70,14 @@ export class CoreCourseModuleMainResourceComponent implements OnInit, OnDestroy,
|
||||||
isDestroyed = false; // Whether the component is destroyed, used when calling fillContextMenu.
|
isDestroyed = false; // Whether the component is destroyed, used when calling fillContextMenu.
|
||||||
contextMenuStatusObserver?: CoreEventObserver; // Observer of package status, used when calling fillContextMenu.
|
contextMenuStatusObserver?: CoreEventObserver; // Observer of package status, used when calling fillContextMenu.
|
||||||
contextFileStatusObserver?: CoreEventObserver; // Observer of file status, used when calling fillContextMenu.
|
contextFileStatusObserver?: CoreEventObserver; // Observer of file status, used when calling fillContextMenu.
|
||||||
|
showCompletion = false; // Whether to show completion inside the activity.
|
||||||
|
|
||||||
protected fetchContentDefaultError = 'core.course.errorgetmodule'; // Default error to show when loading contents.
|
protected fetchContentDefaultError = 'core.course.errorgetmodule'; // Default error to show when loading contents.
|
||||||
protected isCurrentView = false; // Whether the component is in the current view.
|
protected isCurrentView = false; // Whether the component is in the current view.
|
||||||
protected siteId?: string; // Current Site ID.
|
protected siteId?: string; // Current Site ID.
|
||||||
protected statusObserver?: CoreEventObserver; // Observer of package status. Only if setStatusListener is called.
|
protected statusObserver?: CoreEventObserver; // Observer of package status. Only if setStatusListener is called.
|
||||||
protected currentStatus?: string; // The current status of the module. Only if setStatusListener is called.
|
protected currentStatus?: string; // The current status of the module. Only if setStatusListener is called.
|
||||||
|
protected completionObserver?: CoreEventObserver;
|
||||||
protected logger: CoreLogger;
|
protected logger: CoreLogger;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
|
@ -94,6 +96,18 @@ export class CoreCourseModuleMainResourceComponent implements OnInit, OnDestroy,
|
||||||
this.componentId = this.module.id;
|
this.componentId = this.module.id;
|
||||||
this.externalUrl = this.module.url;
|
this.externalUrl = this.module.url;
|
||||||
this.courseId = this.courseId || this.module.course!;
|
this.courseId = this.courseId || this.module.course!;
|
||||||
|
this.showCompletion = !!CoreSites.getCurrentSite()?.isVersionGreaterEqualThan('3.11');
|
||||||
|
|
||||||
|
if (this.showCompletion) {
|
||||||
|
this.completionObserver = CoreEvents.on(CoreEvents.COMPLETION_MODULE_VIEWED, async (data) => {
|
||||||
|
if (data && data.cmId == this.module.id) {
|
||||||
|
await CoreCourse.invalidateModule(this.module.id);
|
||||||
|
|
||||||
|
this.module = await CoreCourse.getModule(this.module.id, this.courseId);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
this.blog = await AddonBlog.isPluginEnabled();
|
this.blog = await AddonBlog.isPluginEnabled();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -140,7 +154,14 @@ export class CoreCourseModuleMainResourceComponent implements OnInit, OnDestroy,
|
||||||
this.refreshIcon = CoreConstants.ICON_LOADING;
|
this.refreshIcon = CoreConstants.ICON_LOADING;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await CoreUtils.ignoreErrors(this.invalidateContent());
|
await CoreUtils.ignoreErrors(Promise.all([
|
||||||
|
this.invalidateContent(),
|
||||||
|
this.showCompletion ? CoreCourse.invalidateModule(this.module.id) : undefined,
|
||||||
|
]));
|
||||||
|
|
||||||
|
if (this.showCompletion) {
|
||||||
|
this.module = await CoreCourse.getModule(this.module.id, this.courseId);
|
||||||
|
}
|
||||||
|
|
||||||
await this.loadContent(true);
|
await this.loadContent(true);
|
||||||
} finally {
|
} finally {
|
||||||
|
@ -376,6 +397,16 @@ export class CoreCourseModuleMainResourceComponent implements OnInit, OnDestroy,
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The completion of the modules has changed.
|
||||||
|
*
|
||||||
|
* @return Promise resolved when done.
|
||||||
|
*/
|
||||||
|
async onCompletionChange(): Promise<void> {
|
||||||
|
// Nothing to do.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Component being destroyed.
|
* Component being destroyed.
|
||||||
*/
|
*/
|
||||||
|
@ -384,6 +415,7 @@ export class CoreCourseModuleMainResourceComponent implements OnInit, OnDestroy,
|
||||||
this.contextMenuStatusObserver?.off();
|
this.contextMenuStatusObserver?.off();
|
||||||
this.contextFileStatusObserver?.off();
|
this.contextFileStatusObserver?.off();
|
||||||
this.statusObserver?.off();
|
this.statusObserver?.off();
|
||||||
|
this.completionObserver?.off();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -14,8 +14,6 @@
|
||||||
|
|
||||||
import { Component, Input, Output, EventEmitter, OnChanges, SimpleChange } from '@angular/core';
|
import { Component, Input, Output, EventEmitter, OnChanges, SimpleChange } from '@angular/core';
|
||||||
|
|
||||||
import { CoreDomUtils } from '@services/utils/dom';
|
|
||||||
import { CoreCourse } from '@features/course/services/course';
|
|
||||||
import { CoreCourseModuleCompletionData } from '@features/course/services/course-helper';
|
import { CoreCourseModuleCompletionData } from '@features/course/services/course-helper';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -32,7 +30,7 @@ export class CoreCourseModuleCompletionBaseComponent implements OnChanges {
|
||||||
@Output() completionChanged = new EventEmitter<CoreCourseModuleCompletionData>(); // Notify when completion changes.
|
@Output() completionChanged = new EventEmitter<CoreCourseModuleCompletionData>(); // Notify when completion changes.
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Detect changes on input properties.
|
* @inheritdoc
|
||||||
*/
|
*/
|
||||||
ngOnChanges(changes: { [name: string]: SimpleChange }): void {
|
ngOnChanges(changes: { [name: string]: SimpleChange }): void {
|
||||||
if (changes.completion && this.completion) {
|
if (changes.completion && this.completion) {
|
||||||
|
@ -47,47 +45,4 @@ export class CoreCourseModuleCompletionBaseComponent implements OnChanges {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Completion clicked.
|
|
||||||
*
|
|
||||||
* @param e The click event.
|
|
||||||
*/
|
|
||||||
async completionClicked(e: Event): Promise<void> {
|
|
||||||
if (!this.completion) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeof this.completion.cmid == 'undefined' || this.completion.tracking !== 1) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
e.preventDefault();
|
|
||||||
e.stopPropagation();
|
|
||||||
|
|
||||||
const modal = await CoreDomUtils.showModalLoading();
|
|
||||||
this.completion.state = this.completion.state === 1 ? 0 : 1;
|
|
||||||
|
|
||||||
try {
|
|
||||||
const response = await CoreCourse.markCompletedManually(
|
|
||||||
this.completion.cmid,
|
|
||||||
this.completion.state === 1,
|
|
||||||
this.completion.courseId!,
|
|
||||||
this.completion.courseName,
|
|
||||||
);
|
|
||||||
|
|
||||||
if (this.completion.valueused === false) {
|
|
||||||
this.calculateData();
|
|
||||||
if (response.offline) {
|
|
||||||
this.completion.offline = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this.completionChanged.emit(this.completion);
|
|
||||||
} catch (error) {
|
|
||||||
this.completion.state = this.completion.state === 1 ? 0 : 1;
|
|
||||||
CoreDomUtils.showErrorModalDefault(error, 'core.errorchangecompletion', true);
|
|
||||||
} finally {
|
|
||||||
modal.dismiss();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,6 +24,8 @@ import { CoreCourseSectionSelectorComponent } from './section-selector/section-s
|
||||||
import { CoreCourseTagAreaComponent } from './tag-area/tag-area';
|
import { CoreCourseTagAreaComponent } from './tag-area/tag-area';
|
||||||
import { CoreCourseUnsupportedModuleComponent } from './unsupported-module/unsupported-module';
|
import { CoreCourseUnsupportedModuleComponent } from './unsupported-module/unsupported-module';
|
||||||
import { CoreCourseModuleCompletionLegacyComponent } from './module-completion-legacy/module-completion-legacy';
|
import { CoreCourseModuleCompletionLegacyComponent } from './module-completion-legacy/module-completion-legacy';
|
||||||
|
import { CoreCourseModuleInfoComponent } from './module-info/module-info';
|
||||||
|
import { CoreCourseModuleManualCompletionComponent } from './module-manual-completion/module-manual-completion';
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
declarations: [
|
declarations: [
|
||||||
|
@ -32,6 +34,8 @@ import { CoreCourseModuleCompletionLegacyComponent } from './module-completion-l
|
||||||
CoreCourseModuleCompletionComponent,
|
CoreCourseModuleCompletionComponent,
|
||||||
CoreCourseModuleCompletionLegacyComponent,
|
CoreCourseModuleCompletionLegacyComponent,
|
||||||
CoreCourseModuleDescriptionComponent,
|
CoreCourseModuleDescriptionComponent,
|
||||||
|
CoreCourseModuleInfoComponent,
|
||||||
|
CoreCourseModuleManualCompletionComponent,
|
||||||
CoreCourseSectionSelectorComponent,
|
CoreCourseSectionSelectorComponent,
|
||||||
CoreCourseTagAreaComponent,
|
CoreCourseTagAreaComponent,
|
||||||
CoreCourseUnsupportedModuleComponent,
|
CoreCourseUnsupportedModuleComponent,
|
||||||
|
@ -46,6 +50,8 @@ import { CoreCourseModuleCompletionLegacyComponent } from './module-completion-l
|
||||||
CoreCourseModuleCompletionComponent,
|
CoreCourseModuleCompletionComponent,
|
||||||
CoreCourseModuleCompletionLegacyComponent,
|
CoreCourseModuleCompletionLegacyComponent,
|
||||||
CoreCourseModuleDescriptionComponent,
|
CoreCourseModuleDescriptionComponent,
|
||||||
|
CoreCourseModuleInfoComponent,
|
||||||
|
CoreCourseModuleManualCompletionComponent,
|
||||||
CoreCourseSectionSelectorComponent,
|
CoreCourseSectionSelectorComponent,
|
||||||
CoreCourseTagAreaComponent,
|
CoreCourseTagAreaComponent,
|
||||||
CoreCourseUnsupportedModuleComponent,
|
CoreCourseUnsupportedModuleComponent,
|
||||||
|
|
|
@ -19,6 +19,7 @@ import { CoreCourseProvider } from '@features/course/services/course';
|
||||||
import { CoreFilterHelper } from '@features/filter/services/filter-helper';
|
import { CoreFilterHelper } from '@features/filter/services/filter-helper';
|
||||||
import { Translate } from '@singletons';
|
import { Translate } from '@singletons';
|
||||||
import { CoreCourseModuleCompletionBaseComponent } from '@features/course/classes/module-completion';
|
import { CoreCourseModuleCompletionBaseComponent } from '@features/course/classes/module-completion';
|
||||||
|
import { CoreCourseHelper } from '@features/course/services/course-helper';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Component to handle activity completion in sites previous to 3.11.
|
* Component to handle activity completion in sites previous to 3.11.
|
||||||
|
@ -115,4 +116,21 @@ export class CoreCourseModuleCompletionLegacyComponent extends CoreCourseModuleC
|
||||||
this.completionDescription = Translate.instant(langKey, translateParams);
|
this.completionDescription = Translate.instant(langKey, translateParams);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Completion clicked.
|
||||||
|
*
|
||||||
|
* @param event The click event.
|
||||||
|
*/
|
||||||
|
async completionClicked(event: Event): Promise<void> {
|
||||||
|
if (!this.completion) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await CoreCourseHelper.changeManualCompletion(this.completion, event);
|
||||||
|
|
||||||
|
this.calculateData();
|
||||||
|
|
||||||
|
this.completionChanged.emit(this.completion);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,27 +27,6 @@
|
||||||
</ng-container>
|
</ng-container>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div *ngIf="completion && !completion.isautomatic && (showCompletionConditions || showManualCompletion)"
|
<core-course-module-manual-completion *ngIf="showManualCompletion" [completion]="completion" [moduleName]="moduleName"
|
||||||
class="core-module-manual-completion">
|
(completionChanged)="completionChanged.emit($event)">
|
||||||
|
</core-course-module-manual-completion>
|
||||||
<ng-container *ngIf="completion.istrackeduser">
|
|
||||||
<ng-container *ngIf="completion.state">
|
|
||||||
<ion-button color="success" fill="outline" [attr.aria-label]="accessibleDescription"
|
|
||||||
(click)="completionClicked($event)">
|
|
||||||
<ion-icon name="fas-check" slot="start" aria-hidden="true"></ion-icon>
|
|
||||||
{{ 'core.course.completion_manual:done' | translate }}
|
|
||||||
</ion-button>
|
|
||||||
</ng-container>
|
|
||||||
<ng-container *ngIf="!completion.state">
|
|
||||||
<ion-button color="light" [attr.aria-label]="accessibleDescription" (click)="completionClicked($event)">
|
|
||||||
{{ 'core.course.completion_manual:markdone' | translate }}
|
|
||||||
</ion-button>
|
|
||||||
</ng-container>
|
|
||||||
</ng-container>
|
|
||||||
|
|
||||||
<ng-container *ngIf="!completion.istrackeduser">
|
|
||||||
<ion-button disabled="true" color="light">
|
|
||||||
{{ 'core.course.completion_manual:markdone' | translate }}
|
|
||||||
</ion-button>
|
|
||||||
</ng-container>
|
|
||||||
</div>
|
|
||||||
|
|
|
@ -9,10 +9,4 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.core-module-manual-completion {
|
|
||||||
ion-button {
|
|
||||||
text-transform: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,7 +35,7 @@ import { Translate } from '@singletons';
|
||||||
export class CoreCourseModuleCompletionComponent extends CoreCourseModuleCompletionBaseComponent {
|
export class CoreCourseModuleCompletionComponent extends CoreCourseModuleCompletionBaseComponent {
|
||||||
|
|
||||||
@Input() showCompletionConditions = false; // Whether to show activity completion conditions.
|
@Input() showCompletionConditions = false; // Whether to show activity completion conditions.
|
||||||
@Input() showManualCompletion = false; // Whether to show manual completion when completion conditions are disabled.
|
@Input() showManualCompletion = false; // Whether to show manual completion.
|
||||||
|
|
||||||
details?: CompletionRule[];
|
details?: CompletionRule[];
|
||||||
accessibleDescription: string | null = null;
|
accessibleDescription: string | null = null;
|
||||||
|
@ -48,21 +48,6 @@ export class CoreCourseModuleCompletionComponent extends CoreCourseModuleComplet
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set an accessible description for manual completions with overridden completion state.
|
|
||||||
if (!this.completion.isautomatic && this.completion.overrideby) {
|
|
||||||
const setByData = {
|
|
||||||
$a: {
|
|
||||||
activityname: this.moduleName,
|
|
||||||
setby: this.completion.overrideby,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
const setByLangKey = this.completion.state ? 'completion_setby:manual:done' : 'completion_setby:manual:markdone';
|
|
||||||
this.accessibleDescription = Translate.instant('core.course.' + setByLangKey, setByData);
|
|
||||||
} else {
|
|
||||||
const langKey = this.completion.state ? 'completion_manual:aria:done' : 'completion_manual:aria:markdone';
|
|
||||||
this.accessibleDescription = Translate.instant('core.course.' + langKey, { $a: this.moduleName });
|
|
||||||
}
|
|
||||||
|
|
||||||
// Format rules.
|
// Format rules.
|
||||||
this.details = this.completion.details.map((rule: CompletionRule) => {
|
this.details = this.completion.details.map((rule: CompletionRule) => {
|
||||||
rule.statuscomplete = rule.rulevalue.status == CoreCourseProvider.COMPLETION_COMPLETE ||
|
rule.statuscomplete = rule.rulevalue.status == CoreCourseProvider.COMPLETION_COMPLETE ||
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
<ion-card *ngIf="module.dates?.length || (module.completiondata && (module.completiondata.isautomatic || showManualCompletion))">
|
||||||
|
<ion-item class="ion-text-wrap">
|
||||||
|
<ion-label>
|
||||||
|
<!-- Activity dates. -->
|
||||||
|
<div *ngIf="module.dates && module.dates.length" class="core-module-dates">
|
||||||
|
<p *ngFor="let date of module.dates">
|
||||||
|
<strong>{{ date.label }}</strong> {{ date.timestamp * 1000 | coreFormatDate:'strftimedatetime' }}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Module completion. -->
|
||||||
|
<core-course-module-completion *ngIf="module.completiondata" [completion]="module.completiondata"
|
||||||
|
[moduleName]="module.name" [moduleId]="module.id" [showCompletionConditions]="true"
|
||||||
|
[showManualCompletion]="showManualCompletion" (completionChanged)="completionChanged.emit($event)">
|
||||||
|
</core-course-module-completion>
|
||||||
|
</ion-label>
|
||||||
|
</ion-item>
|
||||||
|
</ion-card>
|
|
@ -0,0 +1,31 @@
|
||||||
|
// (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, EventEmitter, Input, Output } from '@angular/core';
|
||||||
|
import { CoreCourseModule, CoreCourseModuleCompletionData } from '@features/course/services/course-helper';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Display info about a module: dates and completion.
|
||||||
|
*/
|
||||||
|
@Component({
|
||||||
|
selector: 'core-course-module-info',
|
||||||
|
templateUrl: 'core-course-module-info.html',
|
||||||
|
})
|
||||||
|
export class CoreCourseModuleInfoComponent {
|
||||||
|
|
||||||
|
@Input() module!: CoreCourseModule; // The module to render.
|
||||||
|
@Input() showManualCompletion = false; // Whether to show manual completion.
|
||||||
|
@Output() completionChanged = new EventEmitter<CoreCourseModuleCompletionData>(); // Notify when completion changes.
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
<div *ngIf="completion && !completion.isautomatic" class="core-module-manual-completion">
|
||||||
|
|
||||||
|
<ng-container *ngIf="completion.istrackeduser">
|
||||||
|
<ng-container *ngIf="completion.state">
|
||||||
|
<ion-button color="success" fill="outline" [attr.aria-label]="accessibleDescription"
|
||||||
|
(click)="completionClicked($event)">
|
||||||
|
<ion-icon name="fas-check" slot="start" aria-hidden="true"></ion-icon>
|
||||||
|
{{ 'core.course.completion_manual:done' | translate }}
|
||||||
|
</ion-button>
|
||||||
|
</ng-container>
|
||||||
|
<ng-container *ngIf="!completion.state">
|
||||||
|
<ion-button color="light" [attr.aria-label]="accessibleDescription" (click)="completionClicked($event)">
|
||||||
|
{{ 'core.course.completion_manual:markdone' | translate }}
|
||||||
|
</ion-button>
|
||||||
|
</ng-container>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
<ng-container *ngIf="!completion.istrackeduser">
|
||||||
|
<ion-button disabled="true" color="light">
|
||||||
|
{{ 'core.course.completion_manual:markdone' | translate }}
|
||||||
|
</ion-button>
|
||||||
|
</ng-container>
|
||||||
|
</div>
|
|
@ -0,0 +1,5 @@
|
||||||
|
:host {
|
||||||
|
ion-button {
|
||||||
|
text-transform: none;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,109 @@
|
||||||
|
// (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, EventEmitter, Input, OnChanges, OnDestroy, OnInit, Output, SimpleChange } from '@angular/core';
|
||||||
|
|
||||||
|
import { CoreCourseHelper, CoreCourseModuleCompletionData } from '@features/course/services/course-helper';
|
||||||
|
import { Translate } from '@singletons';
|
||||||
|
import { CoreEventObserver, CoreEvents } from '@singletons/events';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Component to display a button for manual completion.
|
||||||
|
*/
|
||||||
|
@Component({
|
||||||
|
selector: 'core-course-module-manual-completion',
|
||||||
|
templateUrl: 'core-course-module-manual-completion.html',
|
||||||
|
styleUrls: ['module-manual-completion.scss'],
|
||||||
|
})
|
||||||
|
export class CoreCourseModuleManualCompletionComponent implements OnInit, OnChanges, OnDestroy {
|
||||||
|
|
||||||
|
@Input() completion?: CoreCourseModuleCompletionData; // The completion status.
|
||||||
|
@Input() moduleName?: string; // The name of the module this completion affects.
|
||||||
|
@Output() completionChanged = new EventEmitter<CoreCourseModuleCompletionData>(); // Notify when completion changes.
|
||||||
|
|
||||||
|
accessibleDescription: string | null = null;
|
||||||
|
|
||||||
|
protected manualChangedObserver?: CoreEventObserver;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritdoc
|
||||||
|
*/
|
||||||
|
ngOnInit(): void {
|
||||||
|
this.manualChangedObserver = CoreEvents.on(CoreEvents.MANUAL_COMPLETION_CHANGED, (data) => {
|
||||||
|
if (this.completion && this.completion.cmid == data.completion.cmid) {
|
||||||
|
this.completion = data.completion;
|
||||||
|
this.calculateData();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritdoc
|
||||||
|
*/
|
||||||
|
ngOnChanges(changes: { [name: string]: SimpleChange }): void {
|
||||||
|
if (changes.completion && this.completion) {
|
||||||
|
this.calculateData();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritdoc
|
||||||
|
*/
|
||||||
|
protected calculateData(): void {
|
||||||
|
if (!this.completion?.isautomatic) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set an accessible description for manual completions with overridden completion state.
|
||||||
|
if (this.completion.overrideby) {
|
||||||
|
const setByData = {
|
||||||
|
$a: {
|
||||||
|
activityname: this.moduleName,
|
||||||
|
setby: this.completion.overrideby,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
const setByLangKey = this.completion.state ? 'completion_setby:manual:done' : 'completion_setby:manual:markdone';
|
||||||
|
this.accessibleDescription = Translate.instant('core.course.' + setByLangKey, setByData);
|
||||||
|
} else {
|
||||||
|
const langKey = this.completion.state ? 'completion_manual:aria:done' : 'completion_manual:aria:markdone';
|
||||||
|
this.accessibleDescription = Translate.instant('core.course.' + langKey, { $a: this.moduleName });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Completion clicked.
|
||||||
|
*
|
||||||
|
* @param event The click event.
|
||||||
|
*/
|
||||||
|
async completionClicked(event: Event): Promise<void> {
|
||||||
|
if (!this.completion) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await CoreCourseHelper.changeManualCompletion(this.completion, event);
|
||||||
|
|
||||||
|
this.calculateData();
|
||||||
|
|
||||||
|
CoreEvents.trigger(CoreEvents.MANUAL_COMPLETION_CHANGED, { completion: this.completion });
|
||||||
|
this.completionChanged.emit(this.completion);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritdoc
|
||||||
|
*/
|
||||||
|
ngOnDestroy(): void {
|
||||||
|
this.manualChangedObserver?.off();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -67,6 +67,7 @@ import { CoreNetworkError } from '@classes/errors/network-error';
|
||||||
import { CoreSiteHome } from '@features/sitehome/services/sitehome';
|
import { CoreSiteHome } from '@features/sitehome/services/sitehome';
|
||||||
import { CoreNavigator } from '@services/navigator';
|
import { CoreNavigator } from '@services/navigator';
|
||||||
import { CoreSiteHomeHomeHandlerService } from '@features/sitehome/services/handlers/sitehome-home';
|
import { CoreSiteHomeHomeHandlerService } from '@features/sitehome/services/handlers/sitehome-home';
|
||||||
|
import { CoreStatusWithWarningsWSResponse } from '@services/ws';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Prefetch info of a module.
|
* Prefetch info of a module.
|
||||||
|
@ -1890,6 +1891,52 @@ export class CoreCourseHelperProvider {
|
||||||
await Promise.all(promises);
|
await Promise.all(promises);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Completion clicked.
|
||||||
|
*
|
||||||
|
* @param completion The completion.
|
||||||
|
* @param event The click event.
|
||||||
|
* @return Promise resolved with the result.
|
||||||
|
*/
|
||||||
|
async changeManualCompletion(
|
||||||
|
completion: CoreCourseModuleCompletionData,
|
||||||
|
event?: Event,
|
||||||
|
): Promise<CoreStatusWithWarningsWSResponse | void> {
|
||||||
|
if (!completion) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof completion.cmid == 'undefined' || completion.tracking !== 1) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
event?.preventDefault();
|
||||||
|
event?.stopPropagation();
|
||||||
|
|
||||||
|
const modal = await CoreDomUtils.showModalLoading();
|
||||||
|
completion.state = completion.state === 1 ? 0 : 1;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await CoreCourse.markCompletedManually(
|
||||||
|
completion.cmid,
|
||||||
|
completion.state === 1,
|
||||||
|
completion.courseId!,
|
||||||
|
completion.courseName,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (response.offline) {
|
||||||
|
completion.offline = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return response;
|
||||||
|
} catch (error) {
|
||||||
|
completion.state = completion.state === 1 ? 0 : 1;
|
||||||
|
CoreDomUtils.showErrorModalDefault(error, 'core.errorchangecompletion', true);
|
||||||
|
} finally {
|
||||||
|
modal.dismiss();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const CoreCourseHelper = makeSingleton(CoreCourseHelperProvider);
|
export const CoreCourseHelper = makeSingleton(CoreCourseHelperProvider);
|
||||||
|
|
|
@ -150,9 +150,12 @@ export class CoreCourseProvider {
|
||||||
* @param completion Completion status of the module.
|
* @param completion Completion status of the module.
|
||||||
*/
|
*/
|
||||||
checkModuleCompletion(courseId: number, completion?: CoreCourseModuleCompletionData): void {
|
checkModuleCompletion(courseId: number, completion?: CoreCourseModuleCompletionData): void {
|
||||||
if (completion && completion.tracking === 2 && completion.state === 0) {
|
if (completion && completion.tracking === CoreCourseProvider.COMPLETION_TRACKING_AUTOMATIC && completion.state === 0) {
|
||||||
this.invalidateSections(courseId).finally(() => {
|
this.invalidateSections(courseId).finally(() => {
|
||||||
CoreEvents.trigger(CoreEvents.COMPLETION_MODULE_VIEWED, { courseId: courseId });
|
CoreEvents.trigger(CoreEvents.COMPLETION_MODULE_VIEWED, {
|
||||||
|
courseId: courseId,
|
||||||
|
cmId: completion.cmid,
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -969,6 +972,9 @@ export class CoreCourseProvider {
|
||||||
// Ignore errors, shouldn't happen.
|
// Ignore errors, shouldn't happen.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Invalidate module now, completion has changed.
|
||||||
|
await this.invalidateModule(cmId, siteId);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (CoreUtils.isWebServiceError(error) || !courseId) {
|
if (CoreUtils.isWebServiceError(error) || !courseId) {
|
||||||
|
|
|
@ -18,6 +18,7 @@ import { CoreLogger } from '@singletons/logger';
|
||||||
import { CoreSite, CoreSiteInfoResponse, CoreSitePublicConfigResponse } from '@classes/site';
|
import { CoreSite, CoreSiteInfoResponse, CoreSitePublicConfigResponse } from '@classes/site';
|
||||||
import { CoreFilepoolComponentFileEventData } from '@services/filepool';
|
import { CoreFilepoolComponentFileEventData } from '@services/filepool';
|
||||||
import { CoreNavigationOptions } from '@services/navigator';
|
import { CoreNavigationOptions } from '@services/navigator';
|
||||||
|
import { CoreCourseModuleCompletionData } from '@features/course/services/course-helper';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Observer instance to stop listening to an event.
|
* Observer instance to stop listening to an event.
|
||||||
|
@ -45,6 +46,7 @@ export interface CoreEventsData {
|
||||||
[CoreEvents.NOTIFICATION_SOUND_CHANGED]: CoreEventNotificationSoundChangedData;
|
[CoreEvents.NOTIFICATION_SOUND_CHANGED]: CoreEventNotificationSoundChangedData;
|
||||||
[CoreEvents.SELECT_COURSE_TAB]: CoreEventSelectCourseTabData;
|
[CoreEvents.SELECT_COURSE_TAB]: CoreEventSelectCourseTabData;
|
||||||
[CoreEvents.COMPLETION_MODULE_VIEWED]: CoreEventCompletionModuleViewedData;
|
[CoreEvents.COMPLETION_MODULE_VIEWED]: CoreEventCompletionModuleViewedData;
|
||||||
|
[CoreEvents.MANUAL_COMPLETION_CHANGED]: CoreEventManualCompletionChangedData;
|
||||||
[CoreEvents.SECTION_STATUS_CHANGED]: CoreEventSectionStatusChangedData;
|
[CoreEvents.SECTION_STATUS_CHANGED]: CoreEventSectionStatusChangedData;
|
||||||
[CoreEvents.ACTIVITY_DATA_SENT]: CoreEventActivityDataSentData;
|
[CoreEvents.ACTIVITY_DATA_SENT]: CoreEventActivityDataSentData;
|
||||||
[CoreEvents.IAB_LOAD_START]: InAppBrowserEvent;
|
[CoreEvents.IAB_LOAD_START]: InAppBrowserEvent;
|
||||||
|
@ -53,7 +55,7 @@ export interface CoreEventsData {
|
||||||
[CoreEvents.COMPONENT_FILE_ACTION]: CoreFilepoolComponentFileEventData;
|
[CoreEvents.COMPONENT_FILE_ACTION]: CoreFilepoolComponentFileEventData;
|
||||||
[CoreEvents.FILE_SHARED]: CoreEventFileSharedData;
|
[CoreEvents.FILE_SHARED]: CoreEventFileSharedData;
|
||||||
[CoreEvents.APP_LAUNCHED_URL]: CoreEventAppLaunchedData;
|
[CoreEvents.APP_LAUNCHED_URL]: CoreEventAppLaunchedData;
|
||||||
};
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Service to send and listen to events.
|
* Service to send and listen to events.
|
||||||
|
@ -72,6 +74,7 @@ export class CoreEvents {
|
||||||
static readonly SITE_UPDATED = 'site_updated';
|
static readonly SITE_UPDATED = 'site_updated';
|
||||||
static readonly SITE_DELETED = 'site_deleted';
|
static readonly SITE_DELETED = 'site_deleted';
|
||||||
static readonly COMPLETION_MODULE_VIEWED = 'completion_module_viewed';
|
static readonly COMPLETION_MODULE_VIEWED = 'completion_module_viewed';
|
||||||
|
static readonly MANUAL_COMPLETION_CHANGED = 'manual_completion_changed';
|
||||||
static readonly USER_DELETED = 'user_deleted';
|
static readonly USER_DELETED = 'user_deleted';
|
||||||
static readonly PACKAGE_STATUS_CHANGED = 'package_status_changed';
|
static readonly PACKAGE_STATUS_CHANGED = 'package_status_changed';
|
||||||
static readonly COURSE_STATUS_CHANGED = 'course_status_changed';
|
static readonly COURSE_STATUS_CHANGED = 'course_status_changed';
|
||||||
|
@ -330,7 +333,15 @@ export type CoreEventSelectCourseTabData = {
|
||||||
* Data passed to COMPLETION_MODULE_VIEWED event.
|
* Data passed to COMPLETION_MODULE_VIEWED event.
|
||||||
*/
|
*/
|
||||||
export type CoreEventCompletionModuleViewedData = {
|
export type CoreEventCompletionModuleViewedData = {
|
||||||
courseId?: number;
|
courseId: number;
|
||||||
|
cmId?: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Data passed to MANUAL_COMPLETION_CHANGED event.
|
||||||
|
*/
|
||||||
|
export type CoreEventManualCompletionChangedData = {
|
||||||
|
completion: CoreCourseModuleCompletionData;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Reference in New Issue