preview.page.ts 7.56 KB
Newer Older
1
/* tslint:disable:no-string-literal */
2 3 4
import {AnnisResponse} from 'src/app/models/annisResponse';
import {ExerciseType, FileType} from 'src/app/models/enum';
import {HelperService} from 'src/app/helper.service';
5
import {NavController, ToastController} from '@ionic/angular';
6 7
import {ExerciseService} from 'src/app/exercise.service';
import {CorpusService} from 'src/app/corpus.service';
8
import {Component, OnDestroy, OnInit} from '@angular/core';
9 10
import {TranslateService} from '@ngx-translate/core';
import {Solution} from 'src/app/models/solution';
11 12 13
import {HttpClient, HttpErrorResponse} from '@angular/common/http';
import {XAPIevent} from 'src/app/models/xAPIevent';
import {TestResultMC} from 'src/app/models/testResultMC';
14
import configMC from '../../configMC';
15
import {Storage} from '@ionic/storage';
16 17 18 19 20 21 22 23

declare var H5P: any;

@Component({
    selector: 'app-preview',
    templateUrl: './preview.page.html',
    styleUrls: ['./preview.page.scss'],
})
24
export class PreviewPage implements OnDestroy, OnInit {
25
    public configMC = configMC;
26 27 28
    public ExerciseType = ExerciseType;
    public FileType = FileType;
    public currentSolutions: Solution[];
29
    public HelperService = HelperService;
30
    public inputSelector = 'input[type="text"]';
31
    public maxGapLength = 0;
32
    public showShareLink = false;
33 34
    public showInstructions = false;
    public solutionIndicesString: string;
35 36
    public solutionNodeIdSet: Set<string> = new Set<string>();
    public urlBase: string;
37 38 39 40 41

    constructor(public navCtrl: NavController,
                public http: HttpClient,
                public exerciseService: ExerciseService,
                public translateService: TranslateService,
42
                public corpusService: CorpusService,
43
                public helperService: HelperService,
44 45
                public toastCtrl: ToastController,
                public storage: Storage) {
46 47 48 49
        this.currentSolutions = [];
        if (!HelperService.isVocabularyCheck) {
            this.exerciseService.excludeOOV = false;
        }
50 51 52 53
        this.corpusService.checkAnnisResponse().then(() => {
            this.processAnnisResponse(this.corpusService.annisResponse);
            this.initH5P();
        }, () => {
54
        });
55 56
    }

57
    async copyLink(): Promise<void> {
58 59
        const input: HTMLInputElement = document.querySelector(this.inputSelector);
        input.select();
60
        document.execCommand('copy');
61
        input.setSelectionRange(0, 0);
62 63 64 65 66 67 68 69 70 71 72
        const toast = await this.toastCtrl.create({
            message: this.corpusService.shareLinkCopiedString,
            duration: 3000,
            position: 'middle'
        });
        toast.present().then();
    }

