text-range.page.ts 21.2 KB
Newer Older
1
/* tslint:disable:no-string-literal */
2 3 4 5
import {ApplicationState} from 'src/app/models/applicationState';
import {NavController, ToastController} from '@ionic/angular';
import {Citation} from 'src/app/models/citation';
import {HttpErrorResponse} from '@angular/common/http';
6
import {Component, OnInit} from '@angular/core';
7 8 9 10
import {CitationLevel} from 'src/app/models/enum';
import {TranslateService} from '@ngx-translate/core';
import {HelperService} from '../helper.service';
import {CorpusService} from 'src/app/corpus.service';
11 12 13 14
import {CorpusMC} from '../models/corpusMC';
import {BehaviorSubject} from 'rxjs';
import {take} from 'rxjs/operators';
import {TextRange} from '../models/textRange';
15 16 17 18 19 20

@Component({
    selector: 'app-text-range',
    templateUrl: './text-range.page.html',
    styleUrls: ['./text-range.page.scss'],
})
21
export class TextRangePage implements OnInit {
22 23 24 25 26 27 28
    // TODO: rebuild the system so it works for any corpus of arbitrary citation depth
    public CitationLevel = CitationLevel;
    ObjectKeys = Object.keys;
    public currentlyAvailableCitations: string[] = [];
    public currentInputId = 0;
    public citationValuesStart: number[];
    public citationValuesEnd: number[];
29 30 31 32
    public isInputDisabled: { [isStart: number]: BehaviorSubject<boolean> } = {
        0: new BehaviorSubject<boolean>(true),
        1: new BehaviorSubject<boolean>(true)
    };
33 34 35 36 37 38
    public isTextRangeCheckRunning = false;
    HelperService = HelperService;

    constructor(public navCtrl: NavController,
                public corpusService: CorpusService,
                public toastCtrl: ToastController,
39 40
                public translateService: TranslateService,
                public helperService: HelperService) {
41 42
    }

43
    addMissingCitations(citationLabelsStart: string[], citationLabelsEnd: string[]) {
44 45 46 47 48 49 50 51 52 53 54 55
        return new Promise((resolve, reject) => {
            this.mapCitationLabelsToValues(citationLabelsStart[0], 0, citationLabelsStart, this.citationValuesStart).then(() => {
                this.mapCitationLabelsToValues(citationLabelsEnd[0], 0, citationLabelsEnd, this.citationValuesEnd).then(() => {
                    if (citationLabelsStart.length > 1) {
                        const cls1: string = citationLabelsStart[1];
                        this.mapCitationLabelsToValues(cls1, 1, citationLabelsStart, this.citationValuesStart).then(() => {
                            this.mapCitationLabelsToValues(citationLabelsEnd[1], 1, citationLabelsEnd, this.citationValuesEnd).then(() => {
                                if (citationLabelsStart.length > 2) {
                                    const cls2: string = citationLabelsStart[2];
                                    this.mapCitationLabelsToValues(cls2, 2, citationLabelsStart, this.citationValuesStart).then(() => {
                                        const cle2: string = citationLabelsEnd[2];
                                        this.mapCitationLabelsToValues(cle2, 2, citationLabelsEnd, this.citationValuesEnd).then(() => {
56
                                            return resolve();
57 58 59
                                        });
                                    });
                                } else {
60
                                    return resolve();
61 62 63 64
                                }
                            });
                        }, () => reject());
                    } else {
65
                        return resolve();
66 67 68 69 70 71
                    }
                });
            }, () => reject());
        });
    }

72
    addReferences(targetCitationLevel: string, relevantCitations: Citation[] = []): Promise<void> {
73
        return new Promise((resolve, reject) => {
74
            if (relevantCitations.some(x => !x)) {
75
                return resolve();
76
            }
77
            const urnLastPart: string = relevantCitations.map(x => x.isNumeric ? x.value.toString() : x.label).join('.');
78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114
            this.corpusService.currentCorpus.pipe(take(1)).subscribe((cc: CorpusMC) => {
                const fullUrn: string = cc.source_urn + (urnLastPart ? ':' + urnLastPart : '');
                this.corpusService.getCTSvalidReff(fullUrn).then((result: string[]) => {
                    const newCitations: Citation[] = [];
                    const urnList: string[] = result as string[];
                    const replaceString: string = fullUrn + (urnLastPart ? '.' : ':');
                    urnList.forEach((urn) => {
                        const urnModified: string = urn.replace(replaceString, '');
                        const isNumeric: boolean = !isNaN(+urnModified);
                        newCitations.push(new Citation({
                            isNumeric,
                            level: targetCitationLevel,
                            label: urnModified,
                            value: (isNumeric ? +urnModified : newCitations.length + 1)
                        }));
                    });
                    newCitations.forEach((citation) => {
                        citation.subcitations = {};
                        if (relevantCitations.length === 0) {
                            cc.citations[citation.label] = citation;
                            this.currentlyAvailableCitations.push(citation.label);
                        } else if (relevantCitations.length === 1) {
                            cc.citations[relevantCitations[0].label].subcitations[citation.label] = citation;
                            const firstLabel: string = cc.citations[relevantCitations[0].label].label;
                            this.currentlyAvailableCitations.push(firstLabel.concat('.', citation.label));
                        } else if (relevantCitations.length === 2) {
                            const rc0Label: string = relevantCitations[0].label;
                            const rc1Label: string = relevantCitations[1].label;
                            cc.citations[rc0Label].subcitations[rc1Label].subcitations[citation.label] = citation;
                            const firstLabel: string = cc.citations[rc0Label].label;
                            const secondLabel: string = cc.citations[rc0Label].subcitations[rc1Label].label;
                            this.currentlyAvailableCitations.push(firstLabel.concat('.', secondLabel, '.', citation.label));
                        }
                        return resolve();
                    });
                }, async (error: HttpErrorResponse) => {
                    return reject(error);
115 116 117 118 119 120 121
                });
            });
        });
    }

