MOBILE-2310 course: Implement completion and fix PTR issues in section
|
@ -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 |
|
@ -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 |
|
@ -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 |
|
@ -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 |
|
@ -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 |
|
@ -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 |
|
@ -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 |
|
@ -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 |
|
@ -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 |
|
@ -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 |
|
@ -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 {}
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
<a *ngIf="completion" class="core-completion-container" (click)="completionClicked($event)">
|
||||
<img [src]="completionImage" [alt]="completionDescription" [title]="completionDescription">
|
||||
</a>
|
|
@ -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});
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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>
|
||||
|
|
|
@ -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.
|
||||
*/
|
||||
|
|