    initH5P(): void {
        const solutionIndicesString: string = this.exerciseService.excludeOOV ? '&solution_indices=' +
            JSON.stringify(this.currentSolutions.map(x => this.corpusService.annisResponse.solutions.indexOf(x))) : '';
73 74 75
        // this will be called via GET request from the h5p standalone javascript library
        const url: string = `${configMC.backendBaseUrl + configMC.backendApiH5pPath}` +
            `?eid=${this.corpusService.annisResponse.exercise_id}&lang=${this.translateService.currentLang + solutionIndicesString}`;
76 77
        // this has to be LocalStorage because the H5P javascript cannot easily access the Ionic Storage
        window.localStorage.setItem(configMC.localStorageKeyH5P, url);
78 79 80
        const exerciseTypePath: string = this.corpusService.exercise.type === ExerciseType.markWords ? 'mark_words' : 'drag_text';
        this.exerciseService.initH5P(exerciseTypePath);
        this.updateFileUrl();
81 82
    }

83 84 85 86
    ngOnDestroy(): void {
        H5P.externalDispatcher.off('xAPI');
    }

87 88
    ngOnInit(): void {
        H5P.externalDispatcher.on('xAPI', (event: XAPIevent) => {
89 90 91 92 93 94 95 96 97 98 99
            // results are only available when a task has been completed/answered, not in the "attempted" or "interacted" stages
            if (event.data.statement.verb.id === configMC.xAPIverbIDanswered && event.data.statement.result) {
                const iframe: HTMLIFrameElement = document.querySelector(this.exerciseService.h5pIframeString);
                if (iframe) {
                    const iframeDoc: Document = iframe.contentWindow.document;
                    const inner: string = iframeDoc.documentElement.innerHTML;
                    const result: TestResultMC = new TestResultMC({
                        statement: event.data.statement,
                        innerHTML: inner
                    });
                    this.sendData(result);
100
                }
101
            }
102 103 104
        });
    }

105
    processAnnisResponse(ar: AnnisResponse): void {
106
        this.corpusService.annisResponse.solutions = ar.solutions;
107
        this.processSolutions(ar.solutions);
108
        this.corpusService.annisResponse.uri = ar.uri;
109
        const isUrn: boolean = this.corpusService.currentUrn && this.corpusService.currentUrn.startsWith('urn:');
110 111
        this.corpusService.annisResponse.nodes = isUrn ? this.corpusService.annisResponse.nodes : ar.nodes;
        this.corpusService.annisResponse.links = isUrn ? this.corpusService.annisResponse.links : ar.links;
112 113
    }

114
    processSolutions(solutions: Solution[]): void {
115
        const isCloze: boolean = this.corpusService.exercise.type === ExerciseType.cloze;
116
        if (this.exerciseService.excludeOOV) {
117
            const nodeIdSet: Set<string> = new Set(this.corpusService.annisResponse.nodes.filter(
118
                x => !x.is_oov).map(x => x.id));
119
            solutions = this.corpusService.annisResponse.solutions.filter(
120 121 122 123 124 125 126 127 128 129 130 131 132 133 134
                x => nodeIdSet.has(x.target.salt_id) && (isCloze || nodeIdSet.has(x.value.salt_id)));
        }
        let newSolutions: Solution[] = [];
        if (isCloze) {
            this.maxGapLength = Math.max.apply(Math, solutions.map(x => x.target.content.length));
            this.solutionNodeIdSet = new Set(solutions.map(x => x.target.salt_id));
            newSolutions = solutions.concat();
        } else {
            newSolutions = solutions.concat().sort((s1, s2) => {
                return s1.target.content < s2.target.content ? -1 : (s1.target.content > s2.target.content ? 1 : 0);
            });
        }
        this.currentSolutions = newSolutions;
    }

135
    selectLink(): void {
136
        const ta: HTMLTextAreaElement = document.querySelector(this.inputSelector);
137 138 139 140
        ta.select();
    }

    sendData(result: TestResultMC): void {
141 142 143 144 145 146 147 148 149 150 151
        const fileUrl: string = configMC.backendBaseUrl + configMC.backendApiFilePath;
        HelperService.currentError = null;
        HelperService.isLoading = true;
        const formData = new FormData();
        formData.append('learning_result', JSON.stringify(result.statement));
        this.http.post(fileUrl, formData).subscribe(async () => {
            HelperService.isLoading = false;
        }, async (error: HttpErrorResponse) => {
            HelperService.isLoading = false;
            HelperService.currentError = error;
            console.log('ERROR: COULD NOT SEND EXERCISE RESULTS TO SERVER.');
152 153 154
        });
    }

155
    switchOOV(): void {
156
        this.currentSolutions = [];
157
        this.processSolutions(this.corpusService.annisResponse.solutions);
158 159 160
        this.initH5P();
    }

161
    updateFileUrl(): void {
162 163
        const fileId: string = this.corpusService.annisResponse.exercise_id;
        const fileTypeBase = '&type=';
164
        this.urlBase = configMC.backendBaseUrl + configMC.backendApiFilePath + '?id=' + fileId + fileTypeBase;
165
        this.solutionIndicesString = this.exerciseService.excludeOOV ? '&solution_indices=' +
166
            JSON.stringify(this.currentSolutions.map(x => this.corpusService.annisResponse.solutions.indexOf(x))) : '';
167 168
    }
}