MOBILE-2310 course: Implement completion and fix PTR issues in section

main
Dani Palou 2018-01-02 12:21:53 +01:00
parent 3c8ad5b7b3
commit 2e73942083
17 changed files with 352 additions and 61 deletions

View File

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 15.1.0, SVG Export Plug-In -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" [
<!ENTITY ns_flows "http://ns.adobe.com/Flows/1.0/">
]>
<svg version="1.1"
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:a="http://ns.adobe.com/AdobeSVGViewerExtensions/3.0/"
x="0px" y="0px" width="16px" height="16px" viewBox="0 0 16 16" style="overflow:visible;enable-background:new 0 0 16 16;"
xml:space="preserve" preserveAspectRatio="xMinYMid meet">
<defs>
</defs>
<path style="fill:#999999;" d="M10,0v2H6V0H10z M11,2h1c1.1,0,2,0.9,2,2v1h2V2c0-1.1-0.9-2-2-2h-3V2z M16,6h-2v4h2V6z M14,11v1
c0,1.1-0.9,2-2,2h-1v2h3c1.1,0,2-0.9,2-2v-3H14z M10,16v-2H6v2H10z M5,14H4c-1.1,0-2-0.9-2-2v-1H0v3c0,1.1,0.9,2,2,2h3V14z M0,10h2
V6H0V10z M2,5V4c0-1.1,0.9-2,2-2h1V0H2C0.9,0,0,0.9,0,2v3H2z"/>
<path style="fill:#FF403C;" d="M10.2,8l2.6-2.6c0.4-0.4,0.4-1,0-1.4L12,3.3c-0.4-0.4-1-0.4-1.4,0L8,5.9L5.4,3.3
c-0.4-0.4-1-0.4-1.4,0L3.3,4c-0.4,0.4-0.4,1,0,1.4L5.9,8l-2.6,2.6C3,11,3,11.6,3.3,12l0.7,0.7c0.4,0.4,1,0.4,1.4,0L8,10.2l2.5,2.5
c0.4,0.4,1,0.4,1.4,0l0.7-0.7c0.4-0.4,0.4-1,0-1.4L10.2,8z"/>
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@ -0,0 +1,3 @@
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" [
<!ENTITY ns_flows "http://ns.adobe.com/Flows/1.0/">
]><svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16" preserveAspectRatio="xMinYMid meet" overflow="visible"><path d="M10 0v2H6V0h4zm1 2h1c1.1 0 2 .9 2 2v1h2V2c0-1.1-.9-2-2-2h-3v2zm5 4h-2v4h2V6zm-2 5v1c0 1.1-.9 2-2 2h-1v2h3c1.1 0 2-.9 2-2v-3h-2zm-4 5v-2H6v2h4zm-5-2H4c-1.1 0-2-.9-2-2v-1H0v3c0 1.1.9 2 2 2h3v-2zm-5-4h2V6H0v4zm2-5V4c0-1.1.9-2 2-2h1V0H2C.9 0 0 .9 0 2v3h2z" fill="#FF2727"/></svg>

After

Width:  |  Height:  |  Size: 579 B

View File

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 15.1.0, SVG Export Plug-In -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" [
<!ENTITY ns_flows "http://ns.adobe.com/Flows/1.0/">
]>
<svg version="1.1"
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:a="http://ns.adobe.com/AdobeSVGViewerExtensions/3.0/"
x="0px" y="0px" width="16px" height="16px" viewBox="0 0 16 16" style="overflow:visible;enable-background:new 0 0 16 16;"
xml:space="preserve" preserveAspectRatio="xMinYMid meet">
<defs>
</defs>
<path style="fill:#999999;" d="M10,0v2H6V0H10z M11,2h1c1.1,0,2,0.9,2,2v1h2V2c0-1.1-0.9-2-2-2h-3V2z M16,6h-2v4h2V6z M14,11v1
c0,1.1-0.9,2-2,2h-1v2h3c1.1,0,2-0.9,2-2v-3H14z M10,16v-2H6v2H10z M5,14H4c-1.1,0-2-0.9-2-2v-1H0v3c0,1.1,0.9,2,2,2h3V14z M0,10h2
V6H0V10z M2,5V4c0-1.1,0.9-2,2-2h1V0H2C0.9,0,0,0.9,0,2v3H2z"/>
</svg>

