Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions scripts/langindex.json
Original file line number Diff line number Diff line change
Expand Up @@ -659,12 +659,39 @@
"addon.mod_glossary.noentriesfound": "local_moodlemobileapp",
"addon.mod_glossary.searchquery": "local_moodlemobileapp",
"addon.mod_glossary.tagarea_glossary_entries": "glossary",
"addon.mod_h5pactivity.all_attempts": "h5pactivity",
"addon.mod_h5pactivity.answer_checked": "h5pactivity",
"addon.mod_h5pactivity.answer_correct": "h5pactivity",
"addon.mod_h5pactivity.answer_fail": "h5pactivity",
"addon.mod_h5pactivity.answer_incorrect": "h5pactivity",
"addon.mod_h5pactivity.answer_pass": "h5pactivity",
"addon.mod_h5pactivity.attempt": "h5pactivity",
"addon.mod_h5pactivity.attempt_completion_no": "h5pactivity",
"addon.mod_h5pactivity.attempt_completion_yes": "h5pactivity",
"addon.mod_h5pactivity.attempt_success_fail": "h5pactivity",
"addon.mod_h5pactivity.attempt_success_pass": "h5pactivity",
"addon.mod_h5pactivity.attempt_success_unknown": "h5pactivity",
"addon.mod_h5pactivity.attempts_none": "h5pactivity",
"addon.mod_h5pactivity.completion": "h5pactivity",
"addon.mod_h5pactivity.downloadh5pfile": "local_moodlemobileapp",
"addon.mod_h5pactivity.duration": "h5pactivity",
"addon.mod_h5pactivity.errorgetactivity": "local_moodlemobileapp",
"addon.mod_h5pactivity.filestatenotdownloaded": "local_moodlemobileapp",
"addon.mod_h5pactivity.filestateoutdated": "local_moodlemobileapp",
"addon.mod_h5pactivity.maxscore": "h5pactivity",
"addon.mod_h5pactivity.modulenameplural": "h5pactivity",
"addon.mod_h5pactivity.myattempts": "h5pactivity",
"addon.mod_h5pactivity.no_compatible_track": "h5pactivity",
"addon.mod_h5pactivity.offlinedisabledwarning": "local_moodlemobileapp",
"addon.mod_h5pactivity.outcome": "h5pactivity",
"addon.mod_h5pactivity.result_fill-in": "h5pactivity",
"addon.mod_h5pactivity.result_other": "h5pactivity",
"addon.mod_h5pactivity.review_my_attempts": "h5pactivity",
"addon.mod_h5pactivity.score": "h5pactivity",
"addon.mod_h5pactivity.score_out_of": "h5pactivity",
"addon.mod_h5pactivity.startdate": "h5pactivity",
"addon.mod_h5pactivity.totalscore": "h5pactivity",
"addon.mod_h5pactivity.viewattempt": "local_moodlemobileapp",
"addon.mod_imscp.deploymenterror": "imscp",
"addon.mod_imscp.modulenameplural": "imscp",
"addon.mod_imscp.showmoduledescription": "local_moodlemobileapp",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<!-- Buttons to add to the header. -->
<core-navbar-buttons end>
<core-context-menu>
<core-context-menu-item *ngIf="h5pActivity && h5pActivity.enabletracking && accessInfo && !accessInfo.canreviewattempts" [priority]="1000" [content]="'addon.mod_h5pactivity.review_my_attempts' | translate" (action)="viewMyAttempts()" [iconAction]="'stats'"></core-context-menu-item>
<core-context-menu-item *ngIf="externalUrl" [priority]="900" [content]="'core.openinbrowser' | translate" [href]="externalUrl" [iconAction]="'open'"></core-context-menu-item>
<core-context-menu-item *ngIf="description" [priority]="800" [content]="'core.moduleintro' | translate" (action)="expandDescription()" [iconAction]="'arrow-forward'"></core-context-menu-item>
<core-context-menu-item *ngIf="blog" [priority]="750" content="{{'addon.blog.blog' | translate}}" [iconAction]="'fa-newspaper-o'" (action)="gotoBlog($event)"></core-context-menu-item>
Expand Down
7 changes: 7 additions & 0 deletions src/addon/mod/h5pactivity/components/index/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -319,6 +319,13 @@ export class AddonModH5PActivityIndexComponent extends CoreCourseModuleMainActiv
AddonModH5PActivity.instance.logView(this.h5pActivity.id, this.h5pActivity.name, this.siteId);
}

