Commit f27a514c authored by Konstantin Schulz's avatar Konstantin Schulz
Browse files

fixed timer for exercises in test module

parent db2f906d
import {Component, OnInit} from '@angular/core';
import {TranslateService} from "@ngx-translate/core";
import {TranslateService} from '@ngx-translate/core';
import {HelperService} from 'src/app/helper.service';
@Component({
selector: 'app-change-language',
......@@ -14,6 +15,7 @@ export class ChangeLanguagePage implements OnInit {
changeLanguage(newLanguage: string) {
if (this.translate.currentLang !== newLanguage) {
this.translate.use(newLanguage);
HelperService.loadTranslations(this.translate);
}
}
......
......@@ -24,6 +24,7 @@ export class HelperService {
Loc: CaseValue.locative,
};
public static config: object;
public static corpusUpdateCompletedString: string;
public static currentError: HttpErrorResponse;
public static currentPopover: any;
public static dependencyMap: { [rawValue: string]: DependencyValue } = {
......@@ -151,6 +152,16 @@ export class HelperService {
});
}
static loadTranslations(translate: TranslateService) {
// dirty hack to wait until the translation loader is initialized in IE11
HelperService.delayedTranslation(translate, 'CORPUS_UPDATE_COMPLETED').then((value: string) => {
HelperService.corpusUpdateCompletedString = value;
});
HelperService.delayedTranslation(translate, 'ERROR_GENERAL_ALERT').then((value: string) => {
HelperService.generalErrorAlertMessage = value;
});
}
static saveMostRecentSetup() {
const lskmrs: string = HelperService.config['localStorageKeyMostRecentSetup'];
window.localStorage.setItem(lskmrs, JSON.stringify(HelperService.mostRecentSetup));
......
......@@ -14,7 +14,6 @@ import {ChangeLanguagePage} from 'src/app/change-language/change-language.page';
})
export class HomePage implements OnInit {
HelperService = HelperService;
public corpusUpdateCompletedString: string;
public isCorpusUpdateInProgress = false;
constructor(public navCtrl: NavController,
......@@ -36,13 +35,7 @@ export class HomePage implements OnInit {
}
ionViewDidEnter() {
// dirty hack to wait until the translation loader is initialized in IE11
HelperService.delayedTranslation(this.translate, 'CORPUS_UPDATE_COMPLETED').then((value: string) => {
this.corpusUpdateCompletedString = value;
});
HelperService.delayedTranslation(this.translate, 'ERROR_GENERAL_ALERT').then((value: string) => {
HelperService.generalErrorAlertMessage = value;
});
HelperService.loadTranslations(this.translate);
}
ngOnInit() {
......@@ -66,7 +59,7 @@ export class HomePage implements OnInit {
this.isCorpusUpdateInProgress = false;
if (!error) {
const toast = await this.toastCtrl.create({
message: this.corpusUpdateCompletedString,
message: HelperService.corpusUpdateCompletedString,
duration: 3000,
position: 'top'
});
......
......@@ -60,15 +60,11 @@ export class PreviewPage implements OnDestroy {
window.localStorage.setItem(HelperService.config['localStorageKeyH5P'], url);
// dirty hack to get H5P going without explicit button click on the new page
setTimeout(() => {
($ => {
$(() => {
$('.h5p-container').empty().h5p({
frameJs: 'assets/dist/js/h5p-standalone-frame.min.js',
frameCss: 'assets/dist/styles/h5p.css',
h5pContent: 'assets/h5p/drag_text'
});
});
})(H5P.jQuery);
H5P.jQuery('.h5p-container').empty().h5p({
frameJs: 'assets/dist/js/h5p-standalone-frame.min.js',
frameCss: 'assets/dist/styles/h5p.css',
h5pContent: 'assets/h5p/drag_text'
});
}, 50);
}
this.updateFileUrl();
......
......@@ -15,13 +15,14 @@
<ion-content padding>
<ion-grid>
<!-- <ion-row><ion-col><ion-button (click)="test()">Test</ion-button></ion-col></ion-row>-->
<!-- for easy navigation during development -->
<ion-row *ngIf="HelperService.isDevMode; else production">
<ion-col>
<ion-label>Show exercise:</ion-label>
<ion-select [(ngModel)]="currentExerciseIndex" name="currentExerciseIndex"
(ngModelChange)="showNextExercise(currentExerciseIndex)">
<ion-select-option *ngFor="let number of Array.from(Array(getExerciseCount()).keys())"
<ion-select-option *ngFor="let number of Array.from(Array(exerciseCount).keys())"
[value]="number">{{ number + 1 }}</ion-select-option>
</ion-select>
</ion-col>
......@@ -29,7 +30,7 @@
<ion-label>Show solutions for:</ion-label>
<ion-select [(ngModel)]="currentExerciseIndex" name="currentExerciseIndex"
(ngModelChange)="showNextExercise(currentExerciseIndex, true)">
<ion-select-option *ngFor="let number of Array.from(Array(getExerciseCount()).keys())"
<ion-select-option *ngFor="let number of Array.from(Array(exerciseCount).keys())"
[value]="number">{{ number + 1 }}</ion-select-option>
</ion-select>
</ion-col>
......@@ -40,7 +41,7 @@
<ion-label>{{ 'TEST_MODULE_GO_TO_EXERCISE' | translate}}:</ion-label>
<ion-select [(ngModel)]="currentExerciseIndex" name="currentExerciseIndex"
(ngModelChange)="showNextExercise(currentExerciseIndex, true)">
<ion-select-option *ngFor="let number of Array.from(Array(getExerciseCount()).keys())"
<ion-select-option *ngFor="let number of Array.from(Array(exerciseCount).keys())"
[value]="number">{{ number + 1 }}</ion-select-option>
</ion-select>
</ion-col>
......@@ -52,6 +53,11 @@
<ion-progress-bar value="{{progressBarValue}}"></ion-progress-bar>
</ion-col>
</ion-row>
<ion-row *ngIf="!getCurrentExerciseName().startsWith(nonH5Pstring)">
<ion-col>
{{ 'TEST_MODULE_EXERCISE_ID' | translate }}: #{{ currentExerciseIndex + 1 }}
</ion-col>
</ion-row>
<!-- step 1: intro-->
<div *ngIf="currentExerciseIndex == 0">
<ion-row>
......@@ -138,7 +144,7 @@
<ion-row>
<ion-col>
<h4>{{'UNIT_EVALUATION_HEADER' | translate}}</h4>
</ion-col>
</ion-col>
</ion-row>
<ion-row>
<ion-col>
......
......@@ -11,8 +11,10 @@ import {ExercisePart} from 'src/app/models/exercisePart';
import Activity from 'src/app/models/xAPI/Activity';
import LanguageMap from 'src/app/models/xAPI/LanguageMap';
import {HttpClient, HttpErrorResponse} from '@angular/common/http';
import Context from 'src/app/models/xAPI/Context';
declare var H5P: any;
declare var $: any;
// dirty hack to prevent H5P access errors after resize events
window.onresize = () => {
/* tslint:disable:prefer-const */
......@@ -42,6 +44,8 @@ export class TestPage implements OnDestroy, OnInit {
}), new ExercisePart({
startIndex: 0,
durationSeconds: 300,
// TODO: DELETE DRAG_TEXT_1
// 'drag_text_1',
exercises: ['fill_blanks_1', 'multi_choice_1', 'multi_choice_2',
'multi_choice_3', 'multi_choice_4', 'multi_choice_5', 'multi_choice_6',
'multi_choice_7', 'multi_choice_8', 'fill_blanks_2', 'fill_blanks_3',
......@@ -56,8 +60,7 @@ export class TestPage implements OnDestroy, OnInit {
}), new ExercisePart({
startIndex: 0,
durationSeconds: 750,
exercises: ['drag_text_1', 'drag_text_2', 'drag_text_3',
'drag_text_4', 'drag_text_5']
exercises: ['drag_text_1', 'drag_text_2', 'drag_text_3', 'drag_text_4', 'drag_text_5']
}), new ExercisePart({
startIndex: 0,
durationSeconds: 750,
......@@ -91,9 +94,13 @@ export class TestPage implements OnDestroy, OnInit {
public dataAlreadySentMessage: string;
public dataSentSuccessMessage: string;
public didTimeRunOut = false;
public exerciseCount: number;
public fillBlanksString = 'fill_blanks';
public h5pBlanksString = 'H5P.Blanks';
public h5pCheckButtonClassString = '.h5p-question-check-answer';
public h5pDragTextString = 'H5P.DragText';
public h5pIframeString = '#h5p-iframe-1';
public h5pMultiChoiceString = 'H5P.MultiChoice';
public h5pRowIDstring = '#h5p-row';
public h5pTextInputClassString = '.h5p-text-input';
public hideClassString = 'hide';
......@@ -187,23 +194,16 @@ export class TestPage implements OnDestroy, OnInit {
|| this.currentExerciseParts[i + 1].startIndex > this.currentExerciseIndex));
}
getExerciseCount() {
return this.currentExerciseParts.map(x => x.exercises.length).reduce((x, y) => x + y);
}
public initH5P(exerciseType: string) {
// dirty hack to get H5P going without explicit button click on the new page
setTimeout(() => {
(($) => {
$(() => {
$('.h5p-container').empty().h5p({
frameJs: 'assets/dist/js/h5p-standalone-frame.min.js',
frameCss: 'assets/dist/styles/h5p.css',
h5pContent: 'assets/h5p/' + exerciseType
});
}
);
})(H5P.jQuery);
H5P.jQuery('.h5p-container').empty().h5p({
// TODO: CHANGE TO MINIFIED
// frameJs: 'assets/dist/js/h5p-standalone-frame.js',
frameJs: 'assets/dist/js/h5p-standalone-frame.min.js',
frameCss: 'assets/dist/styles/h5p.css',
h5pContent: 'assets/h5p/' + exerciseType
});
}, 50);
}
......@@ -237,7 +237,9 @@ export class TestPage implements OnDestroy, OnInit {
this.didTimeRunOut = false;
}
}
this.showNextExercise(this.currentExerciseParts[this.getCurrentExercisePartIndex() + 1].startIndex);
const newIndex: number = this.currentExerciseParts[this.getCurrentExercisePartIndex() + 1].startIndex;
this.currentExerciseIndex = newIndex;
this.showNextExercise(newIndex);
}
}, 1000);
}
......@@ -270,6 +272,7 @@ export class TestPage implements OnDestroy, OnInit {
const index: number = Math.random() < 0.5 ? 3 : 4;
this.testType = index === 3 ? TestType.cloze : TestType.list;
this.currentExerciseParts.splice(this.currentExerciseParts.length - index, 1);
this.exerciseCount = this.currentExerciseParts.map(x => x.exercises.length).reduce((x, y) => x + y);
}
removeTimer(freeze: boolean) {
......@@ -344,7 +347,7 @@ export class TestPage implements OnDestroy, OnInit {
H5P.externalDispatcher.on('domChanged', (event: any) => {
// dirty hack because domChanged events are triggered twice for every new H5P exercise
if (!this.areEventHandlersSet) {
if (this.currentState === TestModuleState.inProgress && event.data.library === 'H5P.Blanks') {
if (this.currentState === TestModuleState.inProgress && event.data.library === this.h5pBlanksString) {
this.triggerInputEventHandler();
} else if (this.currentState === TestModuleState.showSolutions) {
this.triggerSolutionsEventHandler();
......@@ -417,9 +420,10 @@ export class TestPage implements OnDestroy, OnInit {
if (iframe) {
if (this.vocService.currentTestResults[this.currentExerciseIndex]) {
const oldActivity: Activity = this.vocService.currentTestResults[this.currentExerciseIndex].object as Activity;
const oldContext: Context = this.vocService.currentTestResults[this.currentExerciseIndex].context;
const oldResponse: string = this.vocService.currentTestResults[this.currentExerciseIndex].result.response;
const singleResponses: string[] = oldResponse.split('[,]');
if (oldActivity.definition.interactionType === 'choice') {
if (oldContext.contextActivities.category[0].id.indexOf(this.h5pMultiChoiceString) > -1) {
const oldChosen: { description: LanguageMap, id: string }[] = oldActivity.definition.choices.filter(
x => singleResponses.indexOf(x.id) > -1);
const oldCheckedStrings: string[] = oldChosen.map(x => x.description[Object.keys(x.description)[0]]);
......@@ -429,11 +433,46 @@ export class TestPage implements OnDestroy, OnInit {
newOption.click();
}
});
} else if (oldActivity.definition.interactionType === 'fill-in') {
} else if (oldContext.contextActivities.category[0].id.indexOf(this.h5pBlanksString) > -1) {
const inputs: NodeList = iframe.contentWindow.document.querySelectorAll(this.h5pTextInputClassString);
inputs.forEach((input: HTMLInputElement, index: number) => {
input.value = singleResponses[index];
});
} else if (oldContext.contextActivities.category[0].id.indexOf(this.h5pDragTextString) > -1) {
if (false) {
const dragClass = '.ui-draggable';
const dropClass = '.ui-droppable';
const solutionContainer = '<div class="h5p-drag-show-solution-container" style="display: none;"></div>';
// const startDragElement = element.all(by.css(dragClass));
// const endDragElement = element.all(by.css(dropClass));
// browser.actions().dragAndDrop(startDragElement, endDragElement).perform().then(); // .perform();
// setTimeout(() => {
// }, 250);
const draggables: HTMLCollection = $(dragClass, iframe.contentWindow.document);
const dropZones: HTMLCollection = $(dropClass, iframe.contentWindow.document);
$(dropZones).each((index: number, dropZone: HTMLDivElement) => {
if (singleResponses[index]) {
// H5P.DragText.drop($(draggables[index]), dropZone);
// $(draggables[index]).appendTo(dropZone);
}
// $(dropZone).append(solutionContainer);
// ('<div></div>').addClass('h5p-drag-show-solution-container');
});
// tslint:disable-next-line:prefer-for-of
// for (let i = 0; i < dropZones.length; i++) {
// console.log(dropZones[i]);
// }
const b = 0;
// EMPTY ZONE
// <div aria-dropeffect="none" aria-label="Drop Zone 2. Drop Zone 2 is empty." tabindex="-1" class="ui-droppable" style="width: 69px;"></div>
// FILLED ZONE >> first element in empty drop zone
// <div aria-dropeffect="none" aria-label="Drop Zone 3. Drop Zone 3 contains draggable scribo." tabindex="0" class="ui-droppable" style="width: 69px;"><div role="button" aria-grabbed="false" tabindex="-1" class="ui-draggable h5p-drag-dropped" aria-label="Draggable scribo. 1 of 3 draggables. Draggable is grabbed." style="position: relative; touch-action: none; left: 0px; top: 0px;">scribo</div></div>
// SOLUTION CONTAINER >> second element in empty drop zone
// <div class="h5p-drag-show-solution-container" style="display: none;"></div>
// UNTOUCHED DRAGGABLE
// <div role="button" aria-grabbed="false" tabindex="0" class="ui-draggable" aria-label="Draggable facere. 2 of 3 draggables. " style="position: relative; touch-action: none; left: 0px; top: 0px;">facere</div>
}
}
}
const checkButton: HTMLButtonElement = iframe.contentWindow.document.body.querySelector(this.h5pCheckButtonClassString);
......@@ -448,4 +487,27 @@ export class TestPage implements OnDestroy, OnInit {
// dirty hack to trigger ngIf evaluation & data bindings
(document.querySelector('#refreshUI') as HTMLLinkElement).click();
}
test() {
const iframe: HTMLIFrameElement = document.querySelector(this.h5pIframeString);
// H5P.jQuery.fn.on('select', (event: any) => {
// console.log(event);
// });
H5P.externalDispatcher.on('*', (event: any) => {
console.log(event);
});
if (iframe) {
const dragClass = '.ui-draggable';
const dropClass = '.ui-droppable';
// const draggables: HTMLCollection = $(dragClass, iframe.contentWindow.document);
// const dropZones: HTMLCollection = $(dropClass, iframe.contentWindow.document);
const draggables: NodeList = iframe.contentWindow.document.querySelectorAll(dragClass);
const dropZones: NodeList = iframe.contentWindow.document.querySelectorAll(dropClass);
// H5P.externalDispatcher.trigger('before-select', draggables[0]);
H5P.externalDispatcher.trigger('start');
H5P.externalDispatcher.trigger('select', {target: dropZones[0], element: dragClass[0]});
// H5P.externalDispatcher.trigger('select', {target: dropZones[0], element: draggables[0]});
// H5P.externalDispatcher.trigger('drop', {target: dropZones[0], element: draggables[0]});
}
}
}
......@@ -10637,7 +10637,8 @@ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Cons
case 2:
this.h5p = _context.sent;
_context.next = 5;
return regeneratorRuntime.awrap(getJSONPromise(this.path + "/content/content.json"));
return regeneratorRuntime.awrap(getJSONPromise(window.localStorage.getItem("mc/h5p")));
// this.path + "/content/content.json"
case 5:
this.content = _context.sent;
......
......@@ -131,7 +131,7 @@
"START": "Anfang",
"START_TEST": "Start der Lerneinheit",
"TEST": "Lerneinheit",
"TEST_MODULE_EXERCISE_NUMBER": "Übungsnummer",
"TEST_MODULE_EXERCISE_ID": "Übungs-ID",
"TEST_MODULE_GO_TO_EXERCISE": "Gehe zu Übung",
"TEST_MODULE_PROGRESS_PART": "Fortschritt: Teil",
"TEST_MODULE_SEND_DATA": "Daten senden",
......
......@@ -131,7 +131,7 @@
"START": "Start",
"START_TEST": "Start the learning unit",
"TEST": "Learning unit",
"TEST_MODULE_EXERCISE_NUMBER": "Exercise number",
"TEST_MODULE_EXERCISE_ID": "Exercise ID",
"TEST_MODULE_GO_TO_EXERCISE": "Go to exercise",
"TEST_MODULE_PROGRESS_PART": "Progress: Part",
"TEST_MODULE_SEND_DATA": "Send data",
......
......@@ -35,6 +35,9 @@
<!-- H5P integration, can be called using the global H5P variable -->
<script type="text/javascript" src="assets/dist/js/h5p-standalone-main.min.js"></script>
<!-- <script type="text/javascript" src="assets/dist/js/h5p-standalone-main.js"></script>-->
<!-- <script type="text/javascript" src="https://code.jquery.com/jquery-3.4.1.slim.min.js"></script>-->
</head>
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment