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 { CoreDirectivesModule } from '../../../directives/directives.module';
|
||||||
import { CoreCourseFormatComponent } from './format/format';
|
import { CoreCourseFormatComponent } from './format/format';
|
||||||
import { CoreCourseModuleComponent } from './module/module';
|
import { CoreCourseModuleComponent } from './module/module';
|
||||||
|
import { CoreCourseModuleCompletionComponent } from './module-completion/module-completion';
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
declarations: [
|
declarations: [
|
||||||
CoreCourseFormatComponent,
|
CoreCourseFormatComponent,
|
||||||
CoreCourseModuleComponent
|
CoreCourseModuleComponent,
|
||||||
|
CoreCourseModuleCompletionComponent
|
||||||
],
|
],
|
||||||
imports: [
|
imports: [
|
||||||
CommonModule,
|
CommonModule,
|
||||||
|
@ -37,7 +39,8 @@ import { CoreCourseModuleComponent } from './module/module';
|
||||||
],
|
],
|
||||||
exports: [
|
exports: [
|
||||||
CoreCourseFormatComponent,
|
CoreCourseFormatComponent,
|
||||||
CoreCourseModuleComponent
|
CoreCourseModuleComponent,
|
||||||
|
CoreCourseModuleCompletionComponent
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
export class CoreCourseComponentsModule {}
|
export class CoreCourseComponentsModule {}
|
||||||
|
|
|
@ -2,9 +2,6 @@
|
||||||
<div *ngIf="!componentInstances.courseFormat">
|
<div *ngIf="!componentInstances.courseFormat">
|
||||||
<!-- Course summary. -->
|
<!-- Course summary. -->
|
||||||
<ion-list no-lines *ngIf="!componentInstances.courseSummary">
|
<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">
|
<ion-item *ngIf="course.progress !== false">
|
||||||
<core-progress-bar [progress]="course.progress"></core-progress-bar>
|
<core-progress-bar [progress]="course.progress"></core-progress-bar>
|
||||||
</ion-item>
|
</ion-item>
|
||||||
|
|
|
@ -92,13 +92,27 @@ export class CoreCourseFormatComponent implements OnInit, OnChanges {
|
||||||
* Detect changes on input properties.
|
* Detect changes on input properties.
|
||||||
*/
|
*/
|
||||||
ngOnChanges(changes: {[name: string]: SimpleChange}) {
|
ngOnChanges(changes: {[name: string]: SimpleChange}) {
|
||||||
if (!this.selectedSection && changes.sections && 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));
|
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) {
|
if (!newSection) {
|
||||||
// We haven't created any component dynamically, stop.
|
// Section not found, calculate which one to use.
|
||||||
return;
|
newSection = this.cfDelegate.getCurrentSection(this.course, this.sections);
|
||||||
|
}
|
||||||
|
this.sectionChanged(newSection);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Apply the changes to the components and call ngOnChanges if it exists.
|
// 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>
|
<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}">
|
<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">
|
<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>
|
<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 { CoreCourseHelperProvider } from '../../providers/helper';
|
||||||
import { CoreCourseFormatDelegate } from '../../providers/format-delegate';
|
import { CoreCourseFormatDelegate } from '../../providers/format-delegate';
|
||||||
import { CoreCoursesDelegate } from '../../../courses/providers/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.
|
* 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,
|
constructor(navParams: NavParams, private courseProvider: CoreCourseProvider, private domUtils: CoreDomUtilsProvider,
|
||||||
private courseFormatDelegate: CoreCourseFormatDelegate, private coursesDelegate: CoreCoursesDelegate,
|
private courseFormatDelegate: CoreCourseFormatDelegate, private coursesDelegate: CoreCoursesDelegate,
|
||||||
private translate: TranslateService, private courseHelper: CoreCourseHelperProvider,
|
private translate: TranslateService, private courseHelper: CoreCourseHelperProvider, eventsProvider: CoreEventsProvider,
|
||||||
private textUtils: CoreTextUtilsProvider, eventsProvider: CoreEventsProvider) {
|
private textUtils: CoreTextUtilsProvider, private coursesProvider: CoreCoursesProvider) {
|
||||||
this.course = navParams.get('course');
|
this.course = navParams.get('course');
|
||||||
this.title = courseFormatDelegate.getCourseTitle(this.course);
|
this.title = courseFormatDelegate.getCourseTitle(this.course);
|
||||||
this.moduleId = navParams.get('moduleId');
|
this.moduleId = navParams.get('moduleId');
|
||||||
|
@ -72,9 +73,13 @@ export class CoreCourseSectionPage implements OnDestroy {
|
||||||
* Fetch and load all the data required for the view.
|
* Fetch and load all the data required for the view.
|
||||||
*/
|
*/
|
||||||
protected loadData(refresh?: boolean) {
|
protected loadData(refresh?: boolean) {
|
||||||
|
// First of all, get the course because the data might have changed.
|
||||||
|
return this.coursesProvider.getUserCourse(this.course.id).then((course) => {
|
||||||
let promises = [],
|
let promises = [],
|
||||||
promise;
|
promise;
|
||||||
|
|
||||||
|
this.course = course;
|
||||||
|
|
||||||
// Get the completion status.
|
// Get the completion status.
|
||||||
if (this.course.enablecompletion === false) {
|
if (this.course.enablecompletion === false) {
|
||||||
// Completion not enabled.
|
// Completion not enabled.
|
||||||
|
@ -117,7 +122,8 @@ export class CoreCourseSectionPage implements OnDestroy {
|
||||||
}));
|
}));
|
||||||
|
|
||||||
return Promise.all(promises).catch((error) => {
|
return Promise.all(promises).catch((error) => {
|
||||||
this.domUtils.showErrorModalDefault(error, 'mm.course.couldnotloadsectioncontent', true);
|
this.domUtils.showErrorModalDefault(error, 'core.course.couldnotloadsectioncontent', true);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -127,15 +133,7 @@ export class CoreCourseSectionPage implements OnDestroy {
|
||||||
* @param {any} refresher Refresher.
|
* @param {any} refresher Refresher.
|
||||||
*/
|
*/
|
||||||
doRefresh(refresher: any) {
|
doRefresh(refresher: any) {
|
||||||
let promises = [];
|
this.invalidateData().finally(() => {
|
||||||
|
|
||||||
promises.push(this.courseProvider.invalidateSections(this.course.id));
|
|
||||||
|
|
||||||
// if ($scope.sections) {
|
|
||||||
// promises.push($mmCoursePrefetchDelegate.invalidateCourseUpdates(courseId));
|
|
||||||
// }
|
|
||||||
|
|
||||||
Promise.all(promises).finally(() => {
|
|
||||||
this.loadData(true).finally(() => {
|
this.loadData(true).finally(() => {
|
||||||
refresher.complete();
|
refresher.complete();
|
||||||
});
|
});
|
||||||
|
@ -146,11 +144,27 @@ export class CoreCourseSectionPage implements OnDestroy {
|
||||||
* The completion of any of the modules have changed.
|
* The completion of any of the modules have changed.
|
||||||
*/
|
*/
|
||||||
onCompletionChange() {
|
onCompletionChange() {
|
||||||
this.courseProvider.invalidateSections(this.course.id).finally(() => {
|
this.invalidateData().finally(() => {
|
||||||
this.refreshAfterCompletionChange();
|
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.
|
* Refresh list after a completion change since there could be new activities.
|
||||||
*/
|
*/
|
||||||
|
|