UNPKG

sparnatural

Version:

Visual client-side SPARQL query builder and knowledge graph exploration tool

172 lines (139 loc) 5.64 kB
import { DataFactory } from 'rdf-data-factory'; import { BgpPattern, Pattern, Triple, ValuePatternRow, ValuesPattern } from "sparqljs"; import { SelectedVal } from "../SelectedVal"; import SparqlFactory from "../../generators/sparql/SparqlFactory"; import { AbstractWidget, RDFTerm, RdfTermValue, ValueRepetition, WidgetValue } from "./AbstractWidget"; import EndClassGroup from "../builder-section/groupwrapper/criteriagroup/startendclassgroup/EndClassGroup"; import { AutocompleteDataProviderIfc, mergeDatasourceResults, NoOpAutocompleteProvider, RdfTermDatasourceItem } from "./data/DataProviders"; import Awesomplete from 'awesomplete'; import { I18n } from '../../settings/I18n'; import HTMLComponent from '../HtmlComponent'; const factory = new DataFactory(); export interface AutocompleteConfiguration { dataProvider: AutocompleteDataProviderIfc, maxItems: number } export class AutoCompleteWidget extends AbstractWidget { // The default implementation of AutocompleteConfiguration static defaultConfiguration: AutocompleteConfiguration = { dataProvider: new NoOpAutocompleteProvider(), maxItems:15 } protected configuration: AutocompleteConfiguration; constructor( parentComponent: HTMLComponent, configuration: AutocompleteConfiguration, startClassValue: SelectedVal, objectPropVal: SelectedVal, endClassValue: SelectedVal ) { super( "autocomplete-widget", parentComponent, null, startClassValue, objectPropVal, endClassValue, ValueRepetition.MULTIPLE ); this.configuration = configuration; } render() { super.render(); let inputHtml = $(`<input class="awesomplete"/>`); this.html.append(inputHtml); let errorHtml = $(`<div class="no-items" style="display: none; font-style:italic;"> ${I18n.labels.ListWidgetNoItem} </div>`); // $( "#foo" )[ 0 ] is pulling the DOM element from the JQuery object // see https://learn.jquery.com/using-jquery-core/faq/how-do-i-pull-a-native-dom-element-from-a-jquery-object/ const queryInput:HTMLElement = inputHtml[0]; const awesomplete = new Awesomplete(queryInput, { filter: () => { // We will provide a list that is already filtered ... return true; }, sort: false, // ... and sorted. minChars: 3, maxItems: this.configuration.maxItems, list: [] }); // the callback called when proposals have been fetched, to populate the suggestion list let callback = (items:RdfTermDatasourceItem[]) => { // find distinct values of the 'group' binding const groups = [...new Set(items.map(item => item.group))]; let list = new Array<{label:String, value:String}>(); if(groups.length == 1 && groups[0] == undefined) { // no groups defined at all items.forEach(item => { // Awesomplete list will contain the label as 'label', and the RDFTerm JSON serialization as 'value' list.push({ label: item.label, value: JSON.stringify(item.term) }); }); } else { // we have some groups, merge let mergedResult = mergeDatasourceResults(items); mergedResult.forEach(item => { list.push({ label: (item.group)?"<span title='"+item.group+"'>"+item.label+"</span>":item.label, value: JSON.stringify(item.term) }); }); } // toggle spinner if(list.length == 0) { this.toggleSpinner(I18n.labels.AutocompleteSpinner_NoResults); } else { this.toggleSpinner('') } // build final list awesomplete.list = list; awesomplete.evaluate(); } let errorCallback = (payload:any) => { this.toggleSpinner(I18n.labels.AutocompleteSpinner_NoResults); } // when user selects a value from the autocompletion list... queryInput.addEventListener("awesomplete-selectcomplete", (event:Event) => { // fetch the autocomplete event payload, which is the JSON serialization of the RDFTerm let awesompleteEvent:{label:string, value:string} = (event as unknown as {text:{label:string, value:string}}).text; let autocompleteValue= new RdfTermValue({ label: awesompleteEvent.label, // parse back the RDFTerm as an object rdfTerm: (JSON.parse(awesompleteEvent.value) as RDFTerm), }); // set the value on the criteria inputHtml.val(autocompleteValue.value.label); this.triggerRenderWidgetVal(autocompleteValue); }); // add the behavior on the input HTML element to fetch the autocompletion value var autocompleteTimer = 0; queryInput.addEventListener("input", (event:Event) => { const phrase = (event.target as HTMLInputElement)?.value; // Process inputText as you want, e.g. make an API request. if(phrase.length >= 3) { // cancel the previously-set timer if (autocompleteTimer) { window.clearTimeout(autocompleteTimer); } autocompleteTimer = window.setTimeout(() => { this.toggleSpinner(I18n.labels.AutocompleteSpinner_Searching) this.configuration.dataProvider.getAutocompleteSuggestions( this.startClassVal.type, this.objectPropVal.type, this.endClassVal.type, phrase, callback, errorCallback ); }, 350 ); } }); return this; } parseInput(input: RdfTermValue["value"]): RdfTermValue {return new RdfTermValue(input)} }