UNPKG

sparnatural

Version:

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

475 lines (474 loc) 23.8 kB
import { HTMLComponent } from "../../../../HtmlComponent"; import tippy from "tippy.js"; import { TOOLTIP_CONFIG } from "../../../../../settings/defaultSettings"; /** * Builds a selector for a class based on provided domainId, by reading the * configuration. If the given domainId is null, this means we populate the first * class selection (starting point) so reads all classes that are domains of any property. * **/ export class HierarchicalClassSelectBuilder extends HTMLComponent { constructor(ParentComponent, specProvider, hierarchyData, defaultValue) { super("HierarchicalClassSelectBuilder", ParentComponent, null); //htmlCurentValue: JQuery<HTMLElement>; this.breadcrumItems = []; this.hierarchyData = []; this.hasIcon = false; this.defaultValue = { value: '', path: '' }; this.widgetValue = { value: '', path: '', icon: '' }; this.specProvider = specProvider; this.hierarchyData = hierarchyData; this.defaultValue = defaultValue; } render() { super.render(); return this; } moveHasAncestor(el) { el.classList.remove('active-pane'); el.classList.add('active-pane-hide-left'); if (el.getAttribute('parent') == '') { this.htmlSelectUiUxLists[0].classList.add('root-display'); } } moveHasChild(el) { el.classList.add('active-pane'); this.htmlSelectUiUxLists[0].classList.remove('root-display'); let parentItem = this.getParentLiToUl(el); let liParentLabel = parentItem.querySelector('.item-label').innerText; this.downAncestorInParentLabel(liParentLabel); //test if liparent is not on root ul let ulOfLiParent = parentItem.closest('ul'); if (ulOfLiParent.getAttribute('parent') != '') { //need to add ancestor item label to path, need to animate first acestor let liAncestor = this.getParentLiToUl(ulOfLiParent); let liAncestorLabel = liAncestor.querySelector('.item-label').innerText; this.downAncestorInBreadcrumPath(liAncestorLabel); } else { this.htmlBreadCrumParentLabel[0].classList.add('display'); } } moveHasLeaveChild(el) { el.classList.remove('active-pane'); } moveHasEnterAncestor(el) { el.classList.remove('active-pane-hide-left'); el.classList.add('active-pane'); if (el.getAttribute('parent') == '') { this.htmlSelectUiUxLists[0].classList.add('root-display'); } this.upAncestorInParentLabel(); } isFlatHierarchy() { let isFlat = true; this.hierarchyData.forEach(element => { if (element.childs.length > 0) { isFlat = false; } }); return isFlat; } withIcons() { return this.hasIcon; } getParentLiToUl(el) { let uniqPath = el.getAttribute('parent'); return this.htmlSelectUiUx[0].querySelector(`li[list-child-id="${uniqPath}"]`); } getInput() { return this.html; } downAncestorInBreadcrumPath(newAcestorLabel) { let parentList = this.htmlBreadCrumPathParents[0].querySelectorAll('span:not(.onHiddenUp)'); if (parentList.length == 2) { parentList[0].classList.add('onHiddenUp'); this.htmlBreadCrumPathHome[0].classList.add('onHiddenUp'); this.htmlBreadCrumPathParentsPrefix[0].classList.add('onHiddenUp'); } let NewAncestor = $(`<span class="ancestor-item">&nbsp;/ ${newAcestorLabel}</span>`); //this.htmlBreadCrumPathParents[0].innerHTML = '' ; this.htmlBreadCrumPathParents.append(NewAncestor); setTimeout(function () { NewAncestor[0].classList.toggle('appened'); }, 10); } /*upAncestorInBreadcrumPath() { let parentList = this.htmlBreadCrumPathParents[0].querySelectorAll('span') ; if (parentList.length == 2) { this.htmlBreadCrumPathParents[0].querySelector('span:last-of-type').classList.remove('appened') ; let htmlBreadCrumPathParents = this.htmlBreadCrumPathParents[0] ; setTimeout(function() { htmlBreadCrumPathParents.querySelector('span:last-of-type').remove() ; }, 500); return true; } }*/ downAncestorInParentLabel(newParentLabel) { let new_item = $(`<span>${newParentLabel}</span>`); if (this.htmlBreadCrumParentLabel[0].querySelector('span:last-of-type') != null) { this.htmlBreadCrumParentLabel[0].querySelector('span:last-of-type').classList.add('move-left'); this.htmlBreadCrumParentLabel[0].querySelector('span:last-of-type').classList.remove('move-to-display'); } this.htmlBreadCrumParentLabel.append(new_item); let htmlBreadCrumParentLabel = this.htmlBreadCrumParentLabel[0]; setTimeout(function () { htmlBreadCrumParentLabel.querySelector('span:last-of-type').classList.add('move-to-display'); }, 1); } upAncestorInParentLabel() { let parentList = this.htmlBreadCrumParentLabel[0].querySelectorAll('span'); if (parentList.length == 1) { let htmlBreadCrumParentLabel = this.htmlBreadCrumParentLabel[0]; setTimeout(function () { htmlBreadCrumParentLabel.querySelector('span:last-of-type').remove(); }, 500); return true; } if (this.htmlBreadCrumParentLabel[0].querySelector('span:last-of-type') != null) { this.htmlBreadCrumParentLabel[0].querySelector('span:last-of-type').classList.add('move-right'); this.htmlBreadCrumParentLabel[0].querySelector('span:last-of-type').classList.remove('move-to-display'); } let indexToDisplay = parentList.length - 2; if (indexToDisplay >= 0) { parentList[indexToDisplay].classList.remove('move-left'); parentList[indexToDisplay].classList.add('move-to-display'); this.htmlBreadCrumPathParents[0].querySelector('span:last-of-type').classList.remove('appened'); let htmlBreadCrumPathParents = this.htmlBreadCrumPathParents[0]; setTimeout(function () { htmlBreadCrumPathParents.querySelector('span:last-of-type').remove(); }, 500); let pathHiddenParentList = this.htmlBreadCrumPathParents[0].querySelectorAll('span.onHiddenUp'); if (pathHiddenParentList.length > 0) { pathHiddenParentList[(pathHiddenParentList.length - 1)].classList.remove('onHiddenUp'); } if (this.htmlBreadCrumPathParents[0].querySelectorAll('span.onHiddenUp').length == 0) { this.htmlBreadCrumPathHome[0].classList.remove('onHiddenUp'); this.htmlBreadCrumPathParentsPrefix[0].classList.remove('onHiddenUp'); } } let htmlBreadCrumParentLabel = this.htmlBreadCrumParentLabel[0]; setTimeout(function () { htmlBreadCrumParentLabel.querySelector('span:last-of-type').remove(); }, 500); } /*setCurrentContent() { let entity = this.specProvider.getEntity(this.widgetValue.value) ; let entity_icon = entity.getIcon() ; let icon = `` ; if (entity_icon != '') { icon = `<span><i class="fa ${entity_icon} fa-fw"></i></span>` ; } this.htmlCurentValue.html(`${icon} ${entity.getLabel()} `) ; this.htmlCurentValue[0].classList.add('selected') ; }*/ initSelectUiUxListsHeight() { let listToDisplay = this.htmlSelectUiUx[0].querySelector('ul[parent].active-pane'); //let allLists = this.htmlSelectUiUx[0].querySelectorAll('ul[parent]') ; let listToDisplayLiCount = this.htmlSelectUiUx[0].querySelectorAll('ul[parent].active-pane li').length; let breadcrumHeight = 55; if (listToDisplay.classList.contains('root')) { breadcrumHeight = 0; } let newHeight = 40 * listToDisplayLiCount + breadcrumHeight; if (newHeight > 400) { newHeight = 400; } this.htmlSelectUiUxLists[0].style.height = newHeight + 'px'; this.htmlSelectUiUx[0].querySelectorAll('ul[parent]').forEach((el) => el.style.height = (newHeight - breadcrumHeight) + 'px'); } initClassSelector() { /*Search class with childs*/ let li_elements = this.htmlSelectUiUx[0].querySelectorAll('li '); //let ul_elements = this.htmlSelectUiUx[0].querySelectorAll('ul') ; for (var element of li_elements) { //let class_id = element.getAttribute('value') ; let class_childs_list_id = element.getAttribute('list-child-id'); //Search in all ul if have parent attr with this class_id let hasChild = this.htmlSelectUiUx[0].querySelector('ul[parent="' + class_childs_list_id + '"]'); if (hasChild !== null) { element.classList.add("have-childs"); element.querySelector('span.item-traverse').addEventListener("click", (e) => { let class_target = e.target.closest('li').getAttribute('list-child-id'); let parent_ul_return = e.target.closest('ul').getAttribute('parent'); this.htmlSelectUiUx[0].querySelectorAll('ul[parent].active-pane').forEach(el => this.moveHasAncestor(el)); this.moveHasChild(this.htmlSelectUiUx[0].querySelector('ul[parent="' + class_target + '"]')); this.initSelectUiUxListsHeight(); this.htmlBreadCrumBack[0].setAttribute('return-target', parent_ul_return); }); } } let li_elements_disabled = this.htmlSelectUiUx[0].querySelectorAll('li.disabled'); //let ul_elements = this.htmlSelectUiUx[0].querySelectorAll('ul') ; for (var element of li_elements_disabled) { //let class_id = element.getAttribute('value') ; let class_childs_list_id = element.getAttribute('list-child-id'); //Search in all ul if have parent attr with this class_id let hasChild = this.htmlSelectUiUx[0].querySelector('ul[parent="' + class_childs_list_id + '"]'); if (hasChild !== null) { element.classList.add("have-childs"); element.querySelector('span.item-sel').addEventListener("click", (e) => { let class_target = e.target.closest('li').getAttribute('list-child-id'); let parent_ul_return = e.target.closest('ul').getAttribute('parent'); this.htmlSelectUiUx[0].querySelectorAll('ul[parent].active-pane').forEach(el => this.moveHasAncestor(el)); this.moveHasChild(this.htmlSelectUiUx[0].querySelector('ul[parent="' + class_target + '"]')); this.initSelectUiUxListsHeight(); this.htmlBreadCrumBack[0].setAttribute('return-target', parent_ul_return); }); } } //All breadcrum return action this.htmlBreadCrumBack[0].addEventListener("click", (e) => { let class_target = e.target.closest('.htmlBreadCrumBack').getAttribute('return-target'); this.htmlSelectUiUx[0].querySelectorAll('ul[parent].active-pane').forEach(el => this.moveHasLeaveChild(el)); this.moveHasEnterAncestor(this.htmlSelectUiUx[0].querySelector('ul[parent="' + class_target + '"]')); this.initSelectUiUxListsHeight(); if (class_target != '') { let new_tareget_back = this.getParentLiToUl(this.htmlSelectUiUx[0].querySelector('ul[parent="' + class_target + '"]')).closest('ul').getAttribute('parent'); this.htmlBreadCrumBack[0].setAttribute('return-target', new_tareget_back); } }); // Listen click for selectable class let li_elements_sel = this.htmlSelectUiUx[0].querySelectorAll('li.enabled .item-sel'); li_elements_sel.forEach(element => { element.addEventListener("click", (e) => { let class_id = e.target.closest('li').getAttribute('data-id'); let class_path = e.target.closest('li').getAttribute('data-parent'); let class_icon = e.target.closest('li').getAttribute('data-icon'); this.widgetValue = { value: class_id, path: class_path, icon: class_icon, }; this.html[0].dispatchEvent(new CustomEvent("widgetItemSelected", { bubbles: true, detail: this.widgetValue, })); //this.setCurrentContent() ; }); }); } initBreadCrum() { this.htmlBreadCrumBack = $('<div class="htmlBreadCrumBack"></div>'); let BackContent = $(`<span>${"<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"11\" height=\"16\" viewBox=\"0 0 11 16\" fill=\"none\"><path d=\"M9 14L3 8L9 2\" stroke=\"black\" stroke-width=\"3\" stroke-linecap=\"round\"/></svg>" /* UiuxConfig.ICON_DAG_ARROW_LEFT */}</span>`); this.htmlBreadCrumPath = $('<div class="htmlBreadCrumPath"></div>'); this.htmlBreadCrumPathHome = $('<div class="htmlBreadCrumPathHome">Tout</div>'); this.htmlBreadCrumPathParentsPrefix = $('<div class="htmlBreadCrumPathParentsPrefix">...</div>'); this.htmlBreadCrumPathParents = $('<div class="htmlBreadCrumPathParents"></div>'); this.htmlBreadCrumParentLabel = $('<div class="htmlBreadCrumParentLabel"></div>'); //First block for backward action let leftBlock = $('<div class="htmlBreadCrumLeft"></div>'); this.htmlBreadCrumBack.append(BackContent); leftBlock.append(this.htmlBreadCrumBack); this.htmlSelectUiUxBreadCrum.append(leftBlock); //Second block for navigation path display let rightBlock = $('<div class="htmlBreadCrumRight"></div>'); this.htmlBreadCrumPath.append(this.htmlBreadCrumPathHome); this.htmlBreadCrumPath.append(this.htmlBreadCrumPathParentsPrefix); this.htmlBreadCrumPath.append(this.htmlBreadCrumPathParents); rightBlock.append(this.htmlBreadCrumPath); rightBlock.append(this.htmlBreadCrumParentLabel); this.htmlSelectUiUxBreadCrum.append(rightBlock); } buildClassSelectList(arrayNode, parentClass, path, breadCrumData) { if (arrayNode.length > 0) { let Ul = $(`<ul class="` + parentClass + `" parent="${path}"></ul>`); let i = 0; let total_count = 0; let hasTraverseItem = false; let hasNoEnabledWithChilds = true; arrayNode.forEach(element => { let htmlItem = this.buildClassSelectItem(element, path); let child_path = path + '$' + element.id; Ul.append(htmlItem); i++; if (element.childs.length > 0) { let element_breadCrumData = null; hasTraverseItem = true; if (element.disabled == false) { hasNoEnabledWithChilds = false; } element_breadCrumData = JSON.parse(JSON.stringify(breadCrumData)); element_breadCrumData.parentsLabels.push(element.label); element_breadCrumData.returnPath = path; this.buildClassSelectList(element.childs, 'root-child', child_path, element_breadCrumData); htmlItem.attr('list-child-id', path + '$' + element.id); } if (element.count != undefined) { total_count += element.count; } }); let breadcrumHeight = 55; if (hasTraverseItem) { Ul[0].classList.add('hasTraverseItem'); } if (hasNoEnabledWithChilds) { Ul[0].classList.add('hasNoEnabledWithChilds'); } if (Ul[0].classList.contains('root')) { breadcrumHeight = 0; this.htmlSelectUiUxLists[0].style.height = (40 * i) + 'px'; } if (i > 10) { Ul[0].style.height = 400 + 'px'; } else { Ul[0].style.height = (40 * i + breadcrumHeight) + 'px'; } if (total_count > 0) { let li_count = Ul[0].querySelectorAll('li'); let prop_coef = 100 / total_count; li_count.forEach(element => { let count = parseInt(element.getAttribute('data-count')); let span_gradiant = element.querySelector('.item-count>span'); let span_number = element.querySelector('.item-count-number'); let pourcent = prop_coef * count; span_gradiant.style.width = pourcent + '%'; span_number.innerHTML = '<span>' + this.getCountDisplay(count); +' %</span>'; }); } else { // explicitely set te width of the gradient to 0% if there is no count // so that it is invisible let li_count = Ul[0].querySelectorAll('li'); li_count.forEach(element => { let span_gradiant = element.querySelector('.item-count>span'); span_gradiant.style.width = '0%'; }); } this.htmlSelectUiUxLists.append(Ul); } } buildClassSelectItem(element, parent) { let enabledClass = element.disabled == true ? ` disabled` : `enabled`; let icon = ``; let iconValue = ``; if (element.icon != '') { // TODO : handle iconHover icon = (element.icon.startsWith("fa")) ? `<span><i class="fa ${element.icon} fa-fw"></i></span>` : `<span><img src="${element.icon}" /></span>`; iconValue = `data-icon="${element.icon}"`; this.hasIcon = true; } let selected = this.defaultValue.value == element.id ? 'selected="selected"' : ""; //Add tooltip content if description let tooltip = element.tooltip != undefined ? `${element.tooltip}` : ""; // Prepand label if contain more than 32 caracteres if (element.label.length > 32) { let sep = tooltip != '' ? ` - ` : ""; tooltip = `${element.label}${sep}${tooltip}`; } // set tippy attribute if tooltip content if (tooltip != '') { tooltip = `data-tippy-content="${tooltip.replace(/"/g, '&quot;')}"`; } // set count attribute let count = element.count; if (element.count == undefined) { count = 0; } let count_attr = `data-count="${count}"`; let countUiUX = `<span class="item-count"><span></span></span><span class="item-count-number"></span>`; let color = element.color != undefined ? `data-color="${element.color}"` : ""; let item = $(`<li value="${element.id}" data-id="${element.id}" data-parent="` + parent + `" ${selected} ${color} ${iconValue} ${count_attr} class="${enabledClass}">${countUiUX}<span class="item-sel" ${tooltip}><span class="label-icon">${icon}</span><span class="item-label">${element.label}</span></span><span class="item-traverse">${"<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"11\" height=\"16\" viewBox=\"0 0 11 16\" fill=\"none\"><path d=\"M2 2L8 8L2 14\" stroke=\"black\" stroke-width=\"3\" stroke-linecap=\"round\"/></svg>" /* UiuxConfig.ICON_DAG_ARROW_RIGHT */}</span></li>`); return item; } displayClassSelector() { this.htmlSelectUiUx.addClass('open'); this.parentComponent.html[0].classList.add('focus'); } hideClassSelector() { this.parentComponent.html[0].classList.remove('focus'); this.htmlSelectUiUx.removeClass('open'); } setValue(selectedValue) { this.defaultValue = { value: selectedValue, path: '', }; } submitSelectedValue() { if (this.defaultValue.value != '') { //this.setCurrentContent() ; let entity = this.specProvider.getEntity(this.defaultValue.value); let entity_icon = entity.getIcon(); this.widgetValue = { value: this.defaultValue.value, path: this.defaultValue.path, icon: entity_icon, }; this.html[0].dispatchEvent(new CustomEvent("change", { bubbles: true, detail: { value: this.defaultValue.value, valuePath: this.defaultValue.path }, })); this.hideClassSelector(); /*let clickEvent = new Event( 'click', { bubbles: true } ); //let changeEvent = new Event( 'change', { bubbles: true } ); let allWithId = this.htmlSelectUiUx[0].querySelectorAll(`li[value="${this.defaultValue.value}"] .item-sel`); allWithId[0].dispatchEvent(clickEvent); //this.htmlInputValueClass[0].dispatchEvent(changeEvent);*/ } } buildClassSelectFromJson() { //init select options array let selectOptionList = []; this.htmlSelectUiUx = $(`<div class="htmlSelectUiUx"></div>`); this.htmlSelectUiUxLists = $(`<div class="htmlSelectUiUxLists root-display"></div>`); this.htmlSelectUiUxBreadCrum = $(`<div class="htmlSelectUiUxBreadCrum"></div>`); //this.htmlCurentValue = $('<span class="current">Chercher des ressources</span>') ; let initBreadcrumData = { parentsLabels: ['Tout'], returnPath: '', }; this.initBreadCrum(); this.htmlSelectUiUxLists.append(this.htmlSelectUiUxBreadCrum); this.buildClassSelectList(this.hierarchyData, 'root active-pane', '', initBreadcrumData); this.html = $('<div></div>'); //let currentWrapper = $('<div class="currentWrapper"></div>') ; //currentWrapper.append(this.htmlCurentValue) ; //this.htmlSelectUiUx.append(currentWrapper) ; this.htmlSelectUiUx.append(this.htmlSelectUiUxLists); this.html.append(this.htmlSelectUiUx); this.initClassSelector(); if (this.isFlatHierarchy()) { this.htmlSelectUiUx[0].classList.add('isFlat'); this.parentComponent.html[0].classList.add('selectorIsFlat'); } if (this.hasIcon) { this.htmlSelectUiUx[0].classList.add('hasIcon'); this.parentComponent.html[0].classList.add('selectorHasIcon'); } this.displayClassSelector(); tippy(this.html[0].querySelectorAll(".item-sel[data-tippy-content]"), TOOLTIP_CONFIG); this.html[0].addEventListener("widgetItemSelected", (e) => { this.html[0].dispatchEvent(new CustomEvent("change", { bubbles: true, detail: e.detail, })); this.hideClassSelector(); }); return this.html.children(); } getCountDisplay(count) { let countToDiplay = ''; switch (true) { case count >= 1000000: countToDiplay = '~' + Math.round(count / 1000000) + 'M'; break; case count >= 1000: countToDiplay = '~' + Math.round(count / 1000) + 'K'; break; default: countToDiplay = count + ''; } return countToDiplay; } } export default HierarchicalClassSelectBuilder; //# sourceMappingURL=HierarchicalClassSelectBuilder.js.map