After

Width:  |  Height:  |  Size: 955 B

View File

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 15.1.0, SVG Export Plug-In -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" [
<!ENTITY ns_flows "http://ns.adobe.com/Flows/1.0/">
]>
<svg version="1.1"
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:a="http://ns.adobe.com/AdobeSVGViewerExtensions/3.0/"
x="0px" y="0px" width="16px" height="16px" viewBox="0 0 16 16" style="overflow:visible;enable-background:new 0 0 16 16;"
xml:space="preserve" preserveAspectRatio="xMinYMid meet">
<defs>
</defs>
<path style="fill:#999999;" d="M10,0v2H6V0H10z M11,2h1c0.4,0,0.8,0.1,1.1,0.3c0.3-0.3,0.8-0.4,1.2-0.4c0.5,0,1,0.2,1.4,0.6L16,2.8
V2c0-1.1-0.9-2-2-2h-3V2z M14,10h2V6.4l-2,2V10z M14,11v1c0,1.1-0.9,2-2,2h-1v2h3c1.1,0,2-0.9,2-2v-3H14z M10,16v-2H6v2H10z M5,14H4
c-1.1,0-2-0.9-2-2v-1H0v3c0,1.1,0.9,2,2,2h3V14z M0,10h2V6H0V10z M2,5V4c0-1.1,0.9-2,2-2h1V0H2C0.9,0,0,0.9,0,2v3H2z"/>
<path style="fill:#99CC33;" d="M15.7,3.9L15,3.2c-0.4-0.4-1-0.4-1.4,0l-6,6L5.4,7C5,6.7,4.4,6.7,4,7L3.3,7.7c-0.4,0.4-0.4,1,0,1.4
l3.6,3.6c0.4,0.4,1,0.4,1.4,0l7.4-7.4C16.1,4.9,16.1,4.3,15.7,3.9z"/>
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@ -0,0 +1,3 @@
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" [
<!ENTITY ns_flows "http://ns.adobe.com/Flows/1.0/">
]><svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16" preserveAspectRatio="xMinYMid meet" overflow="visible"><path d="M10 0v2H6V0h4zm1 2h1c.4 0 .8.1 1.1.3.3-.3.8-.4 1.2-.4.5 0 1 .2 1.4.6l.3.3V2c0-1.1-.9-2-2-2h-3v2zm3 8h2V6.4l-2 2V10zm0 1v1c0 1.1-.9 2-2 2h-1v2h3c1.1 0 2-.9 2-2v-3h-2zm-4 5v-2H6v2h4zm-5-2H4c-1.1 0-2-.9-2-2v-1H0v3c0 1.1.9 2 2 2h3v-2zm-5-4h2V6H0v4zm2-5V4c0-1.1.9-2 2-2h1V0H2C.9 0 0 .9 0 2v3h2z" fill="#FF2727"/><path d="M15.7 3.9l-.7-.7c-.4-.4-1-.4-1.4 0l-6 6L5.4 7c-.4-.3-1-.3-1.4 0l-.7.7c-.4.4-.4 1 0 1.4l3.6 3.6c.4.4 1 .4 1.4 0l7.4-7.4c.4-.4.4-1 0-1.4z" fill="#76A1F0"/></svg>

After

Width:  |  Height:  |  Size: 779 B

