Commit 694c687a authored by Thibault Ehrhart's avatar Thibault Ehrhart

Fix sparql queries, add annotations autocomplete, add missing files, fix bugs

parent 37883457
......@@ -417,9 +417,9 @@
"integrity": "sha1-CNQRmj1yaJsr748dMKr2yKq//XI="
},
"@ng-select/ng-select": {
"version": "0.15.1",
"resolved": "https://registry.npmjs.org/@ng-select/ng-select/-/ng-select-0.15.1.tgz",
"integrity": "sha1-AqKuUSP6cb8JzotxVP9WL03RP6c="
"version": "0.15.2",
"resolved": "https://registry.npmjs.org/@ng-select/ng-select/-/ng-select-0.15.2.tgz",
"integrity": "sha1-Sw1pzyOLfH/WDsKEHB4W0E8Wsd8="
},
"@ngtools/json-schema": {
"version": "1.1.0",
......
......@@ -73,22 +73,19 @@ export class HomeDetailsComponent implements OnInit {
getAnnotationName(annotationType: string) {
switch (annotationType) {
case 'http://adel.eurecom.fr/Stanford/PERSON': return 'Person';
case 'http://adel.eurecom.fr/Stanford/LOCATION': return 'Location';
case 'http://adel.eurecom.fr/Stanford/MISC': return 'Misc';
case 'http://adel.eurecom.fr/Stanford/ORGANIZATION': return 'Organization';
case 'http://adel.eurecom.fr/Stanford/Person': return 'Person';
case 'http://adel.eurecom.fr/Stanford/Location': return 'Location';
case 'http://adel.eurecom.fr/Stanford/Misc': return 'Misc';
case 'http://adel.eurecom.fr/Stanford/Organization': return 'Organization';
case 'http://adel.eurecom.fr/Stanford/Thing': return 'Thing';
case 'http://adel.eurecom.fr/Stanford/Event': return 'Event';
case 'http://adel.eurecom.fr/Stanford/Product': return 'Product';
}
return annotationType;
}
getAnnotationColor(annotationType: string) {
switch (annotationType) {
case 'http://adel.eurecom.fr/Stanford/PERSON': return 'person';
case 'http://adel.eurecom.fr/Stanford/LOCATION': return 'location';
case 'http://adel.eurecom.fr/Stanford/MISC': return 'misc';
case 'http://adel.eurecom.fr/Stanford/ORGANIZATION': return 'organization';
}
return 'default';
return NewsService.getAnnotationColor(annotationType);
}
}
......@@ -49,7 +49,8 @@
bindValue="id"
placeholder="Select a value"
clearAllText="Clear"
[formControlName]="'annotation_' + annotation.id">
[formControlName]="'annotation_' + annotation.id"
[typeahead]="annotation.typeahead">
</ng-select>
</div>
</form>
......
import { Component, ViewChild, ElementRef, OnInit } from '@angular/core';
import { Component, ViewChild, ElementRef, OnInit, ChangeDetectionStrategy, ChangeDetectorRef } from '@angular/core';
import { ActivatedRoute, Router, NavigationEnd } from '@angular/router';
import { finalize } from 'rxjs/operators';
import { FormGroup, FormBuilder, FormControl } from '@angular/forms';
......@@ -6,6 +6,8 @@ import { NewsService, NewsContext } from '../../services/news/news.service';
import { SearchService } from '../../services/search/search.service';
import { NgOption } from '@ng-select/ng-select';
import 'rxjs/add/operator/debounceTime';
import { distinctUntilChanged, debounceTime, switchMap, tap } from 'rxjs/operators'
import { Subject } from 'rxjs';
import * as i18nIsoCountries from 'i18n-iso-countries'
......@@ -29,25 +31,29 @@ export class HomeComponent implements OnInit {
subjectCodes: NgOption[] = [];
locations: NgOption[] = [];
annotations: any = [{
id: 'http://adel.eurecom.fr/Stanford/LOCATION',
id: 'http://adel.eurecom.fr/Stanford/Location',
label: 'Location',
selected: null,
options: []
options: [],
typeahead: new Subject<string>()
}, {
id: 'http://adel.eurecom.fr/Stanford/ORGANIZATION',
id: 'http://adel.eurecom.fr/Stanford/Organization',
label: 'Organization',
selected: null,
options: []
options: [],
typeahead: new Subject<string>()
}, {
id: 'http://adel.eurecom.fr/Stanford/PERSON',
id: 'http://adel.eurecom.fr/Stanford/Person',
label: 'Person',
selected: null,
options: []
options: [],
typeahead: new Subject<string>()
}, {
id: 'http://adel.eurecom.fr/Stanford/MISC',
id: 'http://adel.eurecom.fr/Stanford/Misc',
label: 'Misc',
selected: null,
options: []
options: [],
typeahead: new Subject<string>()
}];
constructor(
......@@ -55,7 +61,8 @@ export class HomeComponent implements OnInit {
private route: ActivatedRoute,
private formBuilder: FormBuilder,
private router: Router,
private search: SearchService
private search: SearchService,
private cd: ChangeDetectorRef
) {
router.events.subscribe((val) => {
if (val instanceof NavigationEnd) {
......@@ -90,6 +97,23 @@ export class HomeComponent implements OnInit {
this.doSearch();
});
this.annotations.forEach((annotation: any) => {
annotation.typeahead.pipe(
tap(() => annotation.loading = true),
distinctUntilChanged(),
debounceTime(200),
switchMap((term: string) => this.newsService.getAnnotations(annotation.id, term))
).subscribe((data: any) => {
annotation.options = data.results.bindings.map((b: any) => {
return { id: b.identRef.value, label: b.anchorOf.value };
});
annotation.loading = false;
this.cd.markForCheck();
}, () => {
annotation.options = [];
});
});
// Load news from URL ID
this.sub = this.route.params.subscribe(params => {
let id = params['id'];
......@@ -127,14 +151,6 @@ export class HomeComponent implements OnInit {
this.annotations.forEach((annotation: any) => {
annotation.options.length = 0;
this.formGroupSearch.addControl('annotation_' + annotation.id, new FormControl(''));
this.newsService.getAnnotations().subscribe((data: any) => {
annotation.options = data.results.bindings.filter((b: any) => {
return b.classRef.value === annotation.id;
}).map((b: any) => {
return { id: b.identRef.value, label: b.anchorOf.value };
});
});
});
}
......
import { PipeTransform, Pipe } from '@angular/core';
import { DomSanitizer, SafeHtml } from '@angular/platform-browser'
import { NewsService } from '../../services/news/news.service';
@Pipe({ name: 'colorize' })
export class ColorizePipe implements PipeTransform {
constructor(public sanitizer: DomSanitizer) {
}
transform(text: string, annotations: any): SafeHtml {
if (annotations.length > 0) {
var indexOffset = 0;
var strippedText = String(text).replace(/<[^>]+>/gm, '');
// Create a flat array of annotations
var flatAnnotations:Array<any> = [];
annotations.forEach((annotation: any) => {
annotation.values.forEach((value: any) => {
flatAnnotations.push(value);
});
});
// Sort annotations by start index
flatAnnotations = flatAnnotations.sort((a: any, b: any) => {
if (a.start === b.start) return 0;
return a.start > b.start ? 1 : -1;
});
flatAnnotations.forEach((value: any) => {
var colorType = NewsService.getAnnotationColor(value.type);
var replacement = '<span class="colorize color-' + colorType + '">' + strippedText.substr(value.start + indexOffset, value.end - value.start) + '</span>';
strippedText = strippedText.substr(0, value.start + indexOffset) + replacement + strippedText.substr(value.end + indexOffset);
indexOffset += replacement.length - strippedText.substr(value.start + indexOffset, value.end - value.start).length;
});
return strippedText;
} else {
return text;
}
}
}
import { PipeTransform, Pipe } from '@angular/core';
import { DomSanitizer, SafeHtml } from '@angular/platform-browser'
@Pipe({ name: 'underline' })
export class UnderlinePipe implements PipeTransform {
constructor(public sanitizer: DomSanitizer) {
}
transform(text: string, searchArray: any): SafeHtml {
if (searchArray && text) {
searchArray.forEach((search: string) => {
let pattern = search.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, '\\$&');
const regex = new RegExp(pattern, 'gi');
text = text.replace(regex, (match) => `<span class="underline">${match}</span>`);
});
return text;
} else {
return text;
}
}
}
......@@ -24,10 +24,10 @@ export class NewsService {
constructor(private http: HttpClient) {}
getAnnotations(): Observable<any> {
getAnnotations(classRef: string = null, term: string = null): Observable<any> {
let client = new Client(environment.virtuosoAddress);
client.setOptions('application/json');
return Observable.fromPromise(client.query(`
let query = `
${this.getPrefixes()}
SELECT DISTINCT ?anchorOf ?classRef ?identRef
WHERE {
......@@ -36,8 +36,17 @@ export class NewsService {
?s nif:anchorOf ?anchorOf .
?s itsrdf:taClassRef ?classRef .
?s itsrdf:taIdentRef ?identRef .
`
+ (term ? `FILTER (CONTAINS(LCASE(?anchorOf), LCASE(${JSON.stringify(term)})))` : ``)
+ (classRef ? `FILTER (?classRef = <${classRef}>)` : ``)
+ `
}
`));
LIMIT 20
`;
console.debug(query);
return Observable.fromPromise(client.query(query));
}
getLocations(): Observable<any> {
......@@ -66,7 +75,7 @@ export class NewsService {
{
SELECT DISTINCT ?genre WHERE {
GRAPH <http://asrael.eurecom.fr/agencefrancepresse/news> { ?s a rnews:NewsItem . }
?s rnews:genre ?genre .
?s dc:subject ?genre .
}
}
{
......@@ -109,7 +118,7 @@ export class NewsService {
OPTIONAL {
?s rnews:description ?description .
}
OPTIONAL { ?s rnews:genre ?genre . }
OPTIONAL { ?s dc:subject ?genre . }
OPTIONAL { ?s rnews:headline ?headline . }
OPTIONAL { ?s rnews:identifier ?identifier . }
OPTIONAL { ?s rnews:inLanguage ?language . }
......@@ -210,7 +219,7 @@ export class NewsService {
console.log('context=',context);
if (context.annotations) {
annotationsFilter += `
?s asrael:context ?context .
OPTIONAL { ?s asrael:context ?context . }
`;
let i = 0;
for (let k in context.annotations) {
......@@ -247,7 +256,7 @@ export class NewsService {
${keywordsFilter}
FILTER (LANG(?description) = "" || LANG(?description = "en"))
}
OPTIONAL { ?s rnews:genre ?genre . }
OPTIONAL { ?s dc:subject ?genre . }
OPTIONAL { ?s rnews:headline ?headline . }
OPTIONAL { ?s rnews:identifier ?identifier . }
OPTIONAL { ?s rnews:inLanguage ?language . }
......@@ -279,4 +288,17 @@ export class NewsService {
return this.http.get('assets/' + identifier.replace(/:/g, '_') + '.json');
}
static getAnnotationColor(annotationType: string) {
switch (annotationType) {
case 'http://adel.eurecom.fr/Stanford/Person': return 'person';
case 'http://adel.eurecom.fr/Stanford/Location': return 'location';
case 'http://adel.eurecom.fr/Stanford/Misc': return 'misc';
case 'http://adel.eurecom.fr/Stanford/Organization': return 'organization';
case 'http://adel.eurecom.fr/Stanford/Thing': return 'thing';
case 'http://adel.eurecom.fr/Stanford/Event': return 'event';
case 'http://adel.eurecom.fr/Stanford/Product': return 'product';
}
return 'default';
}
}
......@@ -249,15 +249,24 @@ form {
.colorize {
&.color-person {
color: #c0504d;
color: #ff225a;
}
&.color-misc {
color: #9bbb59;
color: #6713e8;
}
&.color-location {
color: #4f81bd;
color: #22a6ff;
}
&.color-organization {
color: #f79646;
color: #13e864;
}
&.color-thing {
color: #D820e8;
}
&.color-event {
color: #ff8c22;
}
&.color-product {
color: #ffcc2e;
}
}
Markdown is supported
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