Commit bd41f20c authored by Konstantin Schulz's avatar Konstantin Schulz
Browse files

exercises now support multiple search values for each phenomenon

parent 476e4ef5
{
"name": "mcClient",
"version": "0.0.1",
"version": "0.1.5",
"author": "Ionic Framework",
"homepage": "http://ionicframework.com/",
"private": true,
......
......@@ -13,7 +13,7 @@
"localStorageKeyUpdateInfo": "mc/updateInfo",
"machinaCallidaBackendUrl": "https://scm.cms.hu-berlin.de/callidus/mc-backend",
"machinaCallidaFrontendUrl": "https://scm.cms.hu-berlin.de/callidus/mc-frontend",
"maxTextLength": 2000,
"maxTextLength": 0,
"perseidsCTSapiBaseUrl": "https://cts.perseids.org/api/cts?request=",
"perseidsCTSapiGetCapabilities": "GetCapabilities",
"perseidsCTSapiGetValidReff": "GetValidReff",
......
......@@ -2,7 +2,7 @@ import {DependencyValue, PartOfSpeechValue, Phenomenon} from "./enum";
export class QueryMC {
public phenomenon: Phenomenon;
public value: DependencyValue | PartOfSpeechValue | string;
public values: DependencyValue[] | PartOfSpeechValue[] | string[];
constructor(init?:Partial<QueryMC>) {
Object.assign(this, init);
}
......
......@@ -6,7 +6,6 @@ import {ExerciseProvider} from "../../providers/exercise/exercise";
import {TranslateService} from "@ngx-translate/core";
import {FeedbackPage} from "../feedback/feedback";
import {CorpusProvider} from "../../providers/corpus/corpus";
import {ExerciseType, ExerciseTypeTranslation} from "../../models/enum";
@Component({
selector: 'page-home',
......@@ -29,7 +28,6 @@ export class HomePage {
}
async test() {
let a = ExerciseTypeTranslation["cloze"];
let g = 0;
}
}
......@@ -44,7 +44,7 @@ export class PreviewPage {
private getExerciseData() {
let formData = new FormData();
let search_values: string[] = this.exerciseProvider.exercise.queryItems.map(query => query.phenomenon + "=" + query.value);
let search_values: string[] = this.exerciseProvider.exercise.queryItems.map(query => query.phenomenon + "=" + query.values.join("|"));
// TODO: change the corpus title to something meaningful, e.g. concatenate user ID and wanted exercise title
formData.append("title", this.exerciseProvider.createGuid());
formData.append("text", this.corpusProvider.currentText);
......
......@@ -53,7 +53,7 @@
<ion-col><h3>{{ 'DEPENDENT_WORD' | translate }}</h3></ion-col>
</ion-row>
<ion-row>
<ion-col *ngFor="let query of exerciseProvider.exercise.queryItems">
<ion-col *ngFor="let query of exerciseProvider.exercise.queryItems; let i = index">
<ion-grid>
<ion-row>
<ion-col>
......@@ -69,14 +69,22 @@
<ion-row>
<ion-col>
<ion-label>{{ 'QUERY_VALUE' | translate }}</ion-label>
<ion-select *ngIf="query.phenomenon !== Phenomenon.lemma; else lemma"
[(ngModel)]="query.value" name="queryValue">
<ion-select *ngIf="exerciseProvider.exercise.type === ExerciseType.cloze; else matching"
[(ngModel)]="query.values" name="queryValue" multiple="true">
<ion-option *ngFor="let key of getSortedQueryValues(query)" [value]=key>{{
exerciseProvider.phenomenonMap[query.phenomenon][0][key] }}
exerciseProvider.phenomenonMap[query.phenomenon][0][key] + " (" +
exerciseProvider.phenomenonMap[query.phenomenon][2][key]
+ ")" }}
</ion-option>
</ion-select>
<ng-template #lemma>
<ion-input [(ngModel)]="query.value" placeholder="Lemma"></ion-input>
<ng-template #matching>
<ion-select [(ngModel)]="query.values[0]" name="queryValue" multiple="false">
<ion-option *ngFor="let key of getSortedQueryValues(query)" [value]=key>{{
exerciseProvider.phenomenonMap[query.phenomenon][0][key] + " (" +
exerciseProvider.phenomenonMap[query.phenomenon][2][key]
+ ")" }}
</ion-option>
</ion-select>
</ng-template>
</ion-col>
</ion-row>
......
......@@ -2,6 +2,7 @@ import {Component} from '@angular/core';
import {IonicPage, NavController, NavParams, ToastController} from 'ionic-angular';
import {CorpusProvider} from "../../providers/corpus/corpus";
import {
DependencyValue,
ExerciseType, ExerciseTypeTranslation, InstructionsTranslation, PartOfSpeechValue,
Phenomenon,
PhenomenonTranslation
......@@ -12,6 +13,9 @@ import {TranslateService} from "@ngx-translate/core";
import {FeedbackPage} from "../feedback/feedback";
import {HelperProvider} from "../../providers/helper/helper";
import {QueryMC} from "../../models/queryMC";
import {AnnisResponse} from "../../models/annisResponse";
import {NodeMC} from "../../models/nodeMC";
import {LinkMC} from "../../models/linkMC";
/**
* Generated class for the ShowTextPage page.
......@@ -35,14 +39,16 @@ export class ShowTextPage {
public ObjectKeys = Object.keys;
public FeedbackPage = FeedbackPage;
public emptyQueryValueString: string;
public queryValues: { [index: number]: string | string[] };
constructor(public navCtrl: NavController, public navParams: NavParams,
public corpusProvider: CorpusProvider,
public exerciseProvider: ExerciseProvider,
public toastCtrl: ToastController,
public translateService: TranslateService) {
this.corpusProvider.getCTStextPassage(this.corpusProvider.currentUrn).subscribe((data: object) => {
this.corpusProvider.currentText = data["text"];
this.corpusProvider.getCTStextPassage(this.corpusProvider.currentUrn).subscribe((ar: AnnisResponse) => {
this.processAnnisResponse(ar);
this.corpusProvider.currentText = ar.graph.nodes.map(x => x.annis_tok).join(" ");
});
this.translateService.get("TEXT_TOO_LONG").subscribe((value) => {
this.textTooLongString = value + HelperProvider.config["maxTextLength"];
......@@ -51,7 +57,7 @@ export class ShowTextPage {
}
generateExercise() {
if (this.corpusProvider.currentText.length > HelperProvider.config["maxTextLength"]) {
if (0 < HelperProvider.config["maxTextLength"] && HelperProvider.config["maxTextLength"] < this.corpusProvider.currentText.length) {
let toast = this.toastCtrl.create({
message: this.textTooLongString,
duration: 3000,
......@@ -59,7 +65,7 @@ export class ShowTextPage {
});
toast.present().then();
}
else if (this.exerciseProvider.exercise.queryItems[0].phenomenon === Phenomenon.lemma && !this.exerciseProvider.exercise.queryItems[0].value) {
else if (this.exerciseProvider.exercise.queryItems[0].phenomenon === Phenomenon.lemma && !this.exerciseProvider.exercise.queryItems[0].values) {
let toast = this.toastCtrl.create({
message: this.emptyQueryValueString,
duration: 3000,
......@@ -75,33 +81,53 @@ export class ShowTextPage {
getSortedQueryValues(query: QueryMC) {
let targetObject: object = this.exerciseProvider.phenomenonMap[query.phenomenon][0];
return Object.keys(targetObject).sort((a, b) => {
return Object.keys(this.exerciseProvider.phenomenonMap[query.phenomenon][2]).sort((a, b) => {
return a === b ? 0 : (targetObject[a] < targetObject[b] ? -1 : 1);
});
}
adjustQueryValue(query: QueryMC) {
if (query.phenomenon === Phenomenon.lemma) {
query.value = "";
}
else {
let availableValues = Object.keys(this.exerciseProvider.phenomenonMap[query.phenomenon][0]);
// when the phenomenon changes, choose a (almost) random value as the default
query.value = availableValues[Object.keys(availableValues)[0]];
}
let availableValues = Object.keys(this.exerciseProvider.phenomenonMap[query.phenomenon][0]);
// when the phenomenon changes, choose a (almost) random value as the default
query.values = availableValues[Object.keys(availableValues)[0]];
}
adjustTranslations() {
this.translateService.get(ExerciseTypeTranslation[this.exerciseProvider.exercise.type]).subscribe(value => this.exerciseProvider.exercise.typeTranslation = value);
this.translateService.get(InstructionsTranslation[this.exerciseProvider.exercise.type]).subscribe(value => this.exerciseProvider.exercise.instructionsTranslation = value);
if (this.exerciseProvider.exercise.type === ExerciseType.matching) {
this.exerciseProvider.exercise.queryItems.push(new QueryMC({
this.exerciseProvider.exercise.queryItems = [new QueryMC({
phenomenon: Phenomenon.partOfSpeech,
value: PartOfSpeechValue.adjective,
}));
values: [PartOfSpeechValue.adjective],
}), new QueryMC({
phenomenon: Phenomenon.partOfSpeech,
values: [PartOfSpeechValue.adjective],
})];
}
else if (this.exerciseProvider.exercise.queryItems.length > 1) {
this.exerciseProvider.exercise.queryItems.splice(1, 1);
}
}
processAnnisResponse(ar: AnnisResponse) {
Object.keys(this.exerciseProvider.phenomenonMap).forEach(key => this.exerciseProvider.phenomenonMap[key][2] = {});
this.exerciseProvider.phenomenonMap[Phenomenon.lemma][0] = {};
ar.graph.nodes.forEach((node: NodeMC) => {
let existingValue = this.exerciseProvider.phenomenonMap[Phenomenon.lemma][2][node.udep_lemma];
this.exerciseProvider.phenomenonMap[Phenomenon.lemma][2][node.udep_lemma] = (existingValue ? existingValue : 0) + 1;
this.exerciseProvider.phenomenonMap[Phenomenon.lemma][0][node.udep_lemma] = node.udep_lemma;
let pos: PartOfSpeechValue = this.corpusProvider.partOfSpeechMap[node.udep_upostag];
existingValue = this.exerciseProvider.phenomenonMap[Phenomenon.partOfSpeech][2][pos];
this.exerciseProvider.phenomenonMap[Phenomenon.partOfSpeech][2][pos] = (existingValue ? existingValue : 0) + 1;
});
ar.graph.links.filter(x => x.annis_component_type === "Pointing").forEach((link: LinkMC) => {
let dep: DependencyValue = this.corpusProvider.dependencyMap[link.udep_deprel];
if (dep) {
let existingValue = this.exerciseProvider.phenomenonMap[Phenomenon.dependency][2][dep];
this.exerciseProvider.phenomenonMap[Phenomenon.dependency][2][dep] = (existingValue ? existingValue : 0) + 1;
}
});
this.exerciseProvider.annisResponse = ar;
}
}
......@@ -11,6 +11,7 @@ import {Reff} from "../../models/reff";
import {TextRange} from "../../models/textRange";
import {Citation} from "../../models/citation";
import {HelperProvider} from "../helper/helper";
import {DependencyValue, PartOfSpeechValue} from "../../models/enum";
/*
Generated class for the CorpusProvider provider.
......@@ -30,6 +31,66 @@ export class CorpusProvider {
public currentTextRange: TextRange = new TextRange({start: [0, 0, 0], end: [0, 0, 0]});
public currentLastUrnPart: string = "";
public currentCitations: Citation[] = [];
public partOfSpeechMap: { [rawValue: string]: PartOfSpeechValue } = {
"ADJ": PartOfSpeechValue.adjective,
"ADP": PartOfSpeechValue.preposition,
"ADV": PartOfSpeechValue.adverb,
"AUX": PartOfSpeechValue.auxiliary,
"CCONJ": PartOfSpeechValue.conjunction,
"DET": PartOfSpeechValue.pronoun,
"INTJ": PartOfSpeechValue.interjection,
"NOUN": PartOfSpeechValue.noun,
"NUM": PartOfSpeechValue.numeral,
"PART": PartOfSpeechValue.particle,
"PRON": PartOfSpeechValue.pronoun,
"PROPN": PartOfSpeechValue.properNoun,
"PUNCT": PartOfSpeechValue.punctuation,
"SCONJ": PartOfSpeechValue.conjunction,
"SYM": PartOfSpeechValue.symbol,
"VERB": PartOfSpeechValue.verb,
"X": PartOfSpeechValue.other
};
public dependencyMap: { [rawValue: string]: DependencyValue } = {
"acl": DependencyValue.adjectivalClause,
"advcl": DependencyValue.adverbialClauseModifier,
"advmod": DependencyValue.adverbialModifier,
"amod": DependencyValue.adjectivalModifier,
"appos": DependencyValue.appositionalModifier,
"aux": DependencyValue.auxiliary,
"aux:pass": DependencyValue.auxiliary,
"case": DependencyValue.caseMarking,
"cc": DependencyValue.coordinatingConjunction,
"ccomp": DependencyValue.clausalComplement,
"clf": DependencyValue.classifier,
"compound": DependencyValue.multiwordExpression,
"conj": DependencyValue.conjunct,
"cop": DependencyValue.copula,
"csubj": DependencyValue.subject,
"csubj:pass": DependencyValue.subject,
"det": DependencyValue.determiner,
"discourse": DependencyValue.discourseElement,
"dislocated": DependencyValue.dislocated,
"expl": DependencyValue.expletive,
"fixed": DependencyValue.multiwordExpression,
"flat": DependencyValue.multiwordExpression,
"goeswith": DependencyValue.goesWith,
"iobj": DependencyValue.object,
"list": DependencyValue.list,
"mark": DependencyValue.marker,
"nmod": DependencyValue.nominalModifier,
"nmod:poss": DependencyValue.nominalModifier,
"nummod": DependencyValue.numericModifier,
"nsubj": DependencyValue.subject,
"nsubj:pass": DependencyValue.subject,
"obj": DependencyValue.object,
"obl": DependencyValue.oblique,
"orphan": DependencyValue.orphan,
"parataxis": DependencyValue.parataxis,
"punct": DependencyValue.punctuation,
"root": DependencyValue.root,
"vocative": DependencyValue.vocative,
"xcomp": DependencyValue.clausalComplement,
};
constructor(public translate: TranslateService,
public http: HttpClient) {
......
......@@ -27,13 +27,13 @@ export class ExerciseProvider {
typeTranslation: "",
queryItems: [new QueryMC({
phenomenon: Phenomenon.partOfSpeech,
value: PartOfSpeechValue.adjective,
values: PartOfSpeechValue.adjective,
})],
feedback: new Feedback({general: "", incorrect: "", partiallyCorrect: "", correct: ""}),
instructionsTranslation: ""
});
public annisResponse: AnnisResponse;
public phenomenonMap: { [phenomenonName: string]: [{ [translationsKey: string]: string }, object] } = {};
public phenomenonMap: { [phenomenonName: string]: [{ [translationsKey: string]: string }, object, { [specificValue: string]: number }] } = {};
constructor(public http: HttpClient,
public translateService: TranslateService) {
......@@ -52,8 +52,10 @@ export class ExerciseProvider {
this.translateService.get(ExerciseTypeTranslation[ExerciseType.cloze]).subscribe(value => this.exercise.typeTranslation = value);
this.translateService.get(InstructionsTranslation[ExerciseType.cloze]).subscribe(value => this.exercise.instructionsTranslation = value);
// 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.partOfSpeech] = [{}, PartOfSpeechTranslation, {}];
this.phenomenonMap[Phenomenon.dependency] = [{}, DependencyTranslation, {}];
this.phenomenonMap[Phenomenon.lemma] = [{}, null, {}];
Object.keys(Phenomenon).forEach((key) => {
if (key !== Phenomenon[Phenomenon.lemma]) {
let translationObject: object = this.phenomenonMap[key][1];
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment