...
 
Commits (5)
......@@ -18,7 +18,7 @@
background-repeat: no-repeat;
background-color: transparent;
background-size: cover;
width: 100%;
width: 58%;
height: 200px;
}
......
......@@ -81,6 +81,26 @@
[typeahead]="annotation.typeahead">
</ng-select>
</div>
<div>Additional filters</div>
<hr><br>
<div class="form-group">
<input id="inputHasMedias" type="checkbox" formControlName="hasMedias">
<label for="inputHasMedias">Must have an image</label>
</div>
<div class="form-group">
<label for="inputLanguage">Language</label>
<ng-select [items]="languages"
class="form-control"
bindLabel="label"
bindValue="id"
placeholder="Select a language"
clearAllText="Clear"
formControlName="language">
</ng-select>
</div>
</form>
</div>
<div class="column sidebar-search-results padding-top" *ngIf="!isFullscreen">
......
......@@ -32,6 +32,7 @@ export class HomeComponent implements OnInit {
locations: NgOption[] = [];
schemas: NgOption[] = [];
selectedSchema: any = null;
languages: NgOption[] = [];
annotations: any = [{
id: 'http://adel.eurecom.fr/Stanford/Location',
label: 'Location',
......@@ -89,6 +90,7 @@ export class HomeComponent implements OnInit {
this.inDetailsView = val.urlAfterRedirects !== '/home';
}
});
this.selectedSchema = null;
}
ngOnInit() {
......@@ -98,7 +100,9 @@ export class HomeComponent implements OnInit {
date: new FormControl(),
who: new FormControl(),
keywords: new FormControl(),
schema: new FormControl()
schema: new FormControl(),
language: new FormControl(),
hasMedias: new FormControl()
});
this.formGroupSearch.valueChanges.debounceTime(500).subscribe(form => {
......@@ -107,6 +111,8 @@ export class HomeComponent implements OnInit {
this.search.searchParams.subjects = form.selectedSubjectCodes;
this.search.searchParams.location = form.location ? form.location.trim() : null;
this.search.searchParams.keywords = form.keywords ? form.keywords.trim() : null;
this.search.searchParams.hasMedias = form.hasMedias;
this.search.searchParams.language = form.language;
this.search.searchParams.schemaProperties = [];
// Schema properties
......@@ -130,31 +136,36 @@ export class HomeComponent implements OnInit {
// Schema
if (form.schema) {
let isNewSchema = false;
// Remove previous schema property form controls
if (this.selectedSchema) {
if (!this.selectedSchema) {
isNewSchema = true;
} else if (this.selectedSchema.id !== form.schema) {
isNewSchema = true;
this.selectedSchema.data.properties.forEach((prop: any) => {
this.formGroupSearch.removeControl('schema_property_' + prop.property_ID);
this.formGroupSearch.removeControl('schema_property_' + prop.property_ID);
});
}
// Set new active schema
this.selectedSchema = this.schemas.filter(schema => {
return schema.id === form.schema;
}).pop();
if (this.schemas.length > 0) {
this.selectedSchema = this.schemas.filter(schema => {
return schema.id === form.schema;
}).pop();
}
// Add new schema property form controls
if (this.selectedSchema) {
if (this.selectedSchema && isNewSchema) {
this.selectedSchema.data.properties.forEach((prop: any) => {
this.formGroupSearch.addControl('schema_property_' + prop.property_ID, new FormControl(''));
});
}
} else {
} else if (this.selectedSchema) {
// Remove previous schema property form controls
if (this.selectedSchema) {
this.selectedSchema.data.properties.forEach((prop: any) => {
this.formGroupSearch.removeControl('schema_property_' + prop.property_ID);
});
}
this.selectedSchema.data.properties.forEach((prop: any) => {
this.formGroupSearch.removeControl('schema_property_' + prop.property_ID);
});
this.selectedSchema = null;
}
......@@ -229,6 +240,14 @@ export class HomeComponent implements OnInit {
annotation.options.length = 0;
this.formGroupSearch.addControl('annotation_' + annotation.id, new FormControl(''));
});
// Load languages
this.languages.length = 0;
this.newsService.getLanguages().subscribe((data: any) => {
this.languages = data.results.bindings.map((b: any) => {
return { id: b.lang.value, label: b.lang.value };
});
});
}
ngOnDestroy() {
......
......@@ -64,7 +64,7 @@ export class ColorizePipe implements PipeTransform {
// console.log('"' + text.substr(adelOffset.start, adelOffset.end - adelOffset.start) + '"');
let replacement = '<a href="' + value.source + '" target="_blank"><span asrael class="colorize color-' + colorType + '">' + text.substr(adelOffset.start, adelOffset.end - adelOffset.start) + '</span></a>';
let replacement = '<a asrael href="' + value.source + '" target="_blank"><span asrael class="colorize color-' + colorType + '">' + text.substr(adelOffset.start, adelOffset.end - adelOffset.start) + '</span></a>';
text = text.substr(0, adelOffset.start) + replacement + text.substr(adelOffset.end);
this.tagsOffset += 2; // </span></a>
......
......@@ -9,7 +9,7 @@ export class UnderlinePipe implements PipeTransform {
calculateLimsiOffset(htmlText: string, start: number, end: number) {
// Limsi is based on text between <p></p> only
var pattern = /<(?:"[^"]*"['"]*|'[^']*'['"]*|[^'">])+>/g;
var pattern = /<(?:(?! ))(?:"[^"]*"['"]*|'[^']*'['"]*|[^'">])+>/g;
var match = pattern.exec(htmlText);
var totalTagsLength = 0;
var previousIndex = 0;
......@@ -26,7 +26,7 @@ export class UnderlinePipe implements PipeTransform {
if (match[0] === '</p>' && previousTag === '<p>' && match.index - previousIndex === previousTag.length) {
totalTagsLength += 1; // Empty paragraphs (<p></p>) do not have an extra space
}
if (match[0] !== '</p>' && match[0].indexOf('<span asrael') === -1 && match[0] !== '</span>' && previousTag) {
if (match[0] !== '</p>' && match[0].indexOf('<span asrael') === -1 && match[0].indexOf('<a asrael') === -1 && match[0] !== '</a>' && match[0] !== '</span>' && previousTag) {
totalTagsLength += (match.index - previousIndex) - previousTag.length;
}
......@@ -51,11 +51,14 @@ export class UnderlinePipe implements PipeTransform {
var limsiOffset = this.calculateLimsiOffset(text, source.start, source.end);
text = text.replace(source.text, `<span asrael class="highlight ` + (source.type === 'SOURCE-PRIM' ? 'primary' : 'secondary') + `"` + (source.value ? ` title="${tooltip}"` : ``) + `>` + source.text + `</span>`);
/*
let replacement = `<span asrael class="highlight ` + (source.type === 'SOURCE-PRIM' ? 'primary' : 'secondary') + `"` + (source.value ? ` title="${tooltip}"` : ``) + `>` + text.substr(limsiOffset.start, limsiOffset.end - limsiOffset.start) + `</span>`;
//console.log(limsiOffset);
//console.log(text);
//console.log(text.substr(limsiOffset.start, limsiOffset.end - limsiOffset.start));
console.log(limsiOffset);
console.log(text);
console.log(text.substr(limsiOffset.start, limsiOffset.end - limsiOffset.start));
text = text.substr(0, limsiOffset.start) + replacement + text.substr(limsiOffset.end);
*/
});
}
});
......
......@@ -20,6 +20,8 @@ export interface NewsContext {
annotations?: Array<any>;
schema?: string;
schemaProperties?: Array<any>;
language?: string;
hasMedias?: boolean;
}
@Injectable()
......@@ -96,6 +98,20 @@ export class NewsService {
`));
}
getLanguages(): Observable<any> {
let client = new Client(environment.virtuosoAddress);
client.setOptions('application/json');
return Observable.fromPromise(client.query(`
${this.getPrefixes()}
SELECT DISTINCT ?lang
WHERE {
GRAPH <http://asrael.eurecom.fr/agencefrancepresse/news> { ?s a rnews:NewsItem . }
?s rnews:inLanguage ?lang .
}
GROUP BY ?lang
`));
}
getPrefixes() {
return `
PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>
......@@ -248,7 +264,7 @@ export class NewsService {
context.genres = [context.genres];
}
if (Array.isArray(context.genres) && context.genres.length > 0) {
genresFilter = 'OPTIONAL { ?s rnews:genre ?genre . } FILTER (?genre NOT IN(' + context.genres.map(uri => '<' + uri + '>').join(',') + '))';
genresFilter = 'OPTIONAL { ?s rnews:genre ?genre . } FILTER (?genre NOT IN(' + context.genres.map(genre => JSON.stringify(genre) + ' ') + '))';
}
// Date filter
......@@ -264,10 +280,15 @@ export class NewsService {
let schemaFilter = '';
if (context.schemaProperties) {
context.schemaProperties.forEach(prop => {
schemaFilter += `?s wdt:${prop.name} ${JSON.stringify(prop.value)} . `
if (prop.value.length > 0) {
schemaFilter += `?s wdt:${prop.name} ?wdt_${prop.name} . FILTER(?wdt_${prop.name} >= ${JSON.stringify(prop.value)}) `
}
})
}
// Language filter
const languageFilter = context.language ? '?s rnews:inLanguage ' + JSON.stringify(context.language) + ' .': '';
// Annotations filter
let annotationsFilter = '';
console.log('context=',context);
......@@ -292,6 +313,9 @@ export class NewsService {
}
}
// Has medias
const hasMediasFilter = context.hasMedias ? 'FILTER EXISTS { ?s rnews:associatedMedia ?associatedMedia }' : '';
// Offset/limit
let offset = 0;
let limit = 100;
......@@ -315,7 +339,9 @@ export class NewsService {
${dateFilter}
${locationFilter}
${schemaFilter}
${languageFilter}
${annotationsFilter}
${hasMediasFilter}
}
ORDER BY DESC(?dateCreated)
OFFSET ${offset}
......
......@@ -13,8 +13,9 @@ export class SearchService {
searchParams: NewsContext = {
annotations: [],
genres: [
'http://cv.iptc.org/newscodes/genre/Program',
'http://cv.iptc.org/newscodes/genre/Advisory'
'Program',
'Advisory',
'Update'
]
};
......