Commit 069db711 authored by Konstantin Schulz's avatar Konstantin Schulz
Browse files

texts in the vocabulary check are now precisely identifiable and will be...

texts in the vocabulary check are now precisely identifiable and will be cached, replacing the major base text
parent 088f6475
{
"name": "mc_frontend",
"version": "0.8.1",
"version": "0.8.7",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
......@@ -743,6 +743,16 @@
"ionicons": "4.5.6"
}
},
"@ionic/storage": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/@ionic/storage/-/storage-2.2.0.tgz",
"integrity": "sha512-2pszrzmI+fAar2Rx0WmJDVpc15D1k5tvLkB49NLYWJ2pOMaO/3/vp7mg/mEbg3rdsPE9FRbYI6vdKjQ2pP1EWA==",
"requires": {
"localforage": "1.7.1",
"localforage-cordovasqlitedriver": "1.7.0",
"tslib": "^1.7.1"
}
},
"@ngtools/webpack": {
"version": "7.3.9",
"resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-7.3.9.tgz",
......@@ -5549,8 +5559,7 @@
"immediate": {
"version": "3.0.6",
"resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz",
"integrity": "sha1-nbHb0Pr43m++D13V5Wu2BigN5ps=",
"dev": true
"integrity": "sha1-nbHb0Pr43m++D13V5Wu2BigN5ps="
},
"import-cwd": {
"version": "2.1.0",
......@@ -6676,6 +6685,32 @@
"json5": "^1.0.1"
}
},
"localforage": {
"version": "1.7.1",
"resolved": "https://registry.npmjs.org/localforage/-/localforage-1.7.1.tgz",
"integrity": "sha1-5JJ+BCMCuGTbMPMhHxO1xvDell0=",
"requires": {
"lie": "3.1.1"
},
"dependencies": {
"lie": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/lie/-/lie-3.1.1.tgz",
"integrity": "sha1-mkNrLMd0bKWd56QfpGmz77dr2H4=",
"requires": {
"immediate": "~3.0.5"
}
}
}
},
"localforage-cordovasqlitedriver": {
"version": "1.7.0",
"resolved": "https://registry.npmjs.org/localforage-cordovasqlitedriver/-/localforage-cordovasqlitedriver-1.7.0.tgz",
"integrity": "sha1-i5OVd1nuaI06WNW6fAR39sy1ODg=",
"requires": {
"localforage": ">=1.5.0"
}
},
"locate-path": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz",
......
{
"name": "mc_frontend",
"version": "0.8.5",
"version": "0.8.7",
"author": "Ionic Framework",
"homepage": "https://ionicframework.com/",
"scripts": {
......@@ -25,6 +25,7 @@
"@ionic-native/status-bar": "^5.6.0",
"@ionic/angular": "^4.3.1",
"@ionic/core": "^4.4.0",
"@ionic/storage": "^2.2.0",
"@ngx-translate/core": "^11.0.1",
"@ngx-translate/http-loader": "^4.0.0",
"cordova-browser": "5.0.4",
......
import {IonicStorageModule} from '@ionic/storage';
import {NgModule} from '@angular/core';
import {BrowserModule} from '@angular/platform-browser';
import {RouteReuseStrategy} from '@angular/router';
......@@ -23,6 +24,7 @@ import {APP_BASE_HREF} from '@angular/common';
BrowserModule,
IonicModule.forRoot(),
AppRoutingModule,
IonicStorageModule.forRoot({name: 'mc_db', driverOrder: ['indexeddb', 'websql', 'localstorage']}),
HttpClientModule,
TranslateModule.forRoot({
loader: {
......@@ -31,8 +33,8 @@ import {APP_BASE_HREF} from '@angular/common';
deps: [HttpClient]
}
}),
ConfirmCancelPageModule,
ChangeLanguagePageModule
ChangeLanguagePageModule,
ConfirmCancelPageModule
],
providers: [
{
......@@ -41,7 +43,7 @@ import {APP_BASE_HREF} from '@angular/common';
},
StatusBar,
SplashScreen,
{provide: RouteReuseStrategy, useClass: IonicRouteStrategy}
{provide: RouteReuseStrategy, useClass: IonicRouteStrategy},
],
bootstrap: [AppComponent]
})
......
......@@ -5,6 +5,7 @@
<ion-title>{{ 'AUTHOR_SELECT' | translate }}</ion-title>
</div>
<div class="toolbar-right">
<ion-spinner *ngIf="HelperService.isLoading"></ion-spinner>
<button (click)="HelperService.goToHomePage(navCtrl)">
<ion-icon name="home"></ion-icon>
</button>
......@@ -24,21 +25,24 @@
<ion-col>
<a (click)="restoreLastSetup()">{{ [HelperService.mostRecentSetup.currentCorpus.author,
HelperService.mostRecentSetup.currentCorpus.title,
HelperService.mostRecentSetup.workReference].join(", ") }}</a>
HelperService.mostRecentSetup.currentUrn?.split(":").slice(-1)[0]].join(", ") }}</a>
</ion-col>
</ion-row>
<ion-row>
<ion-col>
<label>{{ "AUTHOR_SHOW_ONLY_TREEBANKS" | translate}}
<label>
<input type="checkbox" [(ngModel)]="showOnlyTreebanks" (change)="toggleTreebankAuthors()"/>
<span class="checkbox">{{ "AUTHOR_SHOW_ONLY_TREEBANKS" | translate}}</span>
</label>
</ion-col>
</ion-row>
<ion-row>
<ion-col size="12">
<ion-icon name="search" class="search"></ion-icon>
<input type="search" (ngModelChange)="getAuthors($event.toString())" style=""
placeholder="{{ 'AUTHOR_SEARCH' | translate }}" [(ngModel)]="currentSearchValue"/>
<label>
<ion-icon name="search" class="search"></ion-icon>
<input type="search" (ngModelChange)="getAuthors($event.toString())" style=""
placeholder="{{ 'AUTHOR_SEARCH' | translate }}" [(ngModel)]="currentSearchValue"/>
</label>
</ion-col>
</ion-row>
<ion-row>
......
......@@ -26,8 +26,10 @@ export class AuthorPage {
public corpusService: CorpusService,
public http: HttpClient,
public exerciseService: ExerciseService) {
if (!this.corpusService.availableAuthors) {
this.corpusService.loadCorporaFromLocalStorage();
}
this.toggleTreebankAuthors();
this.corpusService.isTextRangeCorrect = false;
}
public authorsDisplayed: Author[];
......
......@@ -31,6 +31,7 @@ export class CorpusService {
public annisResponse: AnnisResponse;
public availableCorpora: CorpusMC[];
public availableAuthors: Author[];
public baseUrn: string;
public corporaUnavailableString: string;
public currentAuthor: Author;
public currentCorpus: CorpusMC;
......@@ -52,14 +53,18 @@ export class CorpusService {
constructor(public translate: TranslateService,
public http: HttpClient,
public toastCtrl: ToastController) {
public toastCtrl: ToastController,
public helperService: HelperService,
) {
this.translate.get('ERROR_CORPORA_UNAVAILABLE').subscribe(value => this.corporaUnavailableString = value);
this.checkForUpdates().then();
this.helperService.initConfig().then(() => {
this.checkForUpdates();
});
this.initPhenomenonMap();
this.getTranslations();
if (HelperService.mostRecentSetup) {
this.restoreLastCorpus().then();
}
this.initPhenomenonMap();
this.getTranslations();
}
adjustQueryValue(query: QueryMC) {
......@@ -88,10 +93,7 @@ export class CorpusService {
}
}
async checkForUpdates() {
while (!HelperService.config) {
await new Promise(resolve => setTimeout(resolve, 50));
}
checkForUpdates() {
// check local storage for necessary updates
const updateInfoJSON: object = JSON.parse(window.localStorage.getItem(HelperService.config['localStorageKeyUpdateInfo']));
this.getCorpora(updateInfoJSON ? new Date(updateInfoJSON['corpora'].lastAccessTime).getTime() : 0).then();
......@@ -216,7 +218,7 @@ export class CorpusService {
}
}
processAnnisResponse(ar: AnnisResponse) {
processAnnisResponse(ar: AnnisResponse, saveToCache: boolean = true) {
Object.keys(this.phenomenonMap).forEach(key => this.phenomenonMap[key][2] = {});
this.phenomenonMap[Phenomenon.lemma][0] = {};
ar.graph.nodes.forEach((node: NodeMC) => {
......@@ -255,16 +257,21 @@ export class CorpusService {
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.annisResponse = ar;
HelperService.mostRecentSetup.annisResponse = ar;
HelperService.saveMostRecentSetup();
// remove whitespace before punctuation
this.currentText = ar.graph.nodes.map(x => x.annis_tok).join(' ').replace(/[ ]([.,\/#!$%\^&\*;:{}=\-_`~()])/g, (x: string) => {
return x.trim();
});
this.annisResponse = ar;
if (saveToCache) {
HelperService.mostRecentSetup.currentUrn = this.currentUrn;
HelperService.mostRecentSetup.annisResponse = ar;
this.helperService.saveMostRecentSetup().then();
}
}
private processCorpora(corpusList: CorpusMC[]) {
this.availableCorpora = [];
this.availableAuthors = [];
corpusList.forEach((corpus: CorpusMC) => {
corpus.citations = {};
this.availableCorpora.push(corpus);
......@@ -304,15 +311,17 @@ export class CorpusService {
restoreLastCorpus() {
return new Promise((resolve, reject) => {
this.annisResponse = HelperService.mostRecentSetup.annisResponse;
// check if the data is already present
if (this.currentUrn === HelperService.mostRecentSetup.currentUrn &&
this.currentCorpus === HelperService.mostRecentSetup.currentCorpus && this.currentText) {
return resolve();
}
this.currentUrn = HelperService.mostRecentSetup.currentUrn;
this.currentCorpus = HelperService.mostRecentSetup.currentCorpus;
this.currentTextRange = HelperService.mostRecentSetup.currentTextRange;
this.currentUrn = HelperService.mostRecentSetup.currentUrn;
this.isTextRangeCorrect = true;
if (Object.keys(this.annisResponse.graph).length) {
this.processAnnisResponse(this.annisResponse);
}
// check if the data is already present
if (this.currentText) {
return resolve();
}
this.getText().then(() => {
return resolve();
}, () => {
......
......@@ -37,7 +37,8 @@ export class ExerciseParametersPage {
public translateService: TranslateService,
public corpusService: CorpusService,
public exerciseService: ExerciseService,
public http: HttpClient) {
public http: HttpClient,
public helperService: HelperService) {
this.translateService.get('TEXT_TOO_LONG').subscribe(
value => this.textTooLongString = value + HelperService.config['maxTextLength']);
this.translateService.get('QUERY_VALUE_EMPTY').subscribe(value => this.emptyQueryValueString = value);
......@@ -103,7 +104,7 @@ export class ExerciseParametersPage {
this.http.post(url, formData).subscribe((ar: AnnisResponse) => {
HelperService.isLoading = false;
HelperService.mostRecentSetup.annisResponse = ar;
HelperService.saveMostRecentSetup();
this.helperService.saveMostRecentSetup();
this.corpusService.annisResponse.exercise_id = ar.exercise_id;
this.corpusService.annisResponse.uri = ar.uri;
this.corpusService.annisResponse.solutions = ar.solutions;
......
......@@ -6,6 +6,7 @@ import {ApplicationState} from 'src/app/models/applicationState';
import {TranslateHttpLoader} from '@ngx-translate/http-loader';
import {CaseValue, DependencyValue, PartOfSpeechValue} from 'src/app/models/enum';
import {TranslateService} from '@ngx-translate/core';
import {Storage} from '@ionic/storage';
@Injectable({
providedIn: 'root'
......@@ -94,7 +95,9 @@ export class HelperService {
X: PartOfSpeechValue.other
};
constructor(public http: HttpClient) {
constructor(public http: HttpClient,
private storage: Storage,
) {
}
// The translate loader needs to know where to load i18n files in Ionic's static asset pipeline.
......@@ -161,20 +164,29 @@ export class HelperService {
});
}
static saveMostRecentSetup() {
const lskmrs: string = HelperService.config['localStorageKeyMostRecentSetup'];
window.localStorage.setItem(lskmrs, JSON.stringify(HelperService.mostRecentSetup));
initConfig() {
return new Promise((resolve) => {
this.http.get('assets/config.json').subscribe((config: object) => {
HelperService.config = config;
if (!HelperService.config['backendBaseUrl']) {
const part1: string = location.protocol.concat('//').concat(window.location.host);
HelperService.config['backendBaseUrl'] = part1.concat(HelperService.config['backendBaseApiPath']).concat('/');
}
this.storage.get(HelperService.config['localStorageKeyMostRecentSetup']).then((mrs: string) => {
HelperService.mostRecentSetup = JSON.parse(mrs);
});
resolve();
});
});
}
initConfig() {
this.http.get('assets/config.json').subscribe((config: object) => {
HelperService.config = config;
if (!HelperService.config['backendBaseUrl']) {
const part1: string = location.protocol.concat('//').concat(window.location.host);
HelperService.config['backendBaseUrl'] = part1.concat(HelperService.config['backendBaseApiPath']).concat('/');
}
const mrs: string = window.localStorage.getItem(HelperService.config['localStorageKeyMostRecentSetup']);
HelperService.mostRecentSetup = JSON.parse(mrs);
saveMostRecentSetup() {
return new Promise((resolve) => {
const lskmrs: string = HelperService.config['localStorageKeyMostRecentSetup'];
this.storage.set(lskmrs, JSON.stringify(HelperService.mostRecentSetup)).then(() => {
resolve();
});
});
}
}
......@@ -22,7 +22,8 @@ export class HomePage implements OnInit {
public translate: TranslateService,
public corpusService: CorpusService,
public toastCtrl: ToastController,
public popoverController: PopoverController) {
public popoverController: PopoverController,
) {
}
async changeLanguage(ev: any = null) {
......
......@@ -7,7 +7,6 @@ export class ApplicationState {
public currentCorpus: CorpusMC;
public currentTextRange: TextRange;
public currentUrn: string;
public workReference: string;
constructor(init?: Partial<ApplicationState>) {
Object.assign(this, init);
......
......@@ -19,8 +19,9 @@
<ion-grid>
<ion-row *ngIf="HelperService.isVocabularyCheck">
<ion-col>
<label>{{ "EXERCISE_NO_OOV" | translate}}
<label>
<input type="checkbox" [(ngModel)]="exerciseService.excludeOOV" (ngModelChange)="switchOOV()"/>
<span class="checkbox">{{ "EXERCISE_NO_OOV" | translate}}</span>
</label>
<br>
</ion-col>
......
......@@ -15,10 +15,6 @@ div {
max-width: 250px;
}
input {
float: left;
}
ol {
text-align: left;
}
......@@ -22,16 +22,19 @@ export class RankingPage {
public vocService: VocabularyService,
public exerciseService: ExerciseService,
public toastCtrl: ToastController) {
// remove old sentence boundaries
this.corpusService.baseUrn = this.corpusService.currentUrn.split('@')[0];
}
showText(rank: Sentence[]) {
// remove old sentence boundaries
this.corpusService.currentUrn = this.corpusService.currentUrn.split('@')[0];
this.corpusService.currentUrn += `@${rank[0].id}-${rank[rank.length - 1].id}`;
this.corpusService.currentUrn = this.corpusService.baseUrn + `@${rank[0].id}-${rank[rank.length - 1].id}`;
HelperService.currentError = null;
HelperService.isLoading = true;
this.vocService.getVocabularyCheck(this.corpusService.currentUrn, true).subscribe((ar: AnnisResponse) => {
HelperService.isLoading = false;
const urnStart: string = ar.graph.nodes[0].id.split('/')[1];
const urnEnd: string = ar.graph.nodes.slice(-1)[0].id.split('/')[1];
this.corpusService.currentUrn = urnStart.concat('-', urnEnd.split(':').slice(-1)[0]);
this.corpusService.processAnnisResponse(ar);
HelperService.goToShowTextPage(this.navCtrl, true);
}, async (error: HttpErrorResponse) => {
......
......@@ -30,8 +30,9 @@
</ion-row>
<ion-row *ngIf="HelperService.isVocabularyCheck">
<ion-col>
<label>{{ "TEXT_SHOW_OOV" | translate}}
<label>
<input type="checkbox" [(ngModel)]="highlightOOV"/>
<span class="checkbox">{{ "TEXT_SHOW_OOV" | translate}}</span>
</label>
<br>
</ion-col>
......
.oov {
text-decoration: underline;
}
input {
float: left;
}
......@@ -31,7 +31,8 @@ export class TextRangePage {
constructor(public navCtrl: NavController,
public corpusService: CorpusService,
public toastCtrl: ToastController,
public translateService: TranslateService) {
public translateService: TranslateService,
public helperService: HelperService) {
this.currentlyAvailableCitations = [];
this.corpusService.isTextRangeCorrect = false;
this.corpusService.currentTextRange = new TextRange({start: ['', '', ''], end: ['', '', '']});
......@@ -85,25 +86,18 @@ export class TextRangePage {
HelperService.currentError = null;
HelperService.isLoading = true;
return new Promise((resolve, reject) => {
this.corpusService.getCTSvalidReff(fullUrn).subscribe((result: string[] | object) => {
this.corpusService.getCTSvalidReff(fullUrn).subscribe((result: string[]) => {
HelperService.isLoading = false;
let newCitations: Citation[] = [];
if (!Array.isArray(result)) {
// this is a custom corpus
const textparts: object[] = result['textparts'];
newCitations = textparts.map(x => x['citation']) as Citation[];
} else {
// this is a CTS corpus
const urnList: string[] = result as string[];
const replaceString: string = fullUrn + (urnLastPart ? '.' : ':');
urnList.forEach((urn) => {
newCitations.push(new Citation({
level: targetCitationLevel,
label: urn.replace(replaceString, ''),
value: +urn.replace(replaceString, '')
}));
});
}
const newCitations: Citation[] = [];
const urnList: string[] = result as string[];
const replaceString: string = fullUrn + (urnLastPart ? '.' : ':');
urnList.forEach((urn) => {
newCitations.push(new Citation({
level: targetCitationLevel,
label: urn.replace(replaceString, ''),
value: +urn.replace(replaceString, '')
}));
});
newCitations.forEach((citation) => {
citation.subcitations = {};
if (relevantCitations.length === 0) {
......@@ -363,23 +357,22 @@ export class TextRangePage {
return;
}
const newUrnBase: string = this.corpusService.currentCorpus.source_urn + ':';
const workReference: string = this.citationValuesStart.join('.') + '-' + this.citationValuesEnd.join('.');
this.corpusService.currentUrn = newUrnBase + workReference;
this.corpusService.currentUrn = newUrnBase + this.citationValuesStart.join('.') + '-' + this.citationValuesEnd.join('.');
HelperService.mostRecentSetup = new ApplicationState({
currentUrn: this.corpusService.currentUrn,
currentCorpus: this.corpusService.currentCorpus,
workReference,
currentTextRange: this.corpusService.currentTextRange
});
HelperService.saveMostRecentSetup();
this.corpusService.isTextRangeCorrect = true;
this.corpusService.getText().then(() => {
if (HelperService.isVocabularyCheck) {
HelperService.goToVocabularyCheckPage(this.navCtrl);
} else {
HelperService.goToShowTextPage(this.navCtrl);
}
}, () => {
this.helperService.saveMostRecentSetup().then(() => {
this.corpusService.isTextRangeCorrect = true;
this.corpusService.getText().then(() => {
if (HelperService.isVocabularyCheck) {
HelperService.goToVocabularyCheckPage(this.navCtrl);
} else {
HelperService.goToShowTextPage(this.navCtrl);
}
}, () => {
});
});
});
}
......
......@@ -20,9 +20,7 @@
<label>
<span>{{ 'VOCABULARY_QUERY_CORPUS' | translate }}</span>
<span class="button-like" (click)="chooseCorpus()">{{corpusService.currentCorpus ?
(corpusService.currentCorpus.author + ": " + corpusService.currentCorpus.title + " " +
corpusService.currentTextRange.start + "-" + corpusService.currentTextRange.end) :
'VOCABULARY_CHOOSE_CORPUS' | translate}}</span>
currentCorpusString : 'VOCABULARY_CHOOSE_CORPUS' | translate}}</span>
</label>
</ion-col>
</ion-row>
......
import {NavController, ToastController} from '@ionic/angular';
import {Component} from '@angular/core';
import {Component, OnInit} from '@angular/core';
import {VocabularyCorpus, VocabularyCorpusTranslation} from 'src/app/models/enum';
import {VocabularyService} from 'src/app/vocabulary.service';
import {HttpClient, HttpErrorResponse} from '@angular/common/http';
......@@ -14,13 +14,14 @@ import {CorpusService} from 'src/app/corpus.service';
templateUrl: './vocabulary-check.page.html',
styleUrls: ['./vocabulary-check.page.scss'],
})
export class VocabularyCheckPage {
export class VocabularyCheckPage implements OnInit {
HelperService = HelperService;
invalidSentenceCountString: string;
ObjectKeys = Object.keys;
VocabularyCorpus = VocabularyCorpus;
VocabularyCorpusTranslation = VocabularyCorpusTranslation;
invalidQueryCorpusString: string;
public currentCorpusString: string;
public currentRankingUnits: Sentence[][];
constructor(public navCtrl: NavController,
......@@ -110,6 +111,12 @@ export class VocabularyCheckPage {
this.vocService.ranking = this.currentRankingUnits;
}
ngOnInit(): void {
this.currentCorpusString = this.corpusService.currentCorpus.author + ': ' + this.corpusService.currentCorpus.title + ' ' +
this.corpusService.currentTextRange.start.filter(x => x).join('.') + '-' +
this.corpusService.currentTextRange.end.filter(x => x).join('.');
}
updateReferenceRange() {
const hasFreq: boolean = this.vocService.refVocMap[this.vocService.currentReferenceVocabulary].hasFrequencyOrder;
this.vocService.frequencyUpperBound = hasFreq ? 500 : this.getPossibleSubCount();
......
......@@ -102,6 +102,22 @@
font-size: 1.4em;
}
label > span:first-of-type {
font-weight: bold;
padding-right: 1em;
word-wrap: break-spaces;
}
select {
max-width: 95%;
border-radius: 10px;
text-overflow: ellipsis;
}
.checkbox {
padding-left: 1em;
}
.hide {
display: none;
}
......@@ -132,18 +148,6 @@
right: 0;
}
label > span:first-of-type {
font-weight: bold;