    applyAutoComplete(isStart: boolean) {
        this.showFurtherReferences(isStart).then(() => {
122
            const oldId: number = this.currentInputId;
123
            this.currentInputId = 0;
124 125 126 127 128 129 130
            let nextIdx = oldId;
            let newEl: HTMLInputElement = null;
            while (nextIdx < Math.min(oldId + 4, 6) && !newEl) {
                nextIdx++;
                const newId: string = 'input' + nextIdx.toString();
                newEl = document.getElementById(newId) as HTMLInputElement;
            }
131 132 133 134 135 136 137 138
            if (newEl) {
                // adjust disabled state manually because the focus won't work otherwise and the automatic check comes too late
                newEl.disabled = false;
                newEl.focus();
            }
        });
    }

139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154
    checkInputDisabled(): void {
        Object.keys(this.isInputDisabled).forEach((isStart: string) => {
            this.corpusService.currentCorpus.pipe(take(1)).subscribe((cc: CorpusMC) => {
                this.corpusService.currentTextRange.pipe(take(1)).subscribe((tr: TextRange) => {
                    const baseCits: { [label: string]: Citation } = cc.citations;
                    const ctrPart: string[] = +isStart ? tr.start : tr.end;
                    if (!baseCits.hasOwnProperty(ctrPart[0])) {
                        this.isInputDisabled[+isStart].next(true);
                    } else {
                        this.isInputDisabled[+isStart].next(!baseCits[ctrPart[0]].subcitations.hasOwnProperty(ctrPart[1]));
                    }
                });
            });
        });
    }

155 156
    checkTextRange(citationLabelsStart: string[], citationLabelsEnd: string[]) {
        return new Promise(resolve => {
157 158
            citationLabelsStart = citationLabelsStart.filter(x => x);
            citationLabelsEnd = citationLabelsEnd.filter(x => x);
159 160 161 162 163
            this.corpusService.currentCorpus.pipe(take(1)).subscribe((cc: CorpusMC) => {
                if (cc.citation_level_2 === CitationLevel[CitationLevel.default]) {
                    if (citationLabelsStart.length !== 1 || citationLabelsEnd.length !== 1) {
                        return resolve(false);
                    }
164
                } else {
165 166 167 168 169 170 171 172
                    if (citationLabelsStart.length < 2 || citationLabelsEnd.length < 2) {
                        return resolve(false);
                    } else {
                        if (cc.citation_level_3 === CitationLevel[CitationLevel.default]) {
                            if (citationLabelsStart.length !== 2 || citationLabelsEnd.length !== 2) {
                                return resolve(false);
                            }
                        } else if (citationLabelsStart.length !== 3 || citationLabelsEnd.length !== 3) {
173
                            return resolve(false);
174 175 176
                        }
                    }
                }
177 178 179 180 181 182 183 184
                this.citationValuesEnd = [];
                this.citationValuesStart = [];
                this.addMissingCitations(citationLabelsStart, citationLabelsEnd).then(() => {
                    this.compareCitationValues().then((result: boolean) => resolve(result));
                }, () => {
                    // if the citation system does not work, we allow the user to choose the correct citations on his own
                    return resolve(true);
                });
185 186 187
            });
        });
    }
188

189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205