/**
* Go to view user events.
*/
viewMyAttempts(): void {
this.navCtrl.push('AddonModH5PActivityUserAttemptsPage', {courseId: this.courseId, h5pActivityId: this.h5pActivity.id});
}

/**
* Component destroyed.
*/
Expand Down
6 changes: 5 additions & 1 deletion src/addon/mod/h5pactivity/h5pactivity.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import { AddonModH5PActivityModuleHandler } from './providers/module-handler';
import { AddonModH5PActivityProvider } from './providers/h5pactivity';
import { AddonModH5PActivityPrefetchHandler } from './providers/prefetch-handler';
import { AddonModH5PActivityIndexLinkHandler } from './providers/index-link-handler';
import { AddonModH5PActivityReportLinkHandler } from './providers/report-link-handler';

// List of providers (without handlers).
export const ADDON_MOD_H5P_ACTIVITY_PROVIDERS: any[] = [
Expand All @@ -40,6 +41,7 @@ export const ADDON_MOD_H5P_ACTIVITY_PROVIDERS: any[] = [
AddonModH5PActivityModuleHandler,
AddonModH5PActivityPrefetchHandler,
AddonModH5PActivityIndexLinkHandler,
AddonModH5PActivityReportLinkHandler,
]
})
export class AddonModH5PActivityModule {
Expand All @@ -48,10 +50,12 @@ export class AddonModH5PActivityModule {
prefetchDelegate: CoreCourseModulePrefetchDelegate,
prefetchHandler: AddonModH5PActivityPrefetchHandler,
linksDelegate: CoreContentLinksDelegate,
indexHandler: AddonModH5PActivityIndexLinkHandler) {
indexHandler: AddonModH5PActivityIndexLinkHandler,
reportLinkHandler: AddonModH5PActivityReportLinkHandler) {

moduleDelegate.registerHandler(moduleHandler);
prefetchDelegate.registerHandler(prefetchHandler);
linksDelegate.registerHandler(indexHandler);
linksDelegate.registerHandler(reportLinkHandler);
}
}
29 changes: 28 additions & 1 deletion src/addon/mod/h5pactivity/lang/en.json
Original file line number Diff line number Diff line change
@@ -1,8 +1,35 @@
{
"all_attempts": "All user attempts",
"answer_checked": "Answer checked",
"answer_correct": "Your answer is correct",
"answer_fail": "Incorrect answer",
"answer_incorrect": "Your answer is incorrect",
"answer_pass": "Correct answer",
"attempt": "Attempt",
"attempt_completion_no": "This attempt is not marked as completed",
"attempt_completion_yes": "This attempt is completed",
"attempts_none": "This user has no attempts to display.",
"attempt_success_fail": "Fail",
"attempt_success_pass": "Pass",
"attempt_success_unknown": "Not reported",
"completion": "Completion",
"downloadh5pfile": "Download H5P file",
"duration": "Duration",
"errorgetactivity": "Error getting H5P activity data.",
"filestatenotdownloaded": "The H5P package is not downloaded. You need to download it to be able to use it.",
"filestateoutdated": "The H5P package has been modified since the last download. You need to download it again to be able to use it.",
"maxscore": "Max score",
"modulenameplural": "H5P",
"offlinedisabledwarning": "You will need to be online to view the H5P package."
"myattempts": "My attempts",
"no_compatible_track": "This interaction ({{$a}}) does not provide tracking information or the tracking provided is not compatible with the current activity version.",
"offlinedisabledwarning": "You will need to be online to view the H5P package.",
"outcome": "Outcome",
"result_fill-in": "Fill-in text",
"result_other": "Unkown interaction type",
"review_my_attempts": "View my attempts",
"score": "Score",
"score_out_of": "{{$a.rawscore}} out of {{$a.maxscore}}",
"startdate": "Start date",
"totalscore": "Total score",
"viewattempt": "View attempt {{$a}}"
}
140 changes: 140 additions & 0 deletions src/addon/mod/h5pactivity/pages/attempt-results/attempt-results.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
<ion-header>
<ion-navbar core-back-button>
<ion-title><core-format-text *ngIf="h5pActivity" [text]="h5pActivity.name" contextLevel="module" [contextInstanceId]="h5pActivity.coursemodule" [courseId]="courseId"></core-format-text></ion-title>
</ion-navbar>
</ion-header>
<ion-content>
<ion-refresher [enabled]="loaded" (ionRefresh)="doRefresh($event)">
<ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}"></ion-refresher-content>
</ion-refresher>
<core-loading [hideUntil]="loaded">
<ng-container *ngIf="attempt">
<!-- Attempt number and user that did the attempt. -->
<a ion-item text-wrap *ngIf="user" core-user-link [userId]="user.id" [courseId]="courseId" [title]="user.fullname">
<ion-avatar core-user-avatar [user]="user" item-start></ion-avatar>
<h2>{{ 'addon.mod_h5pactivity.attempt' | translate }} #{{attempt.attempt}}: {{user.fullname}}</h2>
</a>
<!-- Attempt number (if user not known). -->
<ion-item text-wrap *ngIf="!user">
<h2>{{ 'addon.mod_h5pactivity.attempt' | translate }} #{{attempt.attempt}}</h2>
</ion-item>

