Commit 3f9b31bb authored by Konstantin Schulz's avatar Konstantin Schulz
Browse files

added frequency analysis data to improve the handling of matching exercises

parent 5abb07b5
{
"name": "mc_frontend",
"version": "1.1.1",
"version": "1.1.3",
"author": "Ionic Framework",
"homepage": "https://ionicframework.com/",
"scripts": {
......
......@@ -12,7 +12,10 @@ import {
CaseTranslations,
CaseValue,
DependencyTranslation,
DependencyValue, ExerciseType, ExerciseTypeTranslation, InstructionsTranslation,
DependencyValue,
ExerciseType,
ExerciseTypeTranslation,
InstructionsTranslation,
PartOfSpeechTranslation,
PartOfSpeechValue,
Phenomenon
......@@ -22,9 +25,8 @@ import {LinkMC} from 'src/app/models/linkMC';
import {QueryMC} from 'src/app/models/queryMC';
import {Exercise} from 'src/app/models/exercise';
import {Feedback} from 'src/app/models/feedback';
import {PhenomenonMap} from 'src/app/models/phenomenonMap';
import {error} from 'selenium-webdriver';
import {reject} from 'q';
import {PhenomenonMap, PhenomenonMapContent} from 'src/app/models/phenomenonMap';
import {FrequencyItem} from 'src/app/models/frequencyItem';
@Injectable({
providedIn: 'root'
......@@ -51,7 +53,12 @@ export class CorpusService {
instructionsTranslation: ''
});
public isTextRangeCorrect = false;
public phenomenonMap: PhenomenonMap = {};
public phenomenonMap: PhenomenonMap = new PhenomenonMap({
case: new PhenomenonMapContent({translationObject: CaseTranslations}),
dependency: new PhenomenonMapContent({translationObject: DependencyTranslation}),
lemma: new PhenomenonMapContent({translationObject: null}),
partOfSpeech: new PhenomenonMapContent({translationObject: PartOfSpeechTranslation})
});
constructor(public translate: TranslateService,
public http: HttpClient,
......@@ -72,10 +79,10 @@ export class CorpusService {
});
}
adjustQueryValue(query: QueryMC) {
const availableValues = Object.keys(this.phenomenonMap[query.phenomenon][2]);
// when the phenomenon changes, choose a (almost) random value as the default
query.values = [availableValues[Object.keys(availableValues)[0]]];
adjustQueryValue(query: QueryMC, queryIndex: number) {
// when the phenomenon changes, choose the first value from the translated list as the default
query.values = [this.getSortedQueryValues(query, queryIndex)[0]];
this.updateBaseWord(query, queryIndex);
}
adjustTranslations() {
......@@ -86,16 +93,17 @@ export class CorpusService {
value => this.exercise.instructionsTranslation = value);
}
if (this.exercise.type === ExerciseType.matching) {
this.exercise.queryItems = [new QueryMC({
phenomenon: Phenomenon.partOfSpeech,
values: [Object.keys(this.phenomenonMap[Phenomenon.partOfSpeech][2])[0]],
}), new QueryMC({
phenomenon: Phenomenon.partOfSpeech,
values: [Object.keys(this.phenomenonMap[Phenomenon.partOfSpeech][2])[0]],
})];
this.exercise.queryItems = [new QueryMC({phenomenon: Phenomenon.partOfSpeech, values: []}),
new QueryMC({phenomenon: Phenomenon.partOfSpeech, values: []})];
this.getFrequencyAnalysis().then(() => {
this.adjustQueryValue(this.exercise.queryItems[0], 0);
this.adjustQueryValue(this.exercise.queryItems[1], 1);
return;
});
} else if (this.exercise.queryItems.length > 1) {
this.exercise.queryItems.splice(1, 1);
}
this.adjustQueryValue(this.exercise.queryItems[0], 0);
}
checkAnnisResponse() {
......@@ -106,6 +114,7 @@ export class CorpusService {
this.helperService.loadMostRecentSetup().then(() => {
this.annisResponse = HelperService.mostRecentSetup.annisResponse;
this.currentUrn = HelperService.mostRecentSetup.currentUrn;
this.currentCorpus = HelperService.mostRecentSetup.currentCorpus;
return outerResolve();
}, () => {
return outerReject();
......@@ -161,10 +170,58 @@ export class CorpusService {
return this.http.get(fullUrl, {params: {urn: urn}});
}
getSortedQueryValues(query: QueryMC) {
const targetObject: object = this.phenomenonMap[query.phenomenon][0];
return Object.keys(this.phenomenonMap[query.phenomenon][2]).sort((a, b) => {
return a === b ? 0 : (targetObject[a] < targetObject[b] ? -1 : 1);
getFrequencyAnalysis() {
return new Promise((resolve, reject) => {
if (this.annisResponse.frequency_analysis.length) {
return resolve();
} else {
HelperService.currentError = null;
HelperService.isLoading = true;
const url = HelperService.config['backendBaseUrl'] + HelperService.config['backendApiFrequencyPath'];
this.http.get(url, {params: {urn: this.currentUrn}}).subscribe((fis: FrequencyItem[]) => {
HelperService.isLoading = false;
this.annisResponse.frequency_analysis = fis;
HelperService.mostRecentSetup.annisResponse = this.annisResponse;
this.helperService.saveMostRecentSetup().then();
return resolve();
}, async (error: HttpErrorResponse) => {
HelperService.isLoading = false;
HelperService.currentError = error;
const toast = await this.toastCtrl.create({
message: HelperService.generalErrorAlertMessage,
duration: 3000,
position: 'top'
});
toast.present().then();
return reject();
});
}
});
}
getSortedQueryValues(query: QueryMC, queryIndex: number): string[] {
const pmc: PhenomenonMapContent = this.phenomenonMap[query.phenomenon];
if (this.exercise.type === ExerciseType.matching) {
if (queryIndex) {
const relevantFIs: FrequencyItem[] = this.annisResponse.frequency_analysis.filter(
x => x.values[0] === this.exercise.queryItems[0].values[0] &&
x.phenomena[1] === query.phenomenon.toString());
return Array.from(new Set<string>(relevantFIs.map(x => x.values[1]))).sort((a, b) => {
return a === b ? 0 : (pmc.translationValues[a] < pmc.translationValues[b] ? -1 : 1);
});
} else {
const relevantFIs: FrequencyItem[] = this.annisResponse.frequency_analysis.filter(
x => x.phenomena[0] === query.phenomenon.toString());
return Array.from(new Set<string>(relevantFIs.map(x => x.values[0]))).sort((a, b) => {
return a === b ? 0 : (pmc.translationValues[a] < pmc.translationValues[b] ? -1 : 1);
});
}
}
if (!pmc.specificValues) {
return [];
}
return Object.keys(pmc.specificValues).sort((a, b) => {
return a === b ? 0 : (pmc.translationValues[a] < pmc.translationValues[b] ? -1 : 1);
});
}
......@@ -211,16 +268,14 @@ export class CorpusService {
initPhenomenonMap() {
// map the different phenomena to their respective Enum for processing and display/translation
this.phenomenonMap[Phenomenon.partOfSpeech] = [{}, PartOfSpeechTranslation, {}];
this.phenomenonMap[Phenomenon.dependency] = [{}, DependencyTranslation, {}];
this.phenomenonMap[Phenomenon.case] = [{}, CaseTranslations, {}];
this.phenomenonMap[Phenomenon.lemma] = [{}, null, {}];
Object.keys(Phenomenon).forEach((key) => {
if (key !== Phenomenon[Phenomenon.lemma]) {
const translationObject: object = this.phenomenonMap[key][1];
const pmc: PhenomenonMapContent = this.phenomenonMap[key];
pmc.translationValues = {};
const translationObject: object = pmc.translationObject;
Object.keys(translationObject).forEach((k: string) => {
if (k !== k.toUpperCase()) {
this.translate.get(translationObject[k]).subscribe(v => this.phenomenonMap[key][0][k] = v);
this.translate.get(translationObject[k]).subscribe(v => pmc.translationValues[k] = v);
}
});
}
......@@ -240,44 +295,26 @@ export class CorpusService {
}
processAnnisResponse(ar: AnnisResponse, saveToCache: boolean = true) {
Object.keys(this.phenomenonMap).forEach(key => this.phenomenonMap[key][2] = {});
this.phenomenonMap[Phenomenon.lemma][0] = {};
ar.nodes.forEach((node: NodeMC) => {
let existingValue = this.phenomenonMap[Phenomenon.lemma][2][node.udep_lemma];
this.phenomenonMap[Phenomenon.lemma][2][node.udep_lemma] = (existingValue ? existingValue : 0) + 1;
this.phenomenonMap[Phenomenon.lemma][0][node.udep_lemma] = node.udep_lemma;
if (node.udep_feats) {
const featsParts: string[] = node.udep_feats.split('|');
const casePart: string = featsParts.find(x => x.toLowerCase().includes(Phenomenon[Phenomenon.case]));
if (casePart) {
const caseAbbreviation: string = casePart.split('=')[1];
const caseValue: CaseValue = HelperService.caseMap[caseAbbreviation];
existingValue = this.phenomenonMap[Phenomenon.case][2][caseValue];
this.phenomenonMap[Phenomenon.case][2][caseValue] = (existingValue ? existingValue : 0) + 1;
}
}
const pos: PartOfSpeechValue = HelperService.partOfSpeechMap[node.udep_upostag];
existingValue = this.phenomenonMap[Phenomenon.partOfSpeech][2][pos];
this.phenomenonMap[Phenomenon.partOfSpeech][2][pos] = (existingValue ? existingValue : 0) + 1;
Object.keys(this.phenomenonMap).forEach((key: string) => {
const pmc: PhenomenonMapContent = this.phenomenonMap[key];
pmc.specificValues = {};
});
// init the display with a (almost) random value
this.exercise.queryItems[0].values = [Object.keys(this.phenomenonMap[Phenomenon.partOfSpeech][2])[0]];
this.phenomenonMap.lemma.translationValues = {};
this.processNodes(ar);
const pointingLinks: LinkMC[] = ar.links.filter(x => x.annis_component_type === 'Pointing');
pointingLinks.forEach((link: LinkMC) => {
const dep: DependencyValue = HelperService.dependencyMap[link.udep_deprel];
if (dep) {
const existingValue = this.phenomenonMap[Phenomenon.dependency][2][dep];
this.phenomenonMap[Phenomenon.dependency][2][dep] = (existingValue ? existingValue : 0) + 1;
const existingValue = this.phenomenonMap.dependency.specificValues[dep];
this.phenomenonMap.dependency.specificValues[dep] = (existingValue ? existingValue : 0) + 1;
}
});
// need to add root dependencies manually because they are tricky to handle
const nodeIds: string[] = ar.nodes.map(x => x.id);
const nodesWithDependencySet: Set<string> = new Set<string>(pointingLinks.map(x => x.target));
const rootNodeIds: string[] = nodeIds.filter(x => !nodesWithDependencySet.has(x));
this.phenomenonMap[Phenomenon.dependency][2][DependencyValue.root] = rootNodeIds.length;
this.adjustQueryValue(this.exercise.queryItems[0]);
this.phenomenonMap.dependency.specificValues[DependencyValue.root] = rootNodeIds.length;
this.adjustQueryValue(this.exercise.queryItems[0], 0);
// remove whitespace before punctuation
this.currentText = ar.nodes.map(x => x.annis_tok).join(' ').replace(/[ ]([.,\/#!$%\^&\*;:{}=\-_`~()])/g, (x: string) => {
return x.trim();
......@@ -329,6 +366,27 @@ export class CorpusService {
});
}
processNodes(ar: AnnisResponse) {
ar.nodes.forEach((node: NodeMC) => {
let existingValue = this.phenomenonMap.lemma.specificValues[node.udep_lemma];
this.phenomenonMap.lemma.specificValues[node.udep_lemma] = (existingValue ? existingValue : 0) + 1;
this.phenomenonMap.lemma.translationValues[node.udep_lemma] = node.udep_lemma;
if (node.udep_feats) {
const featsParts: string[] = node.udep_feats.split('|');
const casePart: string = featsParts.find(x => x.toLowerCase().includes(Phenomenon[Phenomenon.case]));
if (casePart) {
const caseAbbreviation: string = casePart.split('=')[1];
const caseValue: CaseValue = HelperService.caseMap[caseAbbreviation];
existingValue = this.phenomenonMap.case.specificValues[caseValue];
this.phenomenonMap.case.specificValues[caseValue] = (existingValue ? existingValue : 0) + 1;
}
}
const pos: PartOfSpeechValue = HelperService.partOfSpeechMap[node.udep_upostag];
existingValue = this.phenomenonMap.partOfSpeech.specificValues[pos];
this.phenomenonMap.partOfSpeech.specificValues[pos] = (existingValue ? existingValue : 0) + 1;
});
}
restoreLastCorpus() {
return new Promise((resolve, reject) => {
this.annisResponse = HelperService.mostRecentSetup.annisResponse;
......@@ -350,4 +408,19 @@ export class CorpusService {
});
});
}
updateBaseWord(query: QueryMC, queryIndex: number) {
if (!this.annisResponse || !this.annisResponse.frequency_analysis.length) {
return;
}
if (!queryIndex && this.exercise.type === ExerciseType.matching) {
if (!this.getSortedQueryValues(this.exercise.queryItems[1], 1).length) {
const fi: FrequencyItem = this.annisResponse.frequency_analysis.find(
x => x.values[0] === this.exercise.queryItems[0].values[0]);
this.exercise.queryItems[1].phenomenon = Phenomenon[fi.phenomena[1]];
}
this.adjustQueryValue(this.exercise.queryItems[1], 1);
}
}
}
......@@ -48,7 +48,7 @@
<label>
<span class="label">{{ 'QUERY_PHENOMENON' | translate }}</span>
<select [(ngModel)]="query.phenomenon" name="queryPhenomenon"
(change)="corpusService.adjustQueryValue(query)">
(change)="corpusService.adjustQueryValue(query, i)">
<option *ngFor="let phenomenon of ObjectKeys(Phenomenon)" [value]=phenomenon>
{{ PhenomenonTranslation[phenomenon] | translate }}
</option>
......@@ -63,9 +63,8 @@
<label>
<span class="label">{{ 'QUERY_VALUE' | translate }}</span>
<select [(ngModel)]="query.values" name="queryValue" multiple>
<option *ngFor="let key of corpusService.getSortedQueryValues(query)" [value]=key>
{{ corpusService.phenomenonMap[query.phenomenon][0][key] + " (" +
corpusService.phenomenonMap[query.phenomenon][2][key] + ")" }}
<option *ngFor="let key of corpusService.getSortedQueryValues(query, i)"
[value]=key>{{ getDisplayValue(query, key, i) }}
</option>
</select>
</label>
......@@ -75,10 +74,10 @@
<span class="label">
{{ 'QUERY_VALUE' | translate }}
</span>
<select [(ngModel)]="query.values[0]" name="queryValue">
<option *ngFor="let key of corpusService.getSortedQueryValues(query)" [value]=key>
{{ corpusService.phenomenonMap[query.phenomenon][0][key] + " (" +
corpusService.phenomenonMap[query.phenomenon][2][key] + ")" }}
<select [(ngModel)]="query.values[0]" name="queryValue"
(change)="corpusService.updateBaseWord(query, i)">
<option *ngFor="let key of corpusService.getSortedQueryValues(query, i)"
[value]=key>{{ getDisplayValue(query, key, i) }}
</option>
</select>
</label>
......
......@@ -8,13 +8,15 @@ import {
} from '../models/enum';
import {AnnisResponse} from 'src/app/models/annisResponse';
import {NavController, ToastController} from '@ionic/angular';
import {QueryMC} from 'src/app/models/queryMC';
import {HttpClient, HttpErrorResponse} from '@angular/common/http';
import {Component} from '@angular/core';
import {TranslateService} from '@ngx-translate/core';
import {ExerciseService} from 'src/app/exercise.service';
import {HelperService} from 'src/app/helper.service';
import {CorpusService} from 'src/app/corpus.service';
import {QueryMC} from 'src/app/models/queryMC';
import {PhenomenonMapContent} from 'src/app/models/phenomenonMap';
import {FrequencyItem} from 'src/app/models/frequencyItem';
@Component({
selector: 'app-exercise-parameters',
......@@ -54,7 +56,8 @@ export class ExerciseParametersPage {
position: 'top'
});
toast.present().then();
} else if (phenomenon === Phenomenon.lemma && !this.corpusService.exercise.queryItems[0].values) {
} else if ((phenomenon === Phenomenon.lemma && !this.corpusService.exercise.queryItems[0].values) ||
this.corpusService.exercise.type === ExerciseType.matching && !this.corpusService.exercise.queryItems[1].values[0]) {
const toast = await this.toastCtrl.create({
message: this.emptyQueryValueString,
duration: 3000,
......@@ -67,23 +70,41 @@ export class ExerciseParametersPage {
}
}
public getDisplayValue(query: QueryMC, key: string, queryIndex: number = 0): string {
const pmc: PhenomenonMapContent = this.corpusService.phenomenonMap[query.phenomenon];
const translatedKey: string = pmc.translationValues[key];
let count: number;
if (this.corpusService.exercise.type === ExerciseType.matching) {
if (queryIndex) {
const relevantFI: FrequencyItem = this.corpusService.annisResponse.frequency_analysis.find(
x => x.values[0] === this.corpusService.exercise.queryItems[0].values[0] && x.values[1] === key);
count = relevantFI.count;
} else {
const relevantFIs: FrequencyItem[] = this.corpusService.annisResponse.frequency_analysis.filter(
x => x.phenomena[0] === query.phenomenon.toString() && x.values[0] === key);
count = relevantFIs.map(x => x.count).reduce((a, b) => a + b);
}
} else {
count = pmc.specificValues[key];
}
return translatedKey + ' (' + count + ')';
}
private getExerciseData() {
const searchValues: string[] = this.corpusService.exercise.queryItems.map(
query => query.phenomenon + '=' + query.values.join('|'));
const formData = new FormData();
formData.append('urn', this.corpusService.currentUrn);
formData.append('search_values', JSON.stringify(searchValues));
HelperService.currentError = null;
HelperService.isLoading = true;
let instructions: string = this.corpusService.exercise.instructionsTranslation;
if (this.corpusService.exercise.type === ExerciseType.kwic) {
this.getKwicExercise(formData);
return;
} else if (this.corpusService.exercise.type === ExerciseType.markWords) {
const phenomenon: Phenomenon = this.corpusService.exercise.queryItems[0].phenomenon;
const map: object[] = this.corpusService.phenomenonMap[phenomenon];
const pmc: PhenomenonMapContent = this.corpusService.phenomenonMap[phenomenon];
const values: string[] = this.corpusService.exercise.queryItems[0].values as string[];
instructions += ` [${values.map(x => map[0][x]).join(', ')}]`;
instructions += ` [${values.map(x => pmc.translationValues[x]).join(', ')}]`;
}
// TODO: change the corpus title to something meaningful, e.g. concatenate user ID and wanted exercise title
const workTitle: string = this.corpusService.currentCorpus.title + ', ' +
......@@ -103,8 +124,12 @@ export class ExerciseParametersPage {
getH5Pexercise(formData: FormData) {
const url = HelperService.config['backendBaseUrl'] + HelperService.config['backendApiExercisePath'];
HelperService.currentError = null;
HelperService.isLoading = true;
this.http.post(url, formData).subscribe((ar: AnnisResponse) => {
HelperService.isLoading = false;
// save the old frequency analysis in case we want to change the exercise parameters at a later time
ar.frequency_analysis = this.corpusService.annisResponse.frequency_analysis;
HelperService.mostRecentSetup.annisResponse = ar;
this.helperService.saveMostRecentSetup().then();
this.corpusService.annisResponse.exercise_id = ar.exercise_id;
......@@ -125,6 +150,8 @@ export class ExerciseParametersPage {
getKwicExercise(formData: FormData) {
const kwicUrl: string = HelperService.config['backendBaseUrl'] + HelperService.config['backendApiKwicPath'];
HelperService.currentError = null;
HelperService.isLoading = true;
this.http.post(kwicUrl, formData).subscribe((svgString: string) => {
HelperService.isLoading = false;
this.exerciseService.kwicGraphs = svgString;
......
......@@ -2,10 +2,12 @@
import {Solution} from 'src/app/models/solution';
import {LinkMC} from 'src/app/models/linkMC';
import {NodeMC} from 'src/app/models/nodeMC';
import {FrequencyItem} from 'src/app/models/frequencyItem';
export class AnnisResponse {
public directed: boolean;
public exercise_id: string;
public frequency_analysis: FrequencyItem[];
public links: LinkMC[];
public multigraph: boolean;
public nodes: NodeMC[];
......
export class FrequencyItem {
public values: string[];
public phenomena: string[];
public count: number;
constructor(init?: Partial<FrequencyItem>) {
Object.assign(this, init);
}
}
/* tslint:disable:variable-name */
export class NodeMC {
public annis_node_name: string;
public annis_node_type: string;
......
export interface PhenomenonMap {
[phenomenonName: string]: [
{ [translationsKey: string]: string },
object,
{ [specificValue: string]: number }
];
export class PhenomenonMapContent {
translationValues: { [translationsKey: string]: string };
translationObject: object;
specificValues: { [specificValue: string]: number };
constructor(init?: Partial<PhenomenonMapContent>) {
Object.assign(this, init);
}
}
export class PhenomenonMap {
public case: PhenomenonMapContent;
public dependency: PhenomenonMapContent;
public lemma: PhenomenonMapContent;
public partOfSpeech: PhenomenonMapContent;
constructor(init?: Partial<PhenomenonMap>) {
Object.assign(this, init);
}
}
......@@ -2,7 +2,7 @@
<ion-toolbar>
<div class="toolbar-left">
<ion-back-button icon="arrow-round-back" defaultHref="home"></ion-back-button>
<ion-title>{{corpusService.currentCorpus.title}}</ion-title>
<ion-title>{{corpusService.currentCorpus?.title}}</ion-title>
</div>
<div class="toolbar-right">
<ion-spinner *ngIf="HelperService.isLoading"></ion-spinner>
......@@ -28,22 +28,22 @@
<ion-col>
<input [(ngModel)]="corpusService.currentTextRange.start[0]" id="input1"
(ngModelChange)="showFurtherReferences(true).then()"
placeholder="{{ corpusService.currentCorpus.citation_level_1 }}"
placeholder="{{ corpusService.currentCorpus?.citation_level_1 }}"
(focus)="currentInputId = 1" (blur)="resetCurrentInputId()"/>
</ion-col>
<ion-col>
<input *ngIf="corpusService.currentCorpus.citation_level_2 !== CitationLevel[CitationLevel.default]"
<input *ngIf="corpusService.currentCorpus?.citation_level_2 !== CitationLevel[CitationLevel.default]"
[(ngModel)]="corpusService.currentTextRange.start[1]" id="input2"
(ngModelChange)="showFurtherReferences(true).then()"
placeholder="{{ corpusService.currentCorpus.citation_level_2 }}"
placeholder="{{ corpusService.currentCorpus?.citation_level_2 }}"
(focus)="currentInputId = 2" (blur)="resetCurrentInputId()"
disabled="{{!corpusService.currentCorpus.citations.hasOwnProperty(corpusService.currentTextRange.start[0])}}"/>
disabled="{{!corpusService.currentCorpus?.citations.hasOwnProperty(corpusService.currentTextRange.start[0])}}"/>
</ion-col>
<ion-col>
<input *ngIf="corpusService.currentCorpus.citation_level_3 !== CitationLevel[CitationLevel.default]"
<input *ngIf="corpusService.currentCorpus?.citation_level_3 !== CitationLevel[CitationLevel.default]"
[(ngModel)]="corpusService.currentTextRange.start[2]" id="input3"
(ngModelChange)="showFurtherReferences(true).then()"
placeholder="{{ corpusService.currentCorpus.citation_level_3 }}"
placeholder="{{ corpusService.currentCorpus?.citation_level_3 }}"
(focus)="currentInputId = 3" (blur)="resetCurrentInputId()"
disabled="{{isInputDisabled(true)}}"/>
</ion-col>
......@@ -89,22 +89,22 @@
<ion-col>
<input [(ngModel)]="corpusService.currentTextRange.end[0]" id="input4"
(ngModelChange)="showFurtherReferences(false).then()"
placeholder="{{ corpusService.currentCorpus.citation_level_1 }}"
placeholder="{{ corpusService.currentCorpus?.citation_level_1 }}"
(focus)="currentInputId = 4" (blur)="resetCurrentInputId()"/>
</ion-col>
<ion-col>
<input *ngIf="corpusService.currentCorpus.citation_level_2 !== CitationLevel[CitationLevel.default]"
<input *ngIf="corpusService.currentCorpus?.citation_level_2 !== CitationLevel[CitationLevel.default]"
[(ngModel)]="corpusService.currentTextRange.end[1]" id="input5"
(ngModelChange)="showFurtherReferences(false).then()"
placeholder="{{ corpusService.currentCorpus.citation_level_2 }}"
placeholder="{{ corpusService.currentCorpus?.citation_level_2 }}"
(focus)="currentInputId = 5" (blur)="resetCurrentInputId()"
disabled="{{!corpusService.currentCorpus.citations.hasOwnProperty(corpusService.currentTextRange.start[0])}}"/>
disabled="{{!corpusService.currentCorpus?.citations.hasOwnProperty(corpusService.currentTextRange.start[0])}}"/>
</ion-col>
<ion-col>
<input *ngIf="corpusService.currentCorpus.citation_level_3 !== CitationLevel[CitationLevel.default]"
<input *ngIf="corpusService.currentCorpus?.citation_level_3 !== CitationLevel[CitationLevel.default]"
[(ngModel)]="corpusService.currentTextRange.end[2]" id="input6"
(ngModelChange)="showFurtherReferences(false).then()"
placeholder="{{ corpusService.currentCorpus.citation_level_3 }}"
placeholder="{{ corpusService.currentCorpus?.citation_level_3 }}"
(focus)="currentInputId = 6" (blur)="resetCurrentInputId()"
disabled="{{isInputDisabled(false)}}"/>
</ion-col>
......
......@@ -36,7 +36,16 @@ export class TextRangePage {
this.currentlyAvailableCitations = [];
this.corpusService.isTextRangeCorrect = false;
this.corpusService.currentTextRange = new TextRange({start: ['', '', ''], end: ['', '', '']});
if (Object.keys(this.corpusService.currentCorpus.citations).length === 0) {
if (!this.corpusService.currentCorpus) {
this.corpusService.checkAnnisResponse().then(() => {
this.corpusService.restoreLastCorpus().then(() => {
this.addReferences(this.corpusService.currentCorpus.citation_level_1).then(() => {
this.initPage();
}, () => {
});
});
});
} else if (Object.keys(this.corpusService.currentCorpus.citations).length === 0) {
this.addReferences(this.corpusService.currentCorpus.citation_level_1).then(() => {
this.initPage();
}, () => {
......@@ -224,6 +233,9 @@ export class TextRangePage {
}
isInputDisabled(isStart: boolean) {
if (!this.corpusService.currentCorpus) {
return true;
}
const baseCits: { [label: string]: Citation } = this.corpusService.currentCorpus.citations;
const ctrPart: string[] = isStart ? this.corpusService.currentTextRange.start : this.corpusService.currentTextRange.end;
if (!baseCits.hasOwnProperty(ctrPart[0])) {
......
......@@ -4,6 +4,7 @@
"backendApiExerciseListPath": "exerciseList",
"backendApiExercisePath": "exercise",
"backendApiFilePath": "file",
"backendApiFrequencyPath": "frequency",
"backendApiH5pPath": "h5p",
"backendApiKwicPath": "kwic",
"backendApiRawtextPath": "rawtext",
......