diff --git a/package.json b/package.json index 530bd9f4b6cab6c8b8d39ebbb3e779119a5141d7..c9e019838228f8e97fd612724e41dea20679b1ff 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "mc_frontend", - "version": "1.4.8", + "version": "1.5.0", "author": "Ionic Framework", "homepage": "https://ionicframework.com/", "scripts": { diff --git a/src/app/author-detail/author-detail.page.html b/src/app/author-detail/author-detail.page.html index 765d8deb54cab8de141c2a56ac949ced7cbacced..4449c3c8c6e0c563e66900e6df7a57392260b7e5 100644 --- a/src/app/author-detail/author-detail.page.html +++ b/src/app/author-detail/author-detail.page.html @@ -8,7 +8,7 @@ - {{ corpusService.currentAuthor?.name }} + {{ state.currentSetup.currentAuthor?.name }} @@ -17,9 +17,8 @@ - - - + + diff --git a/src/app/author-detail/author-detail.page.ts b/src/app/author-detail/author-detail.page.ts index 7aa65ce67c383f838b8699b8d7bc4d0170c8e5ed..4b72136116da627912ce124eba6220b4e9338e30 100644 --- a/src/app/author-detail/author-detail.page.ts +++ b/src/app/author-detail/author-detail.page.ts @@ -5,25 +5,23 @@ import {TranslateService} from '@ngx-translate/core'; import {HelperService} from '../helper.service'; import {CorpusService} from 'src/app/corpus.service'; import {HttpClient} from '@angular/common/http'; -import {TextRange} from 'src/app/models/textRange'; @Component({ - selector: 'app-author-detail', - templateUrl: './author-detail.page.html', - styleUrls: ['./author-detail.page.scss'], + selector: 'app-author-detail', + templateUrl: './author-detail.page.html', + styleUrls: ['./author-detail.page.scss'], }) export class AuthorDetailPage { - HelperService = HelperService; + HelperService = HelperService; - constructor(public navCtrl: NavController, - public corpusService: CorpusService, - public translate: TranslateService, - public http: HttpClient) { - } + constructor(public navCtrl: NavController, + public corpusService: CorpusService, + public translate: TranslateService, + public http: HttpClient) { + } - showPossibleReferences(corpus: CorpusMC) { - this.corpusService.currentCorpus = corpus; - this.corpusService.currentTextRange = new TextRange({start: ['', '', ''], end: ['', '', '']}); - HelperService.goToTextRangePage(this.navCtrl).then(); - } + showPossibleReferences(corpus: CorpusMC) { + this.corpusService.saveNewCorpus(corpus); + HelperService.goToTextRangePage(this.navCtrl).then(); + } } diff --git a/src/app/author/author.page.html b/src/app/author/author.page.html index eff3e86c318c3eb6b37851596f06352a9e30e1ef..59357fe6971c5b3f46d572da2269396c7cbaf728 100644 --- a/src/app/author/author.page.html +++ b/src/app/author/author.page.html @@ -20,20 +20,29 @@ {{ 'MOST_RECENT_SETUP' | translate }}: - - - - - - {{ [HelperService.mostRecentSetup.currentCorpus.author, - HelperService.mostRecentSetup.currentCorpus.title, - HelperService.mostRecentSetup.currentUrn?.split(":").slice(-1)[0]].join(", ") }} + + @@ -43,7 +52,7 @@ @@ -51,7 +60,7 @@

{{'AUTHOR' | translate}}

+ style="text-align: left"> {{author.name}} diff --git a/src/app/author/author.page.ts b/src/app/author/author.page.ts index 3821fd6ddde4bdd90c9b04450f5c11c5ba9f6c6b..8511d0dba78225a5fbaa6717a149dc4ca6c8b8c8 100644 --- a/src/app/author/author.page.ts +++ b/src/app/author/author.page.ts @@ -6,6 +6,9 @@ import {CorpusService} from 'src/app/corpus.service'; import {HttpClient} from '@angular/common/http'; import {HelperService} from '../helper.service'; import {ExerciseService} from '../exercise.service'; +import {ApplicationState} from '../models/applicationState'; +import {Observable} from 'rxjs'; +import {take} from 'rxjs/operators'; /** * Generated class for the AuthorPage page. @@ -71,9 +74,11 @@ export class AuthorPage { showCorpora(author: Author) { this.corpusService.currentAuthor = author; - HelperService.mostRecentSetup.currentAuthor = author; - this.helperService.saveMostRecentSetup().then(); - this.navCtrl.navigateForward('/author-detail').then(); + HelperService.applicationState.pipe(take(1)).subscribe((as: ApplicationState) => { + as.currentSetup.currentAuthor = author; + this.helperService.saveApplicationState(as).then(); + this.navCtrl.navigateForward('/author-detail').then(); + }); } toggleTreebankAuthors() { diff --git a/src/app/corpus.service.ts b/src/app/corpus.service.ts index c797c175cfb23e214a91015f6e4b30fb840ded06..e1e564f87c9eb48db5807cacd35b873638b2f669 100644 --- a/src/app/corpus.service.ts +++ b/src/app/corpus.service.ts @@ -15,7 +15,7 @@ import { DependencyValue, ExerciseType, ExerciseTypeTranslation, - InstructionsTranslation, MoodleExerciseType, + InstructionsTranslation, PartOfSpeechTranslation, PartOfSpeechValue, Phenomenon @@ -27,7 +27,10 @@ import {Exercise} from 'src/app/models/exercise'; import {Feedback} from 'src/app/models/feedback'; import {PhenomenonMap, PhenomenonMapContent} from 'src/app/models/phenomenonMap'; import {FrequencyItem} from 'src/app/models/frequencyItem'; -import {ExerciseMC} from 'src/app/models/exerciseMC'; +import {BehaviorSubject, ReplaySubject} from 'rxjs'; +import {ApplicationState} from './models/applicationState'; +import {take} from 'rxjs/operators'; +import {TextData} from './models/textData'; @Injectable({ providedIn: 'root' @@ -40,9 +43,11 @@ export class CorpusService { public citationsUnavailableString: string; public corporaUnavailableString: string; public currentAuthor: Author; - public currentCorpus: CorpusMC; + public currentCorpus: ReplaySubject; + private currentCorpusCache: CorpusMC; public currentText = ''; - public currentTextRange: TextRange = new TextRange({start: ['', '', ''], end: ['', '', '']}); + public currentTextRange: ReplaySubject; + private currentTextRangeCache: TextRange = new TextRange({start: ['', '', ''], end: ['', '', '']}); public currentUrn: string; public exercise: Exercise = new Exercise({ type: ExerciseType.cloze, @@ -71,16 +76,18 @@ export class CorpusService { public helperService: HelperService, ) { this.isMostRecentSetupLoaded = false; + this.helperService.initApplicationState(); + this.initCurrentCorpus(); + this.initCurrentTextRange(); HelperService.waitForConfig().then(() => { - this.checkForUpdates().then(() => { + this.checkForUpdates().finally(() => { this.checkAnnisResponse().then(() => { this.restoreLastCorpus().then(() => { this.isMostRecentSetupLoaded = true; - }, () => { }); }, () => { + this.isMostRecentSetupLoaded = true; }); - }, () => { }); }); this.initPhenomenonMap(); @@ -122,12 +129,16 @@ export class CorpusService { if (this.annisResponse) { return outerResolve(); } - this.helperService.loadMostRecentSetup().then(() => { - this.annisResponse = HelperService.mostRecentSetup.annisResponse; - this.currentAuthor = HelperService.mostRecentSetup.currentAuthor; - this.currentUrn = HelperService.mostRecentSetup.currentUrn; - this.currentCorpus = HelperService.mostRecentSetup.currentCorpus; - return outerResolve(); + HelperService.applicationState.pipe(take(1)).subscribe((state: ApplicationState) => { + if (state.mostRecentSetup) { + this.annisResponse = state.mostRecentSetup.annisResponse; + this.currentAuthor = state.mostRecentSetup.currentAuthor; + this.currentUrn = state.mostRecentSetup.currentUrn; + this.currentCorpusCache = state.mostRecentSetup.currentCorpus; + return outerResolve(); + } else { + return outerReject(); + } }, () => { return outerReject(); }); @@ -212,8 +223,10 @@ export class CorpusService { HelperService.makeGetRequest(this.http, this.toastCtrl, url, params).then((fis: FrequencyItem[]) => { HelperService.isLoading = false; this.annisResponse.frequency_analysis = fis; - HelperService.mostRecentSetup.annisResponse = this.annisResponse; - this.helperService.saveMostRecentSetup().then(); + HelperService.applicationState.pipe(take(1)).subscribe((as: ApplicationState) => { + as.mostRecentSetup.annisResponse = this.annisResponse; + this.helperService.saveApplicationState(as).then(); + }); return resolve(); }, () => { return reject(); @@ -281,6 +294,27 @@ export class CorpusService { this.translate.get('LINK_COPIED').subscribe(value => this.shareLinkCopiedString = value); } + initCurrentCorpus(): void { + this.currentCorpus = new ReplaySubject(1); + if (!this.currentCorpusCache) { + HelperService.applicationState.subscribe((as: ApplicationState) => { + const textData: TextData = as.currentSetup ? as.currentSetup : as.mostRecentSetup; + this.currentCorpusCache = textData ? textData.currentCorpus : null; + this.currentCorpus.next(this.currentCorpusCache); + }); + } else { + this.currentCorpus.next(this.currentCorpusCache); + } + } + + initCurrentTextRange(): void { + this.currentTextRange = new ReplaySubject(1); + HelperService.applicationState.pipe(take(1)).subscribe((state: ApplicationState) => { + this.currentTextRangeCache = state.currentSetup.currentTextRange; + this.currentTextRange.next(this.currentTextRangeCache); + }); + } + initPhenomenonMap() { // map the different phenomena to their respective Enum for processing and display/translation Object.keys(Phenomenon).forEach((key) => { @@ -336,9 +370,11 @@ export class CorpusService { }); this.annisResponse = ar; if (saveToCache) { - HelperService.mostRecentSetup.currentUrn = this.currentUrn; - HelperService.mostRecentSetup.annisResponse = ar; - this.helperService.saveMostRecentSetup().then(); + HelperService.applicationState.pipe(take(1)).subscribe((as: ApplicationState) => { + as.currentSetup.currentUrn = this.currentUrn; + as.currentSetup.annisResponse = ar; + this.helperService.saveApplicationState(as).then(); + }); } } @@ -404,28 +440,56 @@ export class CorpusService { restoreLastCorpus() { return new Promise((resolve, reject) => { - this.annisResponse = HelperService.mostRecentSetup.annisResponse; - this.currentUrn = HelperService.mostRecentSetup.currentUrn; - this.currentCorpus = HelperService.mostRecentSetup.currentCorpus; - this.currentTextRange = HelperService.mostRecentSetup.currentTextRange; - this.isTextRangeCorrect = true; - if (this.annisResponse && this.annisResponse.nodes.length) { - this.processAnnisResponse(this.annisResponse, false); - } - // check if the data is already present - if (this.currentText) { - return resolve(); - } - const saveToCache: boolean = !HelperService.mostRecentSetup.annisResponse || - !HelperService.mostRecentSetup.annisResponse.nodes.length; - this.getText(saveToCache).then(() => { - return resolve(); - }, () => { - return reject(); + HelperService.applicationState.pipe(take(1)).subscribe((state: ApplicationState) => { + this.annisResponse = state.mostRecentSetup.annisResponse; + this.currentUrn = state.mostRecentSetup.currentUrn; + this.currentCorpusCache = state.mostRecentSetup.currentCorpus; + this.currentTextRangeCache = state.mostRecentSetup.currentTextRange; + this.isTextRangeCorrect = true; + if (this.annisResponse && this.annisResponse.nodes.length) { + this.processAnnisResponse(this.annisResponse, false); + return resolve(); + } else if (this.currentText) { + // check if the data is already present + return resolve(); + } else { + const saveToCache: boolean = !state.mostRecentSetup.annisResponse || !state.mostRecentSetup.annisResponse.nodes.length; + this.getText(saveToCache).then(() => { + return resolve(); + }, () => { + return reject(); + }); + } }); }); } + saveNewCorpus(corpus: CorpusMC): void { + this.currentCorpusCache = corpus; + this.currentCorpus.next(this.currentCorpusCache); + this.setCurrentTextRange(-1, null, new TextRange({start: ['', '', ''], end: ['', '', '']})); + HelperService.applicationState.pipe(take(1)).subscribe((state: ApplicationState) => { + state.currentSetup.currentCorpus = corpus; + HelperService.applicationState.next(state); + }); + } + + setCurrentTextRange(inputId: number = -1, newValue: string = null, tr: TextRange = null): void { + if (tr) { + this.currentTextRangeCache = tr; + } else if (inputId >= 0) { + const isStart: boolean = inputId < 4; + const targetInputId = `input${inputId}`; + if (newValue === null) { + newValue = document.querySelector(`#${targetInputId}`).value; + } + const trIdx: number = inputId - (isStart ? 1 : 4); + const relevantTextRangePart: string[] = isStart ? this.currentTextRangeCache.start : this.currentTextRangeCache.end; + relevantTextRangePart[trIdx] = newValue; + } + this.currentTextRange.next(this.currentTextRangeCache); + } + updateBaseWord(query: QueryMC, queryIndex: number) { if (!this.annisResponse || !this.annisResponse.frequency_analysis || !this.annisResponse.frequency_analysis.length) { return; diff --git a/src/app/exercise-parameters/exercise-parameters.page.html b/src/app/exercise-parameters/exercise-parameters.page.html index 6e26d230aab7115557ac437c1d9dfb7effb68d59..9efb16af5dce8ff7266768e9b0c407b41ac98fbd 100644 --- a/src/app/exercise-parameters/exercise-parameters.page.html +++ b/src/app/exercise-parameters/exercise-parameters.page.html @@ -60,24 +60,22 @@ + *ngIf="corpusService.exercise.type === ExerciseType.matching; else notMatching"> - + diff --git a/src/app/exercise-parameters/exercise-parameters.page.ts b/src/app/exercise-parameters/exercise-parameters.page.ts index a267a2a83cc22d31793464b3e0a11c44dc5742ae..90c16091f34d8db8085c97c7548de3db9d3502ef 100644 --- a/src/app/exercise-parameters/exercise-parameters.page.ts +++ b/src/app/exercise-parameters/exercise-parameters.page.ts @@ -17,6 +17,10 @@ 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'; +import {CorpusMC} from '../models/corpusMC'; +import {ApplicationState} from '../models/applicationState'; +import {take} from 'rxjs/operators'; +import {TextRange} from '../models/textRange'; @Component({ selector: 'app-exercise-parameters', @@ -107,20 +111,22 @@ export class ExerciseParametersPage implements OnInit { const values: string[] = this.corpusService.exercise.queryItems[0].values as string[]; 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 + ', ' + - this.corpusService.currentTextRange.start.filter(x => x).join('.') + '-' + - this.corpusService.currentTextRange.end.filter(x => x).join('.'); - formData.append('work_title', workTitle); - formData.append('type', MoodleExerciseType[this.corpusService.exercise.type]); - formData.append('type_translation', this.corpusService.exercise.typeTranslation); - formData.append('instructions', instructions); - formData.append('correct_feedback', this.corpusService.exercise.feedback.correct); - formData.append('partially_correct_feedback', this.corpusService.exercise.feedback.partiallyCorrect); - formData.append('incorrect_feedback', this.corpusService.exercise.feedback.incorrect); - formData.append('general_feedback', this.corpusService.exercise.feedback.general); - formData.append('work_author', this.corpusService.currentCorpus.author); - this.getH5Pexercise(formData); + this.corpusService.currentCorpus.pipe(take(1)).subscribe((cc: CorpusMC) => { + this.corpusService.currentTextRange.pipe(take(1)).subscribe((tr: TextRange) => { + // TODO: change the corpus title to something meaningful, e.g. concatenate user ID and wanted exercise title + const workTitle: string = cc.title + ', ' + tr.start.filter(x => x).join('.') + '-' + tr.end.filter(x => x).join('.'); + formData.append('work_title', workTitle); + formData.append('type', MoodleExerciseType[this.corpusService.exercise.type]); + formData.append('type_translation', this.corpusService.exercise.typeTranslation); + formData.append('instructions', instructions); + formData.append('correct_feedback', this.corpusService.exercise.feedback.correct); + formData.append('partially_correct_feedback', this.corpusService.exercise.feedback.partiallyCorrect); + formData.append('incorrect_feedback', this.corpusService.exercise.feedback.incorrect); + formData.append('general_feedback', this.corpusService.exercise.feedback.general); + formData.append('work_author', cc.author); + this.getH5Pexercise(formData); + }); + }); } getH5Pexercise(formData: FormData) { @@ -131,12 +137,14 @@ export class ExerciseParametersPage implements OnInit { 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; - this.corpusService.annisResponse.uri = ar.uri; - this.corpusService.annisResponse.solutions = ar.solutions; - HelperService.goToPreviewPage(this.navCtrl).then(); + HelperService.applicationState.pipe(take(1)).subscribe((as: ApplicationState) => { + as.mostRecentSetup.annisResponse = ar; + this.helperService.saveApplicationState(as).then(); + this.corpusService.annisResponse.exercise_id = ar.exercise_id; + this.corpusService.annisResponse.uri = ar.uri; + this.corpusService.annisResponse.solutions = ar.solutions; + HelperService.goToPreviewPage(this.navCtrl).then(); + }); }, async (error: HttpErrorResponse) => { HelperService.isLoading = false; HelperService.currentError = error; diff --git a/src/app/exercise.service.ts b/src/app/exercise.service.ts index ef4cf14e31fdd062bdfd608df73a1040817cb5f4..a6cfca64d411e5a9898d783c1a15a9ca7b32df3f 100644 --- a/src/app/exercise.service.ts +++ b/src/app/exercise.service.ts @@ -16,7 +16,6 @@ window.onresize = () => { }) export class ExerciseService { public excludeOOV = false; - public exerciseTypePath: string; public fillBlanksString = 'fill_blanks'; public h5pIframeString = '#h5p-iframe-1'; public kwicGraphs: string; diff --git a/src/app/exercise/exercise.page.ts b/src/app/exercise/exercise.page.ts index 4bc89f2af5233b97fe32c0fd272cc485471444b6..4e04d4ee210b5616caa5d8c16ad03555052a4c9a 100644 --- a/src/app/exercise/exercise.page.ts +++ b/src/app/exercise/exercise.page.ts @@ -9,6 +9,8 @@ import {HttpClient, HttpParams} from '@angular/common/http'; import {AnnisResponse} from 'src/app/models/annisResponse'; import {ExerciseType, MoodleExerciseType} from 'src/app/models/enum'; import {CorpusService} from 'src/app/corpus.service'; +import {ApplicationState} from '../models/applicationState'; +import {take} from 'rxjs/operators'; @Component({ selector: 'app-exercise', @@ -38,18 +40,20 @@ export class ExercisePage implements OnInit { let url: string = HelperService.config['backendBaseUrl'] + HelperService.config['backendApiExercisePath']; const httpParams: HttpParams = new HttpParams().set('eid', params['eid']); HelperService.makeGetRequest(this.http, this.toastCtrl, url, httpParams).then((ar: AnnisResponse) => { - HelperService.mostRecentSetup.annisResponse = ar; - this.helperService.saveMostRecentSetup().then(); - this.corpusService.annisResponse = ar; - const met: MoodleExerciseType = MoodleExerciseType[ar.exercise_type]; - this.corpusService.exercise.type = ExerciseType[met.toString()]; - // this will be called via GET request from the h5p standalone javascript library - url = `${HelperService.config['backendBaseUrl']}${HelperService.config['backendApiH5pPath']}` + - `?eid=${this.corpusService.annisResponse.exercise_id}&lang=${this.translateService.currentLang}`; - window.localStorage.setItem(HelperService.config['localStorageKeyH5P'], url); - const exerciseTypePath: string = this.corpusService.exercise.type === ExerciseType.markWords ? - 'mark_words' : 'drag_text'; - this.exerciseService.initH5P(exerciseTypePath); + HelperService.applicationState.pipe(take(1)).subscribe((as: ApplicationState) => { + as.mostRecentSetup.annisResponse = ar; + this.helperService.saveApplicationState(as).then(); + this.corpusService.annisResponse = ar; + const met: MoodleExerciseType = MoodleExerciseType[ar.exercise_type]; + this.corpusService.exercise.type = ExerciseType[met.toString()]; + // this will be called via GET request from the h5p standalone javascript library + url = `${HelperService.config['backendBaseUrl']}${HelperService.config['backendApiH5pPath']}` + + `?eid=${this.corpusService.annisResponse.exercise_id}&lang=${this.translateService.currentLang}`; + window.localStorage.setItem(HelperService.config['localStorageKeyH5P'], url); + const exerciseTypePath: string = this.corpusService.exercise.type === ExerciseType.markWords ? + 'mark_words' : 'drag_text'; + this.exerciseService.initH5P(exerciseTypePath); + }); }, () => { }); } else { diff --git a/src/app/helper.service.ts b/src/app/helper.service.ts index 12ea62b1641184dd34de9097597360cde44fe3b9..54f6243963dc322030233e6ea90b92abd1373644 100644 --- a/src/app/helper.service.ts +++ b/src/app/helper.service.ts @@ -8,12 +8,16 @@ import {CaseValue, DependencyValue, PartOfSpeechValue} from 'src/app/models/enum import {TranslateService} from '@ngx-translate/core'; import {Storage} from '@ionic/storage'; import {Language} from 'src/app/models/language'; +import {ReplaySubject} from 'rxjs'; +import {TextData} from './models/textData'; @Injectable({ providedIn: 'root' }) export class HelperService { + public static applicationState: ReplaySubject = null; + private static applicationStateCache: ApplicationState = null; public static baseUrl: string = location.protocol.concat('//').concat(window.location.host) + window.location.pathname.split('/').slice(0, -1).join('/'); public static caseMap: { [rawValue: string]: CaseValue } = { @@ -81,7 +85,6 @@ export class HelperService { shortcut: 'en' }), new Language({name: 'Deutsch', shortcut: 'de'})]; public static menuId = 'menu1'; - public static mostRecentSetup: ApplicationState = null; public static partOfSpeechMap: { [rawValue: string]: PartOfSpeechValue } = { ADJ: PartOfSpeechValue.adjective, ADP: PartOfSpeechValue.preposition, @@ -142,7 +145,7 @@ export class HelperService { } static goToAuthorDetailPage(navCtrl: NavController): Promise { - return navCtrl.navigateForward('/author-detail'); + return navCtrl.navigateForward('/author-detail'); } static goToDocExercisesPage(navCtrl: NavController): Promise { @@ -235,7 +238,10 @@ export class HelperService { }, 0); return resolve(result); }, async (error: HttpErrorResponse) => { - HelperService.isLoading = false; + // dirty hack to avoid ExpressionChangedAfterItHasBeenCheckedError + setTimeout(() => { + HelperService.isLoading = false; + }, 0); HelperService.currentError = error; const toast = await toastCtrl.create({ message: HelperService.generalErrorAlertMessage, @@ -274,6 +280,24 @@ export class HelperService { }); } + initApplicationState(): void { + HelperService.applicationState = new ReplaySubject(1); + if (!HelperService.applicationStateCache) { + this.storage.get(HelperService.config['localStorageKeyApplicationState']).then((jsonString: string) => { + HelperService.applicationStateCache = new ApplicationState({ + currentSetup: new TextData() + }); + if (jsonString) { + const parsedJson: object = JSON.parse(jsonString); + HelperService.applicationStateCache = parsedJson as ApplicationState; + } + HelperService.applicationState.next(HelperService.applicationStateCache); + }); + } else { + HelperService.applicationState.next(HelperService.applicationStateCache); + } + } + initConfig() { return new Promise((resolve) => { this.http.get('assets/config.json').subscribe((config: object) => { @@ -295,25 +319,11 @@ export class HelperService { }); } - loadMostRecentSetup() { - return new Promise(async (resolve, reject) => { - this.storage.get(HelperService.config['localStorageKeyMostRecentSetup']).then((mrs: string) => { - if (!mrs) { - HelperService.mostRecentSetup = new ApplicationState(); - return reject(); - } - HelperService.mostRecentSetup = JSON.parse(mrs); - return resolve(); - }, (error: any) => { - return reject(); - }); - }); - } - - saveMostRecentSetup() { + saveApplicationState(mrs: ApplicationState) { return new Promise((resolve) => { - const lskmrs: string = HelperService.config['localStorageKeyMostRecentSetup']; - this.storage.set(lskmrs, JSON.stringify(HelperService.mostRecentSetup)).then(() => { + HelperService.applicationStateCache = mrs; + HelperService.applicationState.next(HelperService.applicationStateCache); + this.storage.set(HelperService.config['localStorageKeyApplicationState'], JSON.stringify(mrs)).then(() => { return resolve(); }); }); diff --git a/src/app/home/home.page.html b/src/app/home/home.page.html index 07e2c6610ab342f1236e7462eded6979d2b3d954..e843a89928238ddbf38154a5d4d8a5bc73c70d8e 100644 --- a/src/app/home/home.page.html +++ b/src/app/home/home.page.html @@ -4,7 +4,7 @@ -
+
{{'MACHINA_CALLIDA' | translate}}
@@ -12,7 +12,7 @@
+ name="currentLanguage" placeholder="{{HelperService.currentLanguage?.name}}"> {{lang.name}} @@ -36,13 +36,12 @@
Übungsbeispiel + style="padding: 0.5em 0.25em 0 0.25em;">

{{ 'EXERCISE_GENERATE' | translate }}

{{'TEXT_SELECTION' | translate }}
{{'TEXT_COMPLEXITY' | translate }}
{{'VOCABULARY_CHECK' | translate }}
{{'EXERCISE_PARAMETERS' | translate }} -

{{ 'CONTINUE' | translate }} @@ -53,13 +52,12 @@

Screenshot der Datenbank + style="padding: 0.5em 0.25em 0 0.25em;">

{{ 'EXERCISE_LIST' | translate }}

{{'EXERCISES_CREATED' | translate }}
{{'EXERCISE_TYPE_CLOZE' | translate }}
{{'EXERCISE_TYPE_MARK_WORDS' | translate }}
{{'EXERCISE_TYPE_MATCHING' | translate }}
-

{{ 'CONTINUE' | translate }} @@ -70,7 +68,7 @@

Ergebnisübersicht des Testmoduls + style="padding: 0.5em 0.25em 0 0.25em;">

{{ 'TEST' | translate }}

{{'TEXT_WORK' | translate }}
@@ -86,8 +84,9 @@

- Skizze, wie die Software-Architektur aussehen soll + Skizze, wie die Software-Architektur aussehen soll

{{ 'DOCUMENTATION' | translate }}

{{'ABOUT' | translate }}
{{'DOC_SOFTWARE' | translate }}
@@ -101,14 +100,6 @@

- - - - - - - - diff --git a/src/app/models/applicationState.ts b/src/app/models/applicationState.ts index 3dbdeaf5a618d3ec82a7140ca814228a558a346c..3e3c3c59e59964b3486f49879f9657894daddc02 100644 --- a/src/app/models/applicationState.ts +++ b/src/app/models/applicationState.ts @@ -1,14 +1,8 @@ -import {CorpusMC} from 'src/app/models/corpusMC'; -import {TextRange} from 'src/app/models/textRange'; -import {AnnisResponse} from 'src/app/models/annisResponse'; -import {Author} from 'src/app/models/author'; +import {TextData} from './textData'; export class ApplicationState { - public annisResponse: AnnisResponse; - public currentAuthor: Author; - public currentCorpus: CorpusMC; - public currentTextRange: TextRange; - public currentUrn: string; + public currentSetup: TextData; + public mostRecentSetup: TextData; constructor(init?: Partial) { Object.assign(this, init); diff --git a/src/app/models/textData.ts b/src/app/models/textData.ts new file mode 100644 index 0000000000000000000000000000000000000000..98efa67eb3d777d92cbae0b9cba8491e9feb137c --- /dev/null +++ b/src/app/models/textData.ts @@ -0,0 +1,16 @@ +import {CorpusMC} from 'src/app/models/corpusMC'; +import {TextRange} from 'src/app/models/textRange'; +import {AnnisResponse} from 'src/app/models/annisResponse'; +import {Author} from 'src/app/models/author'; + +export class TextData { + public annisResponse: AnnisResponse; + public currentAuthor: Author; + public currentCorpus: CorpusMC; + public currentTextRange: TextRange; + public currentUrn: string; + + constructor(init?: Partial) { + Object.assign(this, init); + } +} diff --git a/src/app/models/xAPIevent.ts b/src/app/models/xAPIevent.ts index 6eac1c76a5a878d0a37e6a91027901d3a5016310..1dc4fe42b6a8d1fc479cec221a2986ba716aa4cc 100644 --- a/src/app/models/xAPIevent.ts +++ b/src/app/models/xAPIevent.ts @@ -1,4 +1,4 @@ -import StatementBase from "src/app/models/xAPI/StatementBase"; +import StatementBase from 'src/app/models/xAPI/StatementBase'; export class XAPIevent { public data: { statement: StatementBase }; diff --git a/src/app/show-text/show-text.page.html b/src/app/show-text/show-text.page.html index c4a09417dace180833ea1897e9634c25491bed0e..969844d21c7af358b52ee5da4681030fff459455 100644 --- a/src/app/show-text/show-text.page.html +++ b/src/app/show-text/show-text.page.html @@ -8,8 +8,8 @@
- - {{corpusService.currentCorpus?.title}} + + {{cc.title}} {{corpusService.currentUrn?.split(":")[corpusService.currentUrn?.split(":").length - 1]}} @@ -27,7 +27,7 @@
@@ -38,18 +38,17 @@
{{node.annis_tok}}{{ getWhiteSpace(i) }} + [class.oov]="node.is_oov">{{node.annis_tok}}{{ getWhiteSpace(i) }}
{{corpusService.currentText}}
- - + + - @@ -58,7 +57,8 @@
-

+

{{ 'TEXT_COMPLEXITY' | translate }}

- {{corpusService.currentCorpus?.title}} + {{cc.title}} @@ -17,163 +17,166 @@ - - -

{{'TEXT_RANGE' | translate}}

-
- - - {{ 'START_OF_TEXT' | translate }} - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - {{ 'END_OF_TEXT' | translate }} - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - {{ 'BACK' | translate }} - - - {{ "SHOW_TEXT" | translate }} - - - {{ "EXERCISE_SET_PARAMETERS" | translate }} - - -
+
+ + +

{{'TEXT_RANGE' | translate}}

+
+ + + {{ 'START_OF_TEXT' | translate }} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {{ 'END_OF_TEXT' | translate }} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {{ 'BACK' | translate }} + + + + {{ (HelperService.isVocabularyCheck ? "VOCABULARY_CHECK" : "SHOW_TEXT") | translate }} + + + + {{ "EXERCISE_SET_PARAMETERS" | translate }} + + +
+
diff --git a/src/app/text-range/text-range.page.ts b/src/app/text-range/text-range.page.ts index d1f454d48ff89530ca24d776e1f879a4fbdb71dc..31ed2d6edee79080e7996514aed85505bd1ac8bc 100644 --- a/src/app/text-range/text-range.page.ts +++ b/src/app/text-range/text-range.page.ts @@ -8,6 +8,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'; +import {CorpusMC} from '../models/corpusMC'; +import {BehaviorSubject} from 'rxjs'; +import {take} from 'rxjs/operators'; +import {TextRange} from '../models/textRange'; @Component({ selector: 'app-text-range', @@ -22,6 +26,10 @@ export class TextRangePage { public currentInputId = 0; public citationValuesStart: number[]; public citationValuesEnd: number[]; + public isInputDisabled: { [isStart: number]: BehaviorSubject } = { + 0: new BehaviorSubject(true), + 1: new BehaviorSubject(true) + }; public isTextRangeCheckRunning = false; HelperService = HelperService; @@ -32,23 +40,16 @@ export class TextRangePage { public helperService: HelperService) { this.currentlyAvailableCitations = []; this.corpusService.isTextRangeCorrect = false; - if (!this.corpusService.currentCorpus) { - this.corpusService.checkAnnisResponse().then(() => { - this.corpusService.restoreLastCorpus().then(() => { - this.addReferences(this.corpusService.currentCorpus.citation_level_1).then(() => { - this.initPage(); - }, () => { - }); + 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 if (Object.keys(this.corpusService.currentCorpus.citations).length === 0) { - this.addReferences(this.corpusService.currentCorpus.citation_level_1).then(() => { - this.initPage(); - }, () => { - }); - } else { - this.initPage(); - } + } else { + this.initPage(cc); + } + }); } addMissingCitations(citationLabelsStart: string[], citationLabelsEnd: string[]) { @@ -86,51 +87,59 @@ export class TextRangePage { return resolve(); } const urnLastPart: string = relevantCitations.map(x => x.isNumeric ? x.value.toString() : x.label).join('.'); - const fullUrn: string = this.corpusService.currentCorpus.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) { - this.corpusService.currentCorpus.citations[citation.label] = citation; - this.currentlyAvailableCitations.push(citation.label); - } else if (relevantCitations.length === 1) { - this.corpusService.currentCorpus.citations[relevantCitations[0].label].subcitations[citation.label] = citation; - const firstLabel: string = this.corpusService.currentCorpus.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; - this.corpusService.currentCorpus.citations[rc0Label].subcitations[rc1Label].subcitations[citation.label] = citation; - const firstLabel: string = this.corpusService.currentCorpus.citations[rc0Label].label; - const secondLabel: string = this.corpusService.currentCorpus.citations[rc0Label].subcitations[rc1Label].label; - this.currentlyAvailableCitations.push(firstLabel.concat('.', secondLabel, '.', citation.label)); - } - return resolve(); + 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); }); - }, async (error: HttpErrorResponse) => { - return reject(error); }); }); } applyAutoComplete(isStart: boolean) { this.showFurtherReferences(isStart).then(() => { - const newId: string = 'input' + (this.currentInputId + 1).toString(); + const oldId: number = this.currentInputId; this.currentInputId = 0; - const newEl: HTMLInputElement = document.getElementById(newId) as HTMLInputElement; + 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; + } if (newEl) { // adjust disabled state manually because the focus won't work otherwise and the automatic check comes too late newEl.disabled = false; @@ -139,34 +148,52 @@ export class TextRangePage { }); } + 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])); + } + }); + }); + }); + } + checkTextRange(citationLabelsStart: string[], citationLabelsEnd: string[]) { return new Promise(resolve => { citationLabelsStart = citationLabelsStart.filter(x => x); citationLabelsEnd = citationLabelsEnd.filter(x => x); - if (this.corpusService.currentCorpus.citation_level_2 === CitationLevel[CitationLevel.default]) { - if (citationLabelsStart.length !== 1 || citationLabelsEnd.length !== 1) { - return resolve(false); - } - } else { - if (citationLabelsStart.length < 2 || citationLabelsEnd.length < 2) { - return resolve(false); + 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); + } } else { - if (this.corpusService.currentCorpus.citation_level_3 === CitationLevel[CitationLevel.default]) { - if (citationLabelsStart.length !== 2 || citationLabelsEnd.length !== 2) { + 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) { return resolve(false); } - } else if (citationLabelsStart.length !== 3 || citationLabelsEnd.length !== 3) { - return resolve(false); } } - } - 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); + 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); + }); }); }); } @@ -208,149 +235,152 @@ export class TextRangePage { return; } this.isTextRangeCheckRunning = true; - const citationLabelsStart: string[] = this.corpusService.currentTextRange.start; - const citationLabelsEnd: string[] = this.corpusService.currentTextRange.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; - } - const newUrnBase: string = this.corpusService.currentCorpus.source_urn + ':'; - if (this.citationValuesStart.concat(this.citationValuesEnd).some(x => isNaN(x))) { - this.corpusService.currentUrn = newUrnBase + - this.corpusService.currentTextRange.start.filter(x => x).join('.') + '-' + - this.corpusService.currentTextRange.end.filter(x => x).join('.'); - } else { - this.corpusService.currentUrn = newUrnBase + this.citationValuesStart.join('.') + '-' + this.citationValuesEnd.join('.'); - } - HelperService.mostRecentSetup = new ApplicationState({ - currentUrn: this.corpusService.currentUrn, - currentCorpus: this.corpusService.currentCorpus, - currentTextRange: this.corpusService.currentTextRange - }); - this.helperService.saveMostRecentSetup().then(() => { - this.corpusService.isTextRangeCorrect = true; - this.corpusService.getText().then(() => { - if (skipText) { - HelperService.goToExerciseParametersPage(this.navCtrl).then(); - } else if (HelperService.isVocabularyCheck) { - HelperService.goToVocabularyCheckPage(this.navCtrl).then(); + 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('.'); } else { - HelperService.goToShowTextPage(this.navCtrl).then(); + this.corpusService.currentUrn = newUrnBase + this.citationValuesStart.join('.') + '-' + + this.citationValuesEnd.join('.'); } - }, () => { + HelperService.applicationState.pipe(take(1)).subscribe((state: ApplicationState) => { + state.currentSetup.currentTextRange = tr; + state.currentSetup.currentUrn = this.corpusService.currentUrn; + state.mostRecentSetup = state.currentSetup; + this.helperService.saveApplicationState(state).then(() => { + 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(); + } + }, () => { + }); + }); + }); }); }); }); } - initPage() { - if (this.corpusService.currentCorpus.citation_level_2 === CitationLevel[CitationLevel.default]) { - const firstKey: string = Object.keys(this.corpusService.currentCorpus.citations)[0]; - const randomLabel: string = this.corpusService.currentCorpus.citations[firstKey].label; - this.corpusService.currentTextRange.start[0] = this.corpusService.currentTextRange.end[0] = randomLabel; - } - } - - 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])) { - return true; + 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; + }); } - return !baseCits[ctrPart[0]].subcitations.hasOwnProperty(ctrPart[1]); } public mapCitationLabelsToValues(label: string, index: number, citationLabels: string[], valueList: number[]) { return new Promise((resolve, reject) => { - if (index === 0 && this.corpusService.currentCorpus.citations[label]) { - valueList.push(this.corpusService.currentCorpus.citations[label].value); - return resolve(); - } else if (index === 1) { - if (!this.corpusService.currentCorpus.citations[citationLabels[index - 1]]) { - if (!!+label) { - valueList.push(+label); - return resolve(); - } else { - return reject(); - } - } - if (Object.keys(this.corpusService.currentCorpus.citations[citationLabels[index - 1]].subcitations).length === 0) { - const relevantCitations: Citation[] = [this.corpusService.currentCorpus.citations[citationLabels[index - 1]]]; - this.addReferences(this.corpusService.currentCorpus.citation_level_2, relevantCitations).then(() => { - valueList.push(this.corpusService.currentCorpus.citations[citationLabels[index - 1]].subcitations[label].value); - return resolve(); - }, () => { - return reject(); - }); - } else { - valueList.push(this.corpusService.currentCorpus.citations[citationLabels[index - 1]].subcitations[label].value); + this.corpusService.currentCorpus.pipe(take(1)).subscribe((cc: CorpusMC) => { + if (index === 0 && cc.citations[label]) { + valueList.push(cc.citations[label].value); return resolve(); - } - } else if (index === 2) { - if (!this.corpusService.currentCorpus.citations[citationLabels[index - 2]] || - !this.corpusService.currentCorpus.citations[citationLabels[index - 2]].subcitations[citationLabels[index - 1]]) { - if (!!+label) { - valueList.push(+label); - return resolve(); + } 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(); + }); } else { - return reject(); + valueList.push(cc.citations[citationLabels[index - 1]].subcitations[label].value); + return resolve(); } - } - const citation: Citation = this.corpusService.currentCorpus.citations[citationLabels[index - 2]]; - const subCitation: Citation = citation.subcitations[citationLabels[index - 1]]; - if (Object.keys(subCitation.subcitations).length === 0) { - this.addReferences(this.corpusService.currentCorpus.citation_level_3, [citation, subCitation]).then(() => { + } 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(); + } valueList.push(subCitation.subcitations[label].value); return resolve(); - }, () => reject()); - } else { - valueList.push(subCitation.subcitations[label].value); + } + } else if (!!+label) { + valueList.push(+label); return resolve(); } - } else if (!!+label) { - valueList.push(+label); - return resolve(); - } + }); }); } resetCitations() { - switch (this.currentInputId) { - case 1: - if (this.corpusService.currentCorpus.citation_level_2 !== CitationLevel[CitationLevel.default]) { - this.corpusService.currentTextRange.start[1] = ''; - this.corpusService.currentTextRange.start[2] = ''; - } - break; - case 2: - if (this.corpusService.currentCorpus.citation_level_3 !== CitationLevel[CitationLevel.default]) { - this.corpusService.currentTextRange.start[2] = ''; - } - break; - case 4: - if (this.corpusService.currentCorpus.citation_level_2 !== CitationLevel[CitationLevel.default]) { - this.corpusService.currentTextRange.end[1] = ''; - this.corpusService.currentTextRange.end[2] = ''; - } - break; - case 5: - if (this.corpusService.currentCorpus.citation_level_3 !== CitationLevel[CitationLevel.default]) { - this.corpusService.currentTextRange.end[2] = ''; + 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; } - break; - default: - break; - } + }); + }); } resetCurrentInputId() { @@ -364,32 +394,42 @@ export class TextRangePage { } async showFurtherReferences(isStart: boolean): Promise { - const relTextRangePart: string[] = isStart ? this.corpusService.currentTextRange.start : this.corpusService.currentTextRange.end; - if (!relTextRangePart[0]) { - return; - } - this.resetCitations(); - return new Promise((resolve, reject) => { - const baseCit: Citation = this.corpusService.currentCorpus.citations[relTextRangePart[0]]; - if (baseCit && (Object.keys(baseCit.subcitations).length || - this.corpusService.currentCorpus.citation_level_2 === CitationLevel[CitationLevel.default])) { - return resolve(); - } else { - this.addReferences(this.corpusService.currentCorpus.citation_level_2, [baseCit]).then(() => { - return resolve(); - }, () => { - return resolve(); - }); - } - }).then(() => { - if ([2, 3, 5, 6].indexOf(this.currentInputId) > -1) { - const baseCit: Citation = this.corpusService.currentCorpus.citations[relTextRangePart[0]]; - const relCit: Citation = baseCit.subcitations[relTextRangePart[1]]; - const hasLvl3: boolean = this.corpusService.currentCorpus.citation_level_3 !== CitationLevel[CitationLevel.default]; - if (relTextRangePart[1] && !(relCit && Object.keys(relCit.subcitations).length) && hasLvl3) { - this.addReferences(this.corpusService.currentCorpus.citation_level_3, [baseCit, relCit]).then(); + return new Promise(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(); } - } + this.corpusService.currentCorpus.pipe(take(1)).subscribe((cc: CorpusMC) => { + new Promise(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(); + } + } + }); + }); + }); }); } } diff --git a/src/app/vocabulary-check/vocabulary-check.page.html b/src/app/vocabulary-check/vocabulary-check.page.html index 3acac3e9aa280e0b356c09ea76d9111fbccf4a3e..56ec1f215ef7e875d92d8da690f7e56fc8b54173 100644 --- a/src/app/vocabulary-check/vocabulary-check.page.html +++ b/src/app/vocabulary-check/vocabulary-check.page.html @@ -22,8 +22,18 @@ @@ -82,7 +92,7 @@ - {{ 'VOCABULARY_CHECK' | translate }} + {{ 'VOCABULARY_CHECK' | translate }} diff --git a/src/app/vocabulary-check/vocabulary-check.page.scss b/src/app/vocabulary-check/vocabulary-check.page.scss index bd20da06ec760b8a1ecb32d141938a1ccce49896..17892142ebfc8412ffde3a12855f6c60be7433cd 100644 --- a/src/app/vocabulary-check/vocabulary-check.page.scss +++ b/src/app/vocabulary-check/vocabulary-check.page.scss @@ -9,15 +9,3 @@ border-bottom-color: #333333; cursor: pointer; } - -//label > span:first-of-type { -// font-weight: bold; -// padding-right: 1em; -// word-wrap: break-spaces; -//} -// -//select { -// max-width: 95%; -// text-overflow: ellipsis; -//} - diff --git a/src/app/vocabulary-check/vocabulary-check.page.ts b/src/app/vocabulary-check/vocabulary-check.page.ts index 6b72c8da0a70aacd4d073b2ac548cda941af3900..2df447a5bf5377a9ce77c3d35457349e76d0bb00 100644 --- a/src/app/vocabulary-check/vocabulary-check.page.ts +++ b/src/app/vocabulary-check/vocabulary-check.page.ts @@ -1,5 +1,5 @@ import {NavController, ToastController} from '@ionic/angular'; -import {AfterViewInit, Component, OnInit} from '@angular/core'; +import {AfterViewInit, Component} 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'; @@ -8,20 +8,22 @@ import {TranslateService} from '@ngx-translate/core'; import {HelperService} from '../helper.service'; import {ExerciseService} from 'src/app/exercise.service'; import {CorpusService} from 'src/app/corpus.service'; +import {CorpusMC} from '../models/corpusMC'; +import {take} from 'rxjs/operators'; +import {TextRange} from '../models/textRange'; @Component({ selector: 'app-vocabulary-check', templateUrl: './vocabulary-check.page.html', styleUrls: ['./vocabulary-check.page.scss'], }) -export class VocabularyCheckPage implements AfterViewInit { +export class VocabularyCheckPage { HelperService = HelperService; invalidSentenceCountString: string; ObjectKeys = Object.keys; VocabularyCorpus = VocabularyCorpus; VocabularyCorpusTranslation = VocabularyCorpusTranslation; public adaptPassages = true; - public currentCorpusString: string; public currentRankingUnits: Sentence[][]; public invalidQueryCorpusString: string; @@ -36,34 +38,37 @@ export class VocabularyCheckPage implements AfterViewInit { this.translate.get('INVALID_QUERY_CORPUS').subscribe(value => this.invalidQueryCorpusString = value); } - async checkVocabulary() { - if (this.vocService.desiredSentenceCount < 0 || this.vocService.frequencyUpperBound < 0) { - const toast = await this.toastCtrl.create({ - message: this.invalidSentenceCountString, - duration: 3000, - position: 'top' - }); - toast.present().then(); - return; - } else if (!this.corpusService.currentCorpus || this.corpusService.currentTextRange.start.length === 0 || - this.corpusService.currentTextRange.end.length === 0 || !this.corpusService.isTextRangeCorrect) { - const toast = await this.toastCtrl.create({ - message: this.invalidQueryCorpusString, - duration: 3000, - position: 'top' + checkVocabulary() { + this.corpusService.currentCorpus.pipe(take(1)).subscribe(async (cc: CorpusMC) => { + this.corpusService.currentTextRange.pipe(take(1)).subscribe(async (tr: TextRange) => { + if (this.vocService.desiredSentenceCount < 0 || this.vocService.frequencyUpperBound < 0) { + const toast = await this.toastCtrl.create({ + message: this.invalidSentenceCountString, + duration: 3000, + position: 'top' + }); + toast.present().then(); + return; + } else if (!cc || tr.start.length === 0 || tr.end.length === 0 || !this.corpusService.isTextRangeCorrect) { + const toast = await this.toastCtrl.create({ + message: this.invalidQueryCorpusString, + duration: 3000, + position: 'top' + }); + toast.present().then(); + return; + } + this.vocService.currentSentences = []; + this.currentRankingUnits = []; + this.vocService.ranking = []; + // remove old sentence boundaries + this.corpusService.currentUrn = this.corpusService.currentUrn.split('@')[0]; + this.vocService.getVocabularyCheck(this.corpusService.currentUrn, false).then((sentences: Sentence[]) => { + this.processSentences(sentences); + this.navCtrl.navigateForward('/ranking').then(); + }, async (error: HttpErrorResponse) => { + }); }); - toast.present().then(); - return; - } - this.vocService.currentSentences = []; - this.currentRankingUnits = []; - this.vocService.ranking = []; - // remove old sentence boundaries - this.corpusService.currentUrn = this.corpusService.currentUrn.split('@')[0]; - this.vocService.getVocabularyCheck(this.corpusService.currentUrn, false).then((sentences: Sentence[]) => { - this.processSentences(sentences); - this.navCtrl.navigateForward('/ranking').then(); - }, async (error: HttpErrorResponse) => { }); } @@ -71,14 +76,8 @@ export class VocabularyCheckPage implements AfterViewInit { this.navCtrl.navigateForward('/author').then(); } - ngAfterViewInit(): void { - const timeout: number = this.corpusService.isMostRecentSetupLoaded ? 0 : 200; - // dirty hack to avoid ExpressionChangedAfterItHasBeenCheckedError - setTimeout(() => { - 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('.'); - }, timeout); + filterArray(array: string[]): string[] { + return array.filter(x => x); } processSentences(sentences: Sentence[]) { diff --git a/src/assets/config.json b/src/assets/config.json index 892df47f4870cd623970f597a67cd61ca113d232..b91a74ee7a6cc9fdf650ab0b8e52b245fa53cead 100644 --- a/src/assets/config.json +++ b/src/assets/config.json @@ -17,9 +17,9 @@ "developerMailTo": "mailto:sulzkons@hu-berlin.de", "frontendExercisePage": "exercise", "intervalCorporaUpdate": 1209600000, + "localStorageKeyApplicationState": "mc/applicationState", "localStorageKeyCorpora": "mc/corpora", "localStorageKeyH5P": "mc/h5p", - "localStorageKeyMostRecentSetup": "mc/mostRecentSetup", "localStorageKeyUpdateInfo": "mc/updateInfo", "machinaCallidaBackendUrl": "https://scm.cms.hu-berlin.de/callidus/mc_backend", "machinaCallidaConceptUrl": "https://www.projekte.hu-berlin.de/de/callidus/machina-callida", diff --git a/src/assets/i18n/de.json b/src/assets/i18n/de.json index 4575baf1c73eb2fb07de968860db753aa5f3645e..0f6e154456214a8ca9369de6bcafd95f922f2573 100644 --- a/src/assets/i18n/de.json +++ b/src/assets/i18n/de.json @@ -230,6 +230,7 @@ "MACHINA_CALLIDA_FRONTEND": "Machina Callida Frontend", "MACHINA_CALLIDA_INTRO": "Die entwickelte Software (Open Source-Projekt auf GitLab) unterstützt eine korpusbasierte Wortschatzarbeit in der Lektürephase des Lateinunterrichts. Sie bietet Zugriff auf zahlreiche bekannte und weniger bekannte lateinische Korpora, um für ausgewählte Textstellen Übungen zu generieren. Im Folgenden werden einige wesentliche Entwicklungsschritte nachgezeichnet.", "MOST_RECENT_SETUP": "Zuletzt genutzte Einstellungen", + "NO_ENTRY_FOUND": "Kein Eintrag verfügbar", "NO_EXERCISES_FOUND": "Keine Übungen gefunden", "OF": "von", "PART_OF_SPEECH_ADJECTIVE": "Adjektiv", diff --git a/src/assets/i18n/en.json b/src/assets/i18n/en.json index 409c39f19ff4db6c1d2a452abf2d7d6ddd36c380..b542828ca3d7e1a7e5f003a426ce4970d698582a 100644 --- a/src/assets/i18n/en.json +++ b/src/assets/i18n/en.json @@ -230,6 +230,7 @@ "MACHINA_CALLIDA_FRONTEND": "Machina Callida Frontend", "MACHINA_CALLIDA_INTRO": "The software (open source project, GitLab) is able to create corpus-based exercises which can be used by beginners and intermediate learners as well as by teachers of Latin. Thus, it provides access to numerous known and lesser known Latin corpora. Some essential steps of development are given below.", "MOST_RECENT_SETUP": "Most recent settings", + "NO_ENTRY_FOUND": "No entry available", "NO_EXERCISES_FOUND": "No exercises found", "OF": "of", "PART_OF_SPEECH_ADJECTIVE": "Adjective", diff --git a/src/theme/variables.scss b/src/theme/variables.scss index df8beaf5885f9540e0f4b9bfb2580c3bddca7d61..1f3425a2ed0ac04b4f124e61c50a4c673c7794b3 100644 --- a/src/theme/variables.scss +++ b/src/theme/variables.scss @@ -29,6 +29,7 @@ input[type=text] { border-radius: 10px; border: 0.5px solid darkgrey; + padding: 0.2em; } ion-back-button {