View File

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 15.1.0, SVG Export Plug-In -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" [
<!ENTITY ns_flows "http://ns.adobe.com/Flows/1.0/">
]>
<svg version="1.1"
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:a="http://ns.adobe.com/AdobeSVGViewerExtensions/3.0/"
x="0px" y="0px" width="16px" height="16px" viewBox="0 0 16 16" style="overflow:visible;enable-background:new 0 0 16 16;"
xml:space="preserve" preserveAspectRatio="xMinYMid meet">
<defs>
</defs>
<path style="fill:#999999;" d="M10,0v2H6V0H10z M11,2h1c0.4,0,0.8,0.1,1.1,0.3c0.3-0.3,0.8-0.4,1.2-0.4c0.5,0,1,0.2,1.4,0.6L16,2.8
V2c0-1.1-0.9-2-2-2h-3V2z M14,10h2V6.4l-2,2V10z M14,11v1c0,1.1-0.9,2-2,2h-1v2h3c1.1,0,2-0.9,2-2v-3H14z M10,16v-2H6v2H10z M5,14H4
c-1.1,0-2-0.9-2-2v-1H0v3c0,1.1,0.9,2,2,2h3V14z M0,10h2V6H0V10z M2,5V4c0-1.1,0.9-2,2-2h1V0H2C0.9,0,0,0.9,0,2v3H2z"/>
<path style="fill:#76A1F0;" d="M15.7,3.9L15,3.2c-0.4-0.4-1-0.4-1.4,0l-6,6L5.4,7C5,6.7,4.4,6.7,4,7L3.3,7.7c-0.4,0.4-0.4,1,0,1.4
l3.6,3.6c0.4,0.4,1,0.4,1.4,0l7.4-7.4C16.1,4.9,16.1,4.3,15.7,3.9z"/>
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@ -0,0 +1,3 @@
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" [
<!ENTITY ns_flows "http://ns.adobe.com/Flows/1.0/">
]><svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16" preserveAspectRatio="xMinYMid meet" overflow="visible"><path d="M14 0H2C.9 0 0 .9 0 2v12c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2V2c0-1.1-.9-2-2-2zm0 12c0 1.1-.9 2-2 2H4c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h8c1.1 0 2 .9 2 2v8z" fill="#FF2727"/></svg>

After

Width:  |  Height:  |  Size: 476 B

View File

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 15.1.0, SVG Export Plug-In -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" [
<!ENTITY ns_flows "http://ns.adobe.com/Flows/1.0/">
]>
<svg version="1.1"
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:a="http://ns.adobe.com/AdobeSVGViewerExtensions/3.0/"
x="0px" y="0px" width="16px" height="16px" viewBox="0 0 16 16" style="overflow:visible;enable-background:new 0 0 16 16;"
xml:space="preserve" preserveAspectRatio="xMinYMid meet">
<defs>
</defs>
<path style="fill:#999999;" d="M14,0H2C0.9,0,0,0.9,0,2v12c0,1.1,0.9,2,2,2h12c1.1,0,2-0.9,2-2V2C16,0.9,15.1,0,14,0z M14,12
c0,1.1-0.9,2-2,2H4c-1.1,0-2-0.9-2-2V4c0-1.1,0.9-2,2-2h8c1.1,0,2,0.9,2,2V12z"/>
</svg>

After

Width:  |  Height:  |  Size: 841 B

View File

@ -0,0 +1,3 @@
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" [
<!ENTITY ns_flows "http://ns.adobe.com/Flows/1.0/">
]><svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16" preserveAspectRatio="xMinYMid meet" overflow="visible"><path d="M14 8.4V12c0 1.1-.9 2-2 2H4c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h8c.4 0 .8.1 1.1.3.3-.3.8-.4 1.2-.4.5 0 1 .2 1.4.6l.3.3V2c0-1.1-.9-2-2-2H2C.9 0 0 .9 0 2v12c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2V6.4l-2 2z" fill="#FF2727"/><path d="M15.7 3.9l-.7-.7c-.4-.4-1-.4-1.4 0l-6 6L5.4 7c-.4-.3-1-.3-1.4 0l-.7.7c-.4.4-.4 1 0 1.4l3.6 3.6c.4.4 1 .4 1.4 0l7.4-7.4c.4-.4.4-1 0-1.4z" fill="#76A1F0"/></svg>

