Use stimulus controller for sidebar treeviews.

This commit is contained in:
Jan Böhmer 2022-07-31 15:50:16 +02:00
parent 2d1aa829f6
commit fc90259032
6 changed files with 157 additions and 169 deletions

View file

@ -0,0 +1,63 @@
import {Controller} from "@hotwired/stimulus";
import {default as TreeController} from "./tree_controller";
import "patternfly-bootstrap-treeview/src/css/bootstrap-treeview.css"
import "patternfly-bootstrap-treeview";
export default class extends TreeController {
static targets = [ "tree", 'sourceText' ];
_storage_key;
connect() {
const default_mode = this.element.dataset.defaultMode;
this._storage_key = 'tree_' + this.element.id;
//Check if we have a saved mode
const stored_mode = localStorage.getItem(this._storage_key);
//Use stored mode if possible, otherwise use default
if(stored_mode) {
try {
this.setMode(stored_mode);
} catch (e) {
console.error(e);
//If an error happenes, use the default mode
this.setMode(default_mode);
}
} else {
this.setMode(default_mode);
}
}
setMode(mode) {
//Find the button for this mode
const modeButton = this.element.querySelector(`[data-mode="${mode}"]`);
if(!modeButton) {
throw new Error(`Could not find button for mode ${mode}`);
}
//Get the url and text from the button
const url = modeButton.dataset.url;
const text = modeButton.dataset.text;
this.sourceTextTarget.innerText = text;
this.setURL(url);
}
changeDataSource(event)
{
const mode = event.params.mode ?? event.target.dataset.mode;
const url = event.params.url ?? event.target.dataset.url;
const text = event.params.text ?? event.target.dataset.text;
this.sourceTextTarget.innerText = text;
this.setURL(url);
//Save the mode in local storage
localStorage.setItem(this._storage_key, mode);
}
}

View file

@ -6,6 +6,9 @@ import "patternfly-bootstrap-treeview";
export default class extends Controller {
static targets = [ "tree" ];
_url = null;
_data = null;
connect() {
const treeElement = this.treeTarget;
if (!treeElement) {
@ -13,9 +16,30 @@ export default class extends Controller {
return;
}
//Fetch data and initialize tree
this._getData().then(this._fillTree.bind(this));
this._url = this.element.dataset.treeUrl;
this._data = this.element.dataset.treeData;
this.reinitTree();
}
reinitTree()
{
//Fetch data and initialize tree
this._getData()
.then(this._fillTree.bind(this))
.catch((err) => {
console.error("Could not load the tree data: " + err);
});
}
setData(data) {
this._data = data;
this.reinitTree();
}
setURL(url) {
this._url = url;
this.reinitTree();
}
_fillTree(data) {
@ -65,7 +89,7 @@ export default class extends Controller {
}
searchInput(event) {
const data = event.data;
const data = event.target.value;
//Do nothing if no data was passed
const tree = this.treeTarget;
@ -73,10 +97,19 @@ export default class extends Controller {
$(tree).treeview('search', [data]);
}
_getData() {
//Use lambda function to preserve this context
return new Promise((myResolve, myReject) => {
return myResolve(this.element.dataset.treeData);
//If a url is defined, fetch the data from the url
if (this._url) {
return fetch(this._url)
.then((response) => myResolve(response.json()))
.catch((err) => myReject(err));
}
//Otherwise load the data provided via the data attribute
return myResolve(this._data);
});
}
}

View file

@ -13,7 +13,7 @@ class SidebarHelper {
console.info("Base path is " + this.BASE);
this.registerSidebarHideButton();
this.fillTrees();
//this.fillTrees();
}
registerSidebarHideButton()
@ -55,146 +55,6 @@ class SidebarHelper {
}
});
}
/**
* Fill the trees with the given data.
*/
fillTrees()
{
let categories = localStorage.getItem("tree_datasource_tree-categories");
let devices = localStorage.getItem("tree_datasource_tree-devices");
let tools = localStorage.getItem("tree_datasource_tree-tools");
if(categories == null) {
categories = "categories";
}
if(devices == null) {
devices = "devices";
}
if(tools == null) {
tools = "tools";
}
this.treeLoadDataSource("tree-categories", categories);
this.treeLoadDataSource("tree-devices", devices);
this.treeLoadDataSource("tree-tools", tools);
this.trees_filled = true;
let _this = this;
//Register tree btns to expand all, or to switch datasource.
$(".tree-btns").click(function (event) {
event.preventDefault();
$(this).parents("div.dropdown").removeClass('show');
//$(this).closest(".dropdown-menu").removeClass('show');
$(".dropdown-menu.show").removeClass("show");
let mode = $(this).data("mode");
let target = $(this).data("target");
let text = $(this).text() + " \n<span class='caret'></span>"; //Add caret or it will be removed, when written into title
if (mode==="collapse") {
// @ts-ignore
$('#' + target).treeview('collapseAll', { silent: true });
}
else if(mode==="expand") {
// @ts-ignore
$('#' + target).treeview('expandAll', { silent: true });
} else {
localStorage.setItem("tree_datasource_" + target, mode);
_this.treeLoadDataSource(target, mode);
}
return false;
});
}
/**
* Load the given url into the tree with the given id.
* @param target_id
* @param datasource
*/
treeLoadDataSource(target_id, datasource) {
let text = $(".tree-btns[data-mode='" + datasource + "']").html();
text = text + " \n<span class='caret'></span>"; //Add caret or it will be removed, when written into title
switch(datasource) {
case "categories":
this.initTree("#" + target_id, 'tree/categories');
break;
case "locations":
this.initTree("#" + target_id, 'tree/locations');
break;
case "footprints":
this.initTree("#" + target_id, 'tree/footprints');
break;
case "manufacturers":
this.initTree("#" + target_id, 'tree/manufacturers');
break;
case "suppliers":
this.initTree("#" + target_id, 'tree/suppliers');
break;
case "tools":
this.initTree("#" + target_id, 'tree/tools');
break;
case "devices":
this.initTree("#" + target_id, 'tree/devices');
break;
}
$( "#" + target_id + "-title").html(text);
}
/**
* Fill a treeview with data from the given url.
* @param tree The Jquery selector for the tree (e.g. "#tree-tools")
* @param url The url from where the data should be loaded
*/
initTree(tree, url) {
//Get primary color from css variable
const primary_color = getComputedStyle(document.documentElement).getPropertyValue('--bs-info');
//let contextmenu_handler = this.onNodeContextmenu;
$.getJSON(this.BASE + url, function (data) {
// @ts-ignore
$(tree).treeview({
data: data,
enableLinks: true,
showIcon: false,
showBorder: true,
searchResultBackColor: primary_color,
searchResultColor: '#000',
onNodeSelected: function(event, data) {
if(data.href) {
//Simulate a click so we just change the inner frame
let a = document.createElement('a');
a.setAttribute('href', data.href);
a.innerHTML = "";
$(tree).append(a);
a.click();
a.remove();
//Turbo.visit(data.href)
}
},
//onNodeContextmenu: contextmenu_handler,
expandIcon: "fas fa-plus fa-fw fa-treeview", collapseIcon: "fas fa-minus fa-fw fa-treeview"})
.on('initialized', function() {
$(this).treeview('collapseAll', { silent: true });
//Implement searching if needed.
if($(this).data('treeSearch')) {
let _this = this;
let $search = $($(this).data('treeSearch'));
$search.on( 'input', function() {
$(_this).treeview('collapseAll', { silent: true });
$(_this).treeview('search', [$search.val()]);
});
}
});
});
}
}
export default new SidebarHelper();