    compareCitationValues(): Promise<boolean> {
        return new Promise((resolve) => {
            const citationValuesStart: number[] = this.citationValuesStart;
            const citationValuesEnd: number[] = this.citationValuesEnd;
            if (citationValuesStart[0] < citationValuesEnd[0]) {
                resolve(true);
            } else if (citationValuesStart.concat(citationValuesEnd).some(x => isNaN(x))) {
                // there are non-numeric citation values involved, so we cannot easily compare them
                resolve(true);
            } else if (citationValuesStart[0] === citationValuesEnd[0]) {
                if (citationValuesStart.length > 1) {
                    if (citationValuesStart[1] < citationValuesEnd[1]) {
                        resolve(true);
                    } else if (this.citationValuesStart[1] === citationValuesEnd[1]) {
                        if (citationValuesStart.length > 2) {
                            resolve(citationValuesStart[2] <= citationValuesEnd[2]);
206
                        } else {
207
                            resolve(true);
208 209
                        }
                    } else {
210
                        resolve(false);
211 212
                    }
                } else {
213
                    resolve(true);
214
                }
215 216 217
            } else {
                resolve(false);
            }
218 219 220
        });
    }

221 222 223 224 225
    confirmSelection(skipText: boolean = false) {
        if (this.isTextRangeCheckRunning) {
            return;
        }
        this.isTextRangeCheckRunning = true;
226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244
        this.corpusService.currentTextRange.pipe(take(1)).subscribe((tr: TextRange) => {
            const citationLabelsStart: string[] = tr.start;
            const citationLabelsEnd: string[] = tr.end;
            this.checkTextRange(citationLabelsStart, citationLabelsEnd).then(async (isTextRangeCorrect: boolean) => {
                this.isTextRangeCheckRunning = false;
                if (!isTextRangeCorrect) {
                    const toast = await this.toastCtrl.create({
                        message: this.corpusService.invalidTextRangeString,
                        duration: 3000,
                        position: 'top'
                    });
                    toast.present().then();
                    return;
                }
                this.corpusService.currentCorpus.pipe(take(1)).subscribe((cc: CorpusMC) => {
                    const newUrnBase: string = cc.source_urn + ':';
                    if (this.citationValuesStart.concat(this.citationValuesEnd).some(x => isNaN(x))) {
                        this.corpusService.currentUrn = newUrnBase + tr.start.filter(x => x).join('.') + '-' +
                            tr.end.filter(x => x).join('.');
245
                    } else {
246 247
                        this.corpusService.currentUrn = newUrnBase + this.citationValuesStart.join('.') + '-' +
                            this.citationValuesEnd.join('.');
248
                    }
249 250
                    HelperService.applicationState.pipe(take(1)).subscribe((state: ApplicationState) => {
                        state.currentSetup.currentTextRange = tr;
251 252 253 254 255 256 257 258 259 260
                        this.corpusService.isTextRangeCorrect = true;
                        this.corpusService.getText().then(() => {
                            if (skipText) {
                                HelperService.goToExerciseParametersPage(this.navCtrl).then();
                            } else if (HelperService.isVocabularyCheck) {
                                HelperService.goToVocabularyCheckPage(this.navCtrl).then();
                            } else {
                                HelperService.goToShowTextPage(this.navCtrl).then();
                            }
                        }, () => {
261 262
                        });
                    });
263 264 265 266 267
                });
            });
        });
    }

268 269 270 271 272 273 274
    initPage(currentCorpus: CorpusMC) {
        if (currentCorpus.citation_level_2 === CitationLevel[CitationLevel.default]) {
            const firstKey: string = Object.keys(currentCorpus.citations)[0];
            const randomLabel: string = currentCorpus.citations[firstKey].label;
            this.corpusService.currentTextRange.pipe(take(1)).subscribe((tr: TextRange) => {
                tr.start[0] = tr.end[0] = randomLabel;
            });
275 276 277 278 279
        }
    }