<!-- Attempt summary. -->
<ion-card class="addon-mod_h5pactivity-attempt-result-summary">
<ion-list>
<ion-item text-wrap no-lines>
<h2>{{ 'addon.mod_h5pactivity.startdate' | translate }}</h2>
<p>{{ attempt.timecreated | coreFormatDate:'strftimedatetime' }}</p>
</ion-item>
<ion-item text-wrap no-lines>
<h2>{{ 'addon.mod_h5pactivity.completion' | translate }}</h2>
<p *ngIf="attempt.completion">
<img src="assets/img/completion/completion-auto-y.svg" role="presentation" alt="">
{{ 'addon.mod_h5pactivity.attempt_completion_yes' | translate }}
</p>
<p *ngIf="!attempt.completion">
<img src="assets/img/completion/completion-auto-n.svg" role="presentation" alt="">
{{ 'addon.mod_h5pactivity.attempt_completion_no' | translate }}
</p>
</ion-item>
<ion-item text-wrap no-lines>
<h2>{{ 'addon.mod_h5pactivity.duration' | translate }}</h2>
<p>{{ attempt.durationReadable }}</p>
</ion-item>
<ion-item text-wrap no-lines>
<h2>{{ 'addon.mod_h5pactivity.outcome' | translate }}</h2>
<p *ngIf="attempt.success !== null && attempt.success" >
<core-icon name="fa-check-circle"></core-icon>
{{ 'addon.mod_h5pactivity.attempt_success_pass' | translate }}
</p>
<p *ngIf="attempt.success !== null && !attempt.success" >
<core-icon name="fa-circle-o"></core-icon>
{{ 'addon.mod_h5pactivity.attempt_success_fail' | translate }}
</p>
<p *ngIf="attempt.success === null" >
{{ 'addon.mod_h5pactivity.attempt_success_unknown' | translate }}
</p>
</ion-item>
<ion-item *ngIf="attempt.maxscore" text-wrap no-lines>
<h2>{{ 'addon.mod_h5pactivity.totalscore' | translate }}</h2>
<p>{{ 'addon.mod_h5pactivity.score_out_of' | translate:{$a: attempt} }}</p>
</ion-item>
</ion-list>
</ion-card>

<!-- Results. -->
<ng-container *ngIf="attempt.results">
<ion-card *ngFor="let result of attempt.results">
<ion-card-header text-wrap>
<core-format-text [text]="result.description" [component]="component" [componentId]="h5pActivity.cmid" contextLevel="module" [contextInstanceId]="h5pActivity.cmid" [courseId]="courseId"></core-format-text>
</ion-card-header>
<ion-item *ngIf="result.content" text-wrap>
<core-format-text [text]="result.content" [component]="component" [componentId]="h5pActivity.cmid" contextLevel="module" [contextInstanceId]="h5pActivity.cmid" [courseId]="courseId"></core-format-text>
</ion-item>

<!-- Options. -->
<ng-container *ngIf="result.options && result.options.length">
<ion-item text-wrap class="addon-mod_h5pactivity-result-table-header">
<ion-row align-items-center>
<ion-col text-center>{{ result.optionslabel }}</ion-col>
<ion-col text-center>{{ result.correctlabel }}</ion-col>
<ion-col text-center>{{ result.answerlabel }}</ion-col>
</ion-row>
</ion-item>
<ion-item text-wrap *ngFor="let option of result.options" class="addon-mod_h5pactivity-result-table-row">
<ion-row align-items-center>
<ion-col text-center>
<core-format-text [text]="option.description" [component]="component" [componentId]="h5pActivity.cmid" contextLevel="module" [contextInstanceId]="h5pActivity.cmid" [courseId]="courseId"></core-format-text>
</ion-col>
<ion-col text-center>
<ng-container *ngIf="option.correctanswer">
<ng-container *ngTemplateOutlet="answerTemplate; context: {answer: option.correctanswer}"></ng-container>
</ng-container>
</ion-col>
<ion-col text-center>
<ng-container *ngIf="option.useranswer">
<ng-container *ngTemplateOutlet="answerTemplate; context: {answer: option.useranswer}"></ng-container>
</ng-container>
</ion-col>
</ion-row>
</ion-item>

