UNPKG

sparnatural

Version:

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

346 lines (299 loc) 10.5 kB
import { BgpPattern, Pattern, Triple, ValuesPattern } from "sparqljs"; import UiuxConfig from "../../IconsConstants"; import { SelectedVal } from "../../SelectedVal"; import { AbstractWidget, RDFTerm, RdfTermValue, ValueRepetition, WidgetValue } from "../AbstractWidget"; import "jstree" import ISettings from "../../../../sparnatural/settings/ISettings"; import { ValuePatternRow } from "sparqljs"; import EndClassGroup from "../../builder-section/groupwrapper/criteriagroup/startendclassgroup/EndClassGroup"; import SparqlFactory from "../../../generators/sparql/SparqlFactory"; import { DataFactory } from 'rdf-data-factory'; import { I18n } from "../../../settings/I18n"; import { NoOpTreeDataProvider, RdfTermTreeDatasourceItem, TreeDataProviderIfc } from "../data/DataProviders"; import HTMLComponent from "../../HtmlComponent"; const factory = new DataFactory(); require("jstree/dist/themes/default/style.min.css"); export interface TreeConfiguration { dataProvider: TreeDataProviderIfc, maxSelectedItems: number } export class TreeWidget extends AbstractWidget { // The default implementation of TreeConfiguration static defaultConfiguration: TreeConfiguration = { dataProvider: new NoOpTreeDataProvider(), maxSelectedItems: 3 } configuration:TreeConfiguration; IdCriteriaGroupe: any; jsTree: any; value: RdfTermValue; // html content button: any; hiddenInput: any; startClassVal: SelectedVal; objectPropVal: SelectedVal; endClassVal: SelectedVal; displayLayer: JQuery<HTMLElement> constructor( parentComponent: HTMLComponent, configuration:TreeConfiguration, startClassVal: SelectedVal, objectPropVal: SelectedVal, endClassVal: SelectedVal ) { super( "tree-widget", parentComponent, null, startClassVal, objectPropVal, endClassVal, ValueRepetition.MULTIPLE ); this.configuration = configuration; this.IdCriteriaGroupe = "id"; this.startClassVal = startClassVal; this.endClassVal = endClassVal; this.objectPropVal = objectPropVal; } render() { super.render(); this.button = $( '<a id="ecgrw-' + this.IdCriteriaGroupe + '-input" class="treeBtnDisplay">' + UiuxConfig.ICON_TREE + "</a>" ); this.hiddenInput = $( '<input id="ecgrw-' + this.IdCriteriaGroupe + '-input-value" type="hidden"/>' ); this.displayLayer = $( '<div id="ecgrw-' + this.IdCriteriaGroupe + `-displayLayer" class="treeLayer"><div class="treeClose">${UiuxConfig.ICON_REG_XMARK}</div><div class="treeNotice"></div><div class="treeDisplay" id="ecgrw-` + this.IdCriteriaGroupe + '-display"></div><div class="treeActions"><a class="treeCancel">' + I18n.labels.TreeWidgetDelete + '</a><a class="treeSubmit">' + I18n.labels.TreeWidgetSelect + "</a></div></div>" ); this.html .append(this.button) .append(this.hiddenInput) .append(this.displayLayer); //render this element var startClassGroup_value = this.startClassVal.type; var endClassGroup_value = this.endClassVal.type; var ObjectPropertyGroup_value = this.objectPropVal.type; var self = this; let dataProvider = this.configuration.dataProvider; var options = { core: { multiple: true, data: function ( node: { id: string }, callback: { call: (arg0: any, arg1: { id: any; text: any }[]) => void; } ) { let nodeCallback:(items:RdfTermTreeDatasourceItem[]) => void = function( items:RdfTermTreeDatasourceItem[] ) { var result = []; for (var i = 0; i < items.length; i++) { var text = items[i].label; // shorten the label if too long to avoid tree goind far right if(text.length > 90) { text = text.substring(0,90)+" (...)"; } var aNode: { id: string; text: string; children?: boolean; state?: { disabled: boolean }; parent?: any; } = { id: items[i].term.value, text: text, }; if (items[i].hasChildren) { aNode.children = true; } if (items[i].disabled) { aNode.state = { disabled: true, // node disabled }; } aNode.parent = node.id; result.push(aNode); } callback.call(this, result); if (node.id === "#") { self.onTreeDataLoaded(result); } } // TODO : this is not working for now let errorCallback = (payload:any) => { console.error(payload) } if(node.id === "#") { dataProvider.getRoots( startClassGroup_value, ObjectPropertyGroup_value, endClassGroup_value, nodeCallback, errorCallback ); } else { dataProvider.getChildren( node.id, startClassGroup_value, ObjectPropertyGroup_value, endClassGroup_value, nodeCallback, errorCallback ); } }, themes: { icons: false, }, }, checkbox: { keep_selected_style: false, three_state: false, cascade: "down+undetermined", cascade_to_disabled: true, }, plugins: ["changed", "wholerow", "checkbox"], }; // this.jsTree = $("#ecgrw-" + id_inputs + "-display").jstree(options); this.jsTree = this.displayLayer.find("#ecgrw-"+this.IdCriteriaGroupe+"-display").jstree(options); this.button.on("click", { arg1: this }, this.onClickDisplay); //disable/enable on max selction this.jsTree.on("changed.jstree", { arg1: this }, this.onChangedJstree); this.jsTree.on("after_open.jstree", { arg1: this }, this.onChangedJstree); this.displayLayer .find(".treeSubmit") .on("click", { arg1: this }, this.onClickSelect); this.displayLayer .find(".treeCancel") .on("click", { arg1: this }, this.onClickCancel); this.displayLayer .find(".treeClose") .on("click", { arg1: this }, this.onClickClose); this.displayLayer.hide(); return this; } onTreeDataLoaded = function onTreeDataLoaded(result: string | any[]) { if (result.length == 0) { $("#ecgrw-" + this.IdCriteriaGroupe + "-displayLayer .treeNotice") .text(I18n.labels.TreeWidgetNoData) .show(); } else { $("#ecgrw-" + this.IdCriteriaGroupe + "-displayLayer .treeNotice").hide(); } }; //limit to 3 selction onChangedJstree = function (e: { data: { arg1: any } }, data: any) { let this_:TreeWidget = e.data.arg1; var items = $(this_.jsTree).find("li.jstree-node"); var selecteds = this_.jsTree.jstree().get_top_checked(); for (var i = 0; i < items.length; i++) { var id = $(items[i]).attr("id"); if (selecteds.indexOf(id) > -1) { $(items[i]).addClass("tree-item-selected"); } else { $(items[i]).removeClass("tree-item-selected"); } if ($(items[i]).parents(".tree-item-selected").length > 0) { var node = this_.jsTree.jstree(true).get_node(id); if (!this_.jsTree.jstree(true).is_disabled(node)) { $(items[i]).addClass("is-reactivable"); this_.jsTree.jstree(true).disable_checkbox(node); this_.jsTree.jstree(true).disable_node(node); } } else { if ($(items[i]).hasClass("is-reactivable")) { $(items[i]).addClass("red"); this_.jsTree.jstree("enable_checkbox", id); this_.jsTree.jstree(true).enable_node(id); } } } if (this_.jsTree.jstree().get_top_checked().length >= this_.configuration.maxSelectedItems) { for (var i = 0; i < items.length; i++) { var id = $(items[i]).attr("id"); if (selecteds.indexOf(id) == -1) { var node = this_.jsTree.jstree(true).get_node(id); if (!this_.jsTree.jstree(true).is_disabled(node)) { $(items[i]).addClass("is-reactivable"); this_.jsTree.jstree(true).disable_checkbox(node); this_.jsTree.jstree(true).disable_node(node); } } } this_.jsTree.addClass("max-selected"); } else { if (this_.jsTree.hasClass("max-selected")) { var items = $(this_.jsTree).find("li.jstree-node"); for (var i = 0; i < items.length; i++) { var id = $(items[i]).attr("id"); if (selecteds.indexOf(id) == -1) { if ($(items[i]).hasClass("is-reactivable")) { $(items[i]).addClass("red"); if ($(items[i]).parents(".tree-item-selected").length == 0) { this_.jsTree.jstree("enable_checkbox", id); this_.jsTree.jstree(true).enable_node(id); } } } } this_.jsTree.removeClass("max-selected"); } } }; onClickDisplay = function (e: any) { let this_:TreeWidget = e.data.arg1; this_.displayLayer.show(); }; onClickCancel = function (e: any) { let this_:TreeWidget = e.data.arg1; this_.displayLayer.hide(); }; onClickSelect = function (e: any) { let this_:TreeWidget = e.data.arg1; const values = this_.getValue() this_.displayLayer?.hide(); this_.triggerRenderWidgetVal(values) }; onClickClose = function (e: any) { let this_:TreeWidget = e.data.arg1; this_.displayLayer?.hide(); $(this_.parentComponent).trigger("change"); }; getValue = function ():Array<RdfTermValue> { var checked = this.jsTree.jstree().get_top_checked(true); // rebuild a clean data structure var values = []; for (var node in checked) { const val = new RdfTermValue({ // TODO : find a wat to retrieve the itemLabel label: checked[node].original.text, rdfTerm: { type: "uri", value: checked[node].id } }); values.push(val); } return values; }; parseInput(input: RdfTermValue["value"]): RdfTermValue { return new RdfTermValue(input); } }