    public mapCitationLabelsToValues(label: string, index: number, citationLabels: string[], valueList: number[]) {
        return new Promise((resolve, reject) => {
280 281 282
            this.corpusService.currentCorpus.pipe(take(1)).subscribe((cc: CorpusMC) => {
                if (index === 0 && cc.citations[label]) {
                    valueList.push(cc.citations[label].value);
283
                    return resolve();
284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300
                } else if (index === 1) {
                    if (!cc.citations[citationLabels[index - 1]]) {
                        if (!!+label) {
                            valueList.push(+label);
                            return resolve();
                        } else {
                            return reject();
                        }
                    }
                    if (Object.keys(cc.citations[citationLabels[index - 1]].subcitations).length === 0) {
                        const relevantCitations: Citation[] = [cc.citations[citationLabels[index - 1]]];
                        this.addReferences(cc.citation_level_2, relevantCitations).then(() => {
                            valueList.push(cc.citations[citationLabels[index - 1]].subcitations[label].value);
                            return resolve();
                        }, () => {
                            return reject();
                        });
301
                    } else {
302 303
                        valueList.push(cc.citations[citationLabels[index - 1]].subcitations[label].value);
                        return resolve();
304
                    }
305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325
                } else if (index === 2) {
                    if (!cc.citations[citationLabels[index - 2]] ||
                        !cc.citations[citationLabels[index - 2]].subcitations[citationLabels[index - 1]]) {
                        if (!!+label) {
                            valueList.push(+label);
                            return resolve();
                        } else {
                            return reject();
                        }
                    }
                    const citation: Citation = cc.citations[citationLabels[index - 2]];
                    const subCitation: Citation = citation.subcitations[citationLabels[index - 1]];
                    if (Object.keys(subCitation.subcitations).length === 0) {
                        this.addReferences(cc.citation_level_3, [citation, subCitation]).then(() => {
                            valueList.push(subCitation.subcitations[label].value);
                            return resolve();
                        }, () => reject());
                    } else {
                        if (!subCitation.subcitations[label]) {
                            return reject();
                        }
326
                        valueList.push(subCitation.subcitations[label].value);
327
                        return resolve();
328 329 330
                    }
                } else if (!!+label) {
                    valueList.push(+label);
331
                    return resolve();
332
                }
333
            });
334 335 336
        });
    }

337 338 339 340 341 342 343 344 345 346 347 348 349 350 351
    ngOnInit(): void {
        this.currentlyAvailableCitations = [];
        this.corpusService.isTextRangeCorrect = false;
        this.corpusService.currentCorpus.pipe(take(1)).subscribe((cc: CorpusMC) => {
            if (Object.keys(cc.citations).length === 0) {
                this.addReferences(cc.citation_level_1).then(() => {
                    this.initPage(cc);
                }, () => {
                });
            } else {
                this.initPage(cc);
            }
        });
    }

352
    resetCitations() {
353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379
        this.corpusService.currentCorpus.pipe(take(1)).subscribe((cc: CorpusMC) => {
            this.corpusService.currentTextRange.pipe(take(1)).subscribe((tr: TextRange) => {
                switch (this.currentInputId) {
                    case 1:
                        if (cc.citation_level_2 !== CitationLevel[CitationLevel.default]) {
                            tr.start[1] = '';
                            tr.start[2] = '';
                        }
                        break;
                    case 2:
                        if (cc.citation_level_3 !== CitationLevel[CitationLevel.default]) {
                            tr.start[2] = '';
                        }
                        break;
                    case 4:
                        if (cc.citation_level_2 !== CitationLevel[CitationLevel.default]) {
                            tr.end[1] = '';
                            tr.end[2] = '';
                        }
                        break;
                    case 5:
                        if (cc.citation_level_3 !== CitationLevel[CitationLevel.default]) {
                            tr.end[2] = '';
                        }
                        break;
                    default:
                        break;
380
                }
381 382
            });
        });
383 384 385 386 387 388 389 390 391 392 393 394
    }

    resetCurrentInputId() {
        const oldId: number = this.currentInputId;
        // dirty hack to prevent the blur event from triggering before the click event
        setTimeout(() => {
            if (oldId === this.currentInputId) {
                this.currentInputId = 0;
            }
        }, 50);
    }

395
    async showFurtherReferences(isStart: boolean): Promise<void> {
396 397 398 399 400 401 402
        return new Promise<void>(outerResolve => {
            this.corpusService.currentTextRange.pipe(take(1)).subscribe((tr: TextRange) => {
                const relTextRangePart: string[] = isStart ? tr.start : tr.end;
                this.resetCitations();
                this.checkInputDisabled();
                if (!relTextRangePart[0]) {
                    return outerResolve();
403
                }
404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431
                this.corpusService.currentCorpus.pipe(take(1)).subscribe((cc: CorpusMC) => {
                    new Promise<void>(innerResolve => {
                        const baseCit: Citation = cc.citations[relTextRangePart[0]];
                        if (baseCit && (Object.keys(baseCit.subcitations).length ||
                            cc.citation_level_2 === CitationLevel[CitationLevel.default])) {
                            innerResolve();
                            return outerResolve();
                        } else {
                            this.addReferences(cc.citation_level_2, [baseCit]).then(() => {
                                innerResolve();
                                return outerResolve();
                            }, () => {
                                innerResolve();
                                return outerResolve();
                            });
                        }
                    }).then(() => {
                        if ([2, 3, 5, 6].indexOf(this.currentInputId) > -1) {
                            const baseCit: Citation = cc.citations[relTextRangePart[0]];
                            const relCit: Citation = baseCit.subcitations[relTextRangePart[1]];
                            const hasLvl3: boolean = cc.citation_level_3 !== CitationLevel[CitationLevel.default];
                            if (relTextRangePart[1] && !(relCit && Object.keys(relCit.subcitations).length) && hasLvl3) {
                                this.addReferences(cc.citation_level_3, [baseCit, relCit]).then();
                            }
                        }
                    });
                });
            });
432 433 434
        });
    }
}