<!-- Result score. -->
<ion-item *ngIf="result.maxscore" text-wrap text-end class="addon-mod_h5pactivity-result-score">
<p><strong>{{ 'addon.mod_h5pactivity.score' | translate }}: {{ 'addon.mod_h5pactivity.score_out_of' | translate:{$a: result} }}</strong></p>
</ion-item>
</ng-container>

<!-- Result doesn't support tracking. -->
<ion-item text-wrap class="core-warning-item" *ngIf="!result.track">
<ion-icon item-start name="warning" color="warning"></ion-icon> {{ 'addon.mod_h5pactivity.no_compatible_track' | translate:{$a: result.interactiontype} }}
</ion-item>
</ion-card>
</ng-container>
</ng-container>
</core-loading>
</ion-content>

<!-- Template to render an answer. -->
<ng-template #answerTemplate let-answer="answer">
<p *ngIf="answer.correct">
<core-icon name="fa-check" [label]="'addon.mod_h5pactivity.answer_correct' | translate" color="success"></core-icon>
{{ answer.answer }}
</p>
<p *ngIf="answer.incorrect">
<core-icon name="fa-remove" [label]="'addon.mod_h5pactivity.answer_incorrect' | translate" color="danger"></core-icon>
{{ answer.answer }}
</p>
<p *ngIf="answer.text">
{{ answer.answer }}
</p>
<p *ngIf="answer.checked">
<core-icon name="fa-check-circle" [label]="'addon.mod_h5pactivity.answer_checked' | translate"></core-icon>
</p>
<p *ngIf="answer.pass">
<core-icon name="fa-check" [label]="'addon.mod_h5pactivity.answer_pass' | translate" color="success"></core-icon>
</p>
<p *ngIf="answer.fail">
<core-icon name="fa-remove" [label]="'addon.mod_h5pactivity.answer_fail' | translate" color="danger"></core-icon>
</p>
</ng-template>
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// (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 { NgModule } from '@angular/core';
import { IonicPageModule } from 'ionic-angular';
import { TranslateModule } from '@ngx-translate/core';
import { CoreComponentsModule } from '@components/components.module';
import { CoreDirectivesModule } from '@directives/directives.module';
import { CorePipesModule } from '@pipes/pipes.module';
import { AddonModH5PActivityAttemptResultsPage } from './attempt-results';

@NgModule({
declarations: [
AddonModH5PActivityAttemptResultsPage,
],
imports: [
CoreComponentsModule,
CoreDirectivesModule,
CorePipesModule,
IonicPageModule.forChild(AddonModH5PActivityAttemptResultsPage),
TranslateModule.forChild(),
],
})
export class AddonModH5PActivityAttemptResultsPageModule {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
ion-app.app-root page-addon-mod-h5pactivity-attempt-results {

.addon-mod_h5pactivity-attempt-result-summary {
img {
width: 16px;
height: 16px;
display: inline;
@include margin-horizontal(0, 4px);
}

.icon {
font-size: 1.4em;
}
}

.addon-mod_h5pactivity-result-table-header .item-inner {
font-size: 0.9em;
font-weight: bold;

.col[text-center] {
@include padding-horizontal(0);
}
}

.addon-mod_h5pactivity-result-table-header, .addon-mod_h5pactivity-result-table-row {

.item-inner ion-label {
@include margin(null, 0, null, null);
}

.item {
@include padding(null, null, null, 0);
}

.label {
margin-top: 0;
margin-bottom: 0;
}

.icon {
font-size: 1.2em;
}
}

.addon-mod_h5pactivity-result-table-row.item:nth-child(even) {
background-color: $gray-lighter;
@include darkmode() {
background-color: $core-dark-item-divider-bg-color;
}
}

.addon-mod_h5pactivity-result-score {
border-top: 1px solid black;
}
}
Loading