After

Width:  |  Height:  |  Size: 682 B

View File

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 15.1.0, SVG Export Plug-In -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" [
<!ENTITY ns_flows "http://ns.adobe.com/Flows/1.0/">
]>
<svg version="1.1"
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:a="http://ns.adobe.com/AdobeSVGViewerExtensions/3.0/"
x="0px" y="0px" width="16px" height="16px" viewBox="0 0 16 16" style="overflow:visible;enable-background:new 0 0 16 16;"
xml:space="preserve" preserveAspectRatio="xMinYMid meet">
<defs>
</defs>
<path style="fill:#999999;" d="M14,8.4V12c0,1.1-0.9,2-2,2H4c-1.1,0-2-0.9-2-2V4c0-1.1,0.9-2,2-2h8c0.4,0,0.8,0.1,1.1,0.3
c0.3-0.3,0.8-0.4,1.2-0.4c0.5,0,1,0.2,1.4,0.6L16,2.8V2c0-1.1-0.9-2-2-2H2C0.9,0,0,0.9,0,2v12c0,1.1,0.9,2,2,2h12c1.1,0,2-0.9,2-2
V6.4L14,8.4z"/>
<path style="fill:#76A1F0;" d="M15.7,3.9L15,3.2c-0.4-0.4-1-0.4-1.4,0l-6,6L5.4,7C5,6.7,4.4,6.7,4,7L3.3,7.7c-0.4,0.4-0.4,1,0,1.4
l3.6,3.6c0.4,0.4,1,0.4,1.4,0l7.4-7.4C16.1,4.9,16.1,4.3,15.7,3.9z"/>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -20,11 +20,13 @@ import { CoreComponentsModule } from '../../../components/components.module';
import { CoreDirectivesModule } from '../../../directives/directives.module';
import { CoreCourseFormatComponent } from './format/format';
import { CoreCourseModuleComponent } from './module/module';
import { CoreCourseModuleCompletionComponent } from './module-completion/module-completion';
@NgModule({
declarations: [
CoreCourseFormatComponent,
CoreCourseModuleComponent
CoreCourseModuleComponent,
CoreCourseModuleCompletionComponent
],
imports: [
CommonModule,
@ -37,7 +39,8 @@ import { CoreCourseModuleComponent } from './module/module';
],
exports: [
CoreCourseFormatComponent,
CoreCourseModuleComponent
CoreCourseModuleComponent,
CoreCourseModuleCompletionComponent
]
})
export class CoreCourseComponentsModule {}

View File

@ -2,9 +2,6 @@
<div *ngIf="!componentInstances.courseFormat">
<!-- Course summary. -->
<ion-list no-lines *ngIf="!componentInstances.courseSummary">
<summary ion-item text-wrap *ngIf="course.summary">
<core-format-text [text]="course.summary" maxHeight="60"></core-format-text>
</summary>
<ion-item *ngIf="course.progress !== false">
<core-progress-bar [progress]="course.progress"></core-progress-bar>
</ion-item>

View File

@ -92,13 +92,27 @@ export class CoreCourseFormatComponent implements OnInit, OnChanges {
* Detect changes on input properties.
*/
ngOnChanges(changes: {[name: string]: SimpleChange}) {
if (!this.selectedSection && changes.sections && this.sections) {
this.sectionChanged(this.cfDelegate.getCurrentSection(this.course, this.sections));
}
if (changes.sections && this.sections) {
if (!this.selectedSection) {
// There is no selected section yet, calculate which one to get.
this.sectionChanged(this.cfDelegate.getCurrentSection(this.course, this.sections));
} else {
// We have a selected section, but the list has changed. Search the section in the list.
let newSection;
for (let i = 0; i < this.sections.length; i++) {
let section = this.sections[i];
if (this.compareSections(section, this.selectedSection)) {
newSection = section;
break;
}
}
if (!Object.keys(this.componentInstances).length) {
// We haven't created any component dynamically, stop.
return;
if (!newSection) {
// Section not found, calculate which one to use.
newSection = this.cfDelegate.getCurrentSection(this.course, this.sections);
}
this.sectionChanged(newSection);
}
}
// Apply the changes to the components and call ngOnChanges if it exists.

View File

@ -0,0 +1,3 @@
<a *ngIf="completion" class="core-completion-container" (click)="completionClicked($event)">
<img [src]="completionImage" [alt]="completionDescription" [title]="completionDescription">
</a>

View File

@ -0,0 +1,150 @@
// (C) Copyright 2015 Martin Dougiamas
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import { Component, Input, Output, EventEmitter, OnChanges, SimpleChange } from '@angular/core';
import { TranslateService } from '@ngx-translate/core';
import { CoreSitesProvider } from '../../../../providers/sites';
import { CoreDomUtilsProvider } from '../../../../providers/utils/dom';
import { CoreTextUtilsProvider } from '../../../../providers/utils/text';
/**
* Component to handle activity completion. It shows a checkbox with the current status, and allows manually changing
* the completion if it's allowed.
*
* Example usage:
*
* <core-course-module-completion [completion]="module.completionstatus" [moduleName]="module.name"
* (completionChanged)="completionChanged()"></core-course-module-completion>
*/
@Component({
selector: 'core-course-module-completion',
templateUrl: 'module-completion.html'
})
export class CoreCourseModuleCompletionComponent implements OnChanges {
@Input() completion: any; // The completion status.
@Input() moduleName?: string; // The name of the module this completion affects.
@Output() completionChanged?: EventEmitter<void>; // Will emit an event when the completion changes.
completionImage: string;
completionDescription: string;
constructor(private textUtils: CoreTextUtilsProvider, private translate: TranslateService,
private domUtils: CoreDomUtilsProvider, private sitesProvider: CoreSitesProvider) {
this.completionChanged = new EventEmitter();
}
/**
* Detect changes on input properties.
*/
ngOnChanges(changes: {[name: string]: SimpleChange}) {
if (changes.completion && this.completion) {
this.showStatus();
}
}
/**
* Completion clicked.
*
* @param {Event} e The click event.
*/
completionClicked(e: Event) : void {
if (this.completion) {
if (typeof this.completion.cmid == 'undefined' || this.completion.tracking !== 1) {
return;
}
e.preventDefault();
e.stopPropagation();
let modal = this.domUtils.showModalLoading(),
params = {
cmid: this.completion.cmid,
completed: this.completion.state === 1 ? 0 : 1
},
currentSite = this.sitesProvider.getCurrentSite();
currentSite.write('core_completion_update_activity_completion_status_manually', params).then((response) => {
if (!response.status) {
return Promise.reject(null);
}
this.completionChanged.emit();
}).catch((error) => {
this.domUtils.showErrorModalDefault(error, 'core.errorchangecompletion', true);
}).finally(() => {
modal.dismiss();
});
}
}
/**
* Set image and description to show as completion icon.
*/
protected showStatus() : void {
let langKey,
moduleName = this.moduleName || '',
image;
if (this.completion.tracking === 1 && this.completion.state === 0) {
image = 'completion-manual-n';
langKey = 'core.completion-alt-manual-n';
} else if (this.completion.tracking === 1 && this.completion.state === 1) {
image = 'completion-manual-y';
langKey = 'core.completion-alt-manual-y';
} else if (this.completion.tracking === 2 && this.completion.state === 0) {
image = 'completion-auto-n';
langKey = 'core.completion-alt-auto-n';
} else if (this.completion.tracking === 2 && this.completion.state === 1) {
image = 'completion-auto-y';
langKey = 'core.completion-alt-auto-y';
} else if (this.completion.tracking === 2 && this.completion.state === 2) {
image = 'completion-auto-pass';
langKey = 'core.completion-alt-auto-pass';
} else if (this.completion.tracking === 2 && this.completion.state === 3) {
image = 'completion-auto-fail';
langKey = 'core.completion-alt-auto-fail';
}
if (image) {
if (this.completion.overrideby > 0) {
image += '-override';
}
this.completionImage = 'assets/img/completion/' + image + '.svg';
}
if (moduleName) {
this.textUtils.formatText(moduleName, true, true, 50).then((modNameFormatted) => {
let promise;
if (this.completion.overrideby > 0) {
langKey += '-override';
// @todo: Get user profile.
// promise = $mmUser.getProfile(scope.completion.overrideby, scope.completion.courseId, true).then(function(profile) {
// return {
// overrideuser: profile.fullname,
// modname: modNameFormatted
// };
// });
} else {
promise = Promise.resolve(modNameFormatted);
}
return promise.then((translateParams) => {
this.completionDescription = this.translate.instant(langKey, {$a: translateParams});
});
});
}
}
}

View File

@ -5,7 +5,7 @@
<core-format-text [text]="module.handlerData.title"></core-format-text>
<div item-end *ngIf="module.uservisible !== false && ((module.handlerData.buttons && module.handlerData.buttons.length > 0) || spinner || module.completionstatus)" class="buttons mm-module-buttons" [ngClass]="{'mm-button-completion': module.completionstatus}">
<!-- <mm-completion ng-if="module.completionstatus" completion="module.completionstatus" module-name="module.name" after-change="completionChanged"></mm-completion> -->
<core-course-module-completion *ngIf="module.completionstatus" [completion]="module.completionstatus" [moduleName]="module.name" (completionChanged)="completionChanged.emit()"></core-course-module-completion>
<button ion-button icon-only clear *ngFor="let button of module.handlerData.buttons" [hidden]="button.hidden" (click)="button.action($event, module, courseId)" class="mm-animate-show-hide" [attr.aria-label]="button.label | translate">
<ion-icon [name]="button.icon" [ios]="button.iosIcon || ''" [md]="button.mdIcon || ''"></ion-icon>

View File

@ -22,6 +22,7 @@ import { CoreCourseProvider } from '../../providers/course';
import { CoreCourseHelperProvider } from '../../providers/helper';
import { CoreCourseFormatDelegate } from '../../providers/format-delegate';
import { CoreCoursesDelegate } from '../../../courses/providers/delegate';
import { CoreCoursesProvider } from '../../../courses/providers/courses';
/**
* Page that displays the list of courses the user is enrolled in.
@ -45,8 +46,8 @@ export class CoreCourseSectionPage implements OnDestroy {
constructor(navParams: NavParams, private courseProvider: CoreCourseProvider, private domUtils: CoreDomUtilsProvider,
private courseFormatDelegate: CoreCourseFormatDelegate, private coursesDelegate: CoreCoursesDelegate,
private translate: TranslateService, private courseHelper: CoreCourseHelperProvider,
private textUtils: CoreTextUtilsProvider, eventsProvider: CoreEventsProvider) {
private translate: TranslateService, private courseHelper: CoreCourseHelperProvider, eventsProvider: CoreEventsProvider,
private textUtils: CoreTextUtilsProvider, private coursesProvider: CoreCoursesProvider) {
this.course = navParams.get('course');
this.title = courseFormatDelegate.getCourseTitle(this.course);
this.moduleId = navParams.get('moduleId');
@ -72,52 +73,57 @@ export class CoreCourseSectionPage implements OnDestroy {
* Fetch and load all the data required for the view.
*/
protected loadData(refresh?: boolean) {
let promises = [],
promise;
// First of all, get the course because the data might have changed.
return this.coursesProvider.getUserCourse(this.course.id).then((course) => {
let promises = [],
promise;
// Get the completion status.
if (this.course.enablecompletion === false) {
// Completion not enabled.
promise = Promise.resolve({});
} else {
promise = this.courseProvider.getActivitiesCompletionStatus(this.course.id).catch(() => {
// It failed, don't use completion.
return {};
});
}
this.course = course;
promises.push(promise.then((completionStatus) => {
// Get all the sections.
promises.push(this.courseProvider.getSections(this.course.id, false, true).then((sections) => {
this.courseHelper.addHandlerDataForModules(sections, this.course.id, this.moduleId, completionStatus);
// Format the name of each section and check if it has content.
this.sections = sections.map((section) => {
this.textUtils.formatText(section.name.trim(), true, true).then((name) => {
section.formattedName = name;
});
section.hasContent = this.courseHelper.sectionHasContent(section);
return section;
// Get the completion status.
if (this.course.enablecompletion === false) {
// Completion not enabled.
promise = Promise.resolve({});
} else {
promise = this.courseProvider.getActivitiesCompletionStatus(this.course.id).catch(() => {
// It failed, don't use completion.
return {};
});
}
promises.push(promise.then((completionStatus) => {
// Get all the sections.
promises.push(this.courseProvider.getSections(this.course.id, false, true).then((sections) => {
this.courseHelper.addHandlerDataForModules(sections, this.course.id, this.moduleId, completionStatus);
if (this.courseFormatDelegate.canViewAllSections(this.course)) {
// Add a fake first section (all sections).
this.sections.unshift({
name: this.translate.instant('core.course.allsections'),
id: CoreCourseProvider.ALL_SECTIONS_ID
// Format the name of each section and check if it has content.
this.sections = sections.map((section) => {
this.textUtils.formatText(section.name.trim(), true, true).then((name) => {
section.formattedName = name;
});
section.hasContent = this.courseHelper.sectionHasContent(section);
return section;
});
}
if (this.courseFormatDelegate.canViewAllSections(this.course)) {
// Add a fake first section (all sections).
this.sections.unshift({
name: this.translate.instant('core.course.allsections'),
id: CoreCourseProvider.ALL_SECTIONS_ID
});
}
}));
}));
}));
// Load the course handlers.
promises.push(this.coursesDelegate.getHandlersToDisplay(this.course, refresh, false).then((handlers) => {
this.courseHandlers = handlers;
}));
// Load the course handlers.
promises.push(this.coursesDelegate.getHandlersToDisplay(this.course, refresh, false).then((handlers) => {
this.courseHandlers = handlers;
}));
return Promise.all(promises).catch((error) => {
this.domUtils.showErrorModalDefault(error, 'mm.course.couldnotloadsectioncontent', true);
return Promise.all(promises).catch((error) => {
this.domUtils.showErrorModalDefault(error, 'core.course.couldnotloadsectioncontent', true);
});
});
}
@ -127,15 +133,7 @@ export class CoreCourseSectionPage implements OnDestroy {
* @param {any} refresher Refresher.
*/
doRefresh(refresher: any) {
let promises = [];
promises.push(this.courseProvider.invalidateSections(this.course.id));
// if ($scope.sections) {
// promises.push($mmCoursePrefetchDelegate.invalidateCourseUpdates(courseId));
// }
Promise.all(promises).finally(() => {
this.invalidateData().finally(() => {
this.loadData(true).finally(() => {
refresher.complete();
});
@ -146,11 +144,27 @@ export class CoreCourseSectionPage implements OnDestroy {
* The completion of any of the modules have changed.
*/
onCompletionChange() {
this.courseProvider.invalidateSections(this.course.id).finally(() => {
this.invalidateData().finally(() => {
this.refreshAfterCompletionChange();
});
}
/**
* Invalidate the data.
*/
protected invalidateData() {
let promises = [];
promises.push(this.courseProvider.invalidateSections(this.course.id));
promises.push(this.coursesProvider.invalidateUserCourses());
// if ($scope.sections) {
// promises.push($mmCoursePrefetchDelegate.invalidateCourseUpdates(courseId));
// }
return Promise.all(promises);
}
/**
* Refresh list after a completion change since there could be new activities.
*/