Added working treeviews and buttons.

This commit is contained in:
Jan Böhmer 2019-03-25 12:44:44 +01:00
parent 82761a3454
commit afd45d464c
17 changed files with 547 additions and 74 deletions

304
assets/ts_src/ajax_ui.js Normal file
View file

@ -0,0 +1,304 @@
"use strict";
/*
*
* part-db version 0.1
* Copyright (C) 2005 Christoph Lechner
* http://www.cl-projects.de/
*
* part-db version 0.2+
* Copyright (C) 2009 K. Jacobs and others (see authors.php)
* http://code.google.com/p/part-db/
*
* Part-DB Version 0.4+
* Copyright (C) 2016 - 2019 Jan Böhmer
* https://github.com/jbtronics
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*
*/
Object.defineProperty(exports, "__esModule", { value: true });
var Cookies = require("js-cookie");
/**
* Extract the title (The name between the <title> tags) of a HTML snippet.
* @param {string} html The HTML code which should be searched.
* @returns {string} The title extracted from the html.
*/
function extractTitle(html) {
var title = "";
var regex = /<title>(.*?)<\/title>/gi;
if (regex.test(html)) {
var matches = html.match(regex);
for (var match in matches) {
title = $(matches[match]).text();
}
}
return title;
}
var AjaxUI = /** @class */ (function () {
function AjaxUI() {
this.BASE = "/";
this.trees_filled = false;
this.statePopped = false;
//Make back in the browser go back in history
window.onpopstate = this.onPopState;
$(document).ajaxError(this.onAjaxError.bind(this));
//$(document).ajaxComplete(this.onAjaxComplete.bind(this));
}
/**
* Starts the ajax ui und execute handlers registered in addStartAction().
* Should be called in a document.ready, after handlers are set.
*/
AjaxUI.prototype.start = function () {
console.info("AjaxUI started!");
this.BASE = $("body").data("base-url") + "/";
console.info("Base path is " + this.BASE);
this.registerLinks();
this.registerForm();
this.fillTrees();
};
/**
* Fill the trees with the given data.
*/
AjaxUI.prototype.fillTrees = function () {
var categories = Cookies.get("tree_datasource_tree-categories");
var devices = Cookies.get("tree_datasource_tree-devices");
var tools = Cookies.get("tree_datasource_tree-tools");
if (typeof categories == "undefined") {
categories = "categories";
}
if (typeof devices == "undefined") {
devices = "devices";
}
if (typeof tools == "undefined") {
tools = "tools";
}
this.treeLoadDataSource("tree-categories", categories);
this.treeLoadDataSource("tree-devices", devices);
this.treeLoadDataSource("tree-tools", tools);
this.trees_filled = true;
//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");
var mode = $(this).data("mode");
var target = $(this).data("target");
var 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 {
Cookies.set("tree_datasource_" + target, mode);
exports.ajaxUI.treeLoadDataSource(target, mode);
}
return false;
});
};
/**
* Load the given url into the tree with the given id.
* @param target_id
* @param datasource
*/
AjaxUI.prototype.treeLoadDataSource = function (target_id, datasource) {
var 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":
exports.ajaxUI.initTree("#" + target_id, 'tree/categories/');
break;
case "locations":
exports.ajaxUI.initTree("#" + target_id, 'tree/locations');
break;
case "footprints":
exports.ajaxUI.initTree("#" + target_id, 'tree/footprints');
break;
case "manufacturers":
exports.ajaxUI.initTree("#" + target_id, 'tree/manufacturers');
break;
case "suppliers":
exports.ajaxUI.initTree("#" + target_id, 'tree/suppliers');
break;
case "tools":
exports.ajaxUI.initTree("#" + target_id, 'tree/tools/');
break;
case "devices":
exports.ajaxUI.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
*/
AjaxUI.prototype.initTree = function (tree, url) {
//let contextmenu_handler = this.onNodeContextmenu;
$.getJSON(exports.ajaxUI.BASE + url, function (data) {
// @ts-ignore
$(tree).treeview({
data: data,
enableLinks: false,
showIcon: false,
showBorder: true,
onNodeSelected: function (event, data) {
if (data.href) {
exports.ajaxUI.navigateTo(data.href);
}
},
//onNodeContextmenu: contextmenu_handler,
expandIcon: "fas fa-plus fa-fw fa-treeview", collapseIcon: "fas fa-minus fa-fw fa-treeview"
}).treeview('collapseAll', { silent: true });
});
};
/**
* Register all links, for loading via ajax.
*/
AjaxUI.prototype.registerLinks = function () {
$('a').not(".link-external, [data-no-ajax]").click(function (event) {
var a = $(this);
var href = $.trim(a.attr("href"));
//Ignore links without href attr and nav links ('they only have a #)
if (href != null && href != "" && href.charAt(0) !== '#') {
event.preventDefault();
exports.ajaxUI.navigateTo(href);
}
});
console.debug('Links registered!');
};
/**
* Register all forms for loading via ajax.
*/
AjaxUI.prototype.registerForm = function () {
var options = {
success: this.onAjaxComplete,
beforeSubmit: function (arr, $form, options) {
//When data-with-progbar is specified, then show progressbar.
if ($form.data("with-progbar") != undefined) {
exports.ajaxUI.showProgressBar();
}
return true;
}
};
$('form').not('[data-no-ajax]').ajaxForm(options);
console.debug('Forms registered!');
};
AjaxUI.prototype.showProgressBar = function () {
//Blur content background
$('#content').addClass('loading-content');
// @ts-ignore
$('#progressModal').modal({
keyboard: false,
backdrop: false,
show: true
});
};
AjaxUI.prototype.hideProgressBar = function () {
// @ts-ignore
$('#progressModal').modal('hide');
//Remove the remaining things of the modal
$('.modal-backdrop').remove();
$('body').removeClass('modal-open');
$('body, .navbar').css('padding-right', "");
};
/**
* Navigates to the given URL
* @param url The url which should be opened.
* @param show_loading Show the loading bar during loading.
*/
AjaxUI.prototype.navigateTo = function (url, show_loading) {
if (show_loading === void 0) { show_loading = true; }
if (show_loading) {
this.showProgressBar();
}
$.ajax(url, {
success: this.onAjaxComplete
});
//$.ajax(url).promise().done(this.onAjaxComplete);
};
/**
* Called when an error occurs on loading ajax. Outputs the message to the console.
*/
AjaxUI.prototype.onAjaxError = function (event, request, settings) {
'use strict';
//Ignore aborted requests.
if (request.statusText == 'abort') {
return;
}
console.error("Error getting the ajax data from server!");
console.log(event);
console.log(request);
console.log(settings);
//If it was a server error and response is not empty, show it to user.
if (request.status == 500 && request.responseText !== "") {
console.log("Response:" + request.responseText);
}
};
/**
* This function gets called every time, the "back" button in the browser is pressed.
* We use it to load the content from history stack via ajax and to rewrite url, so we only have
* to load #content-data
* @param event
*/
AjaxUI.prototype.onPopState = function (event) {
var page = location.href;
exports.ajaxUI.statePopped = true;
exports.ajaxUI.navigateTo(page);
};
/**
* This function takes the response of an ajax requests, and does the things we need to do for our AjaxUI.
* This includes inserting the content and pushing history.
* @param responseText
* @param textStatus
* @param jqXHR
*/
AjaxUI.prototype.onAjaxComplete = function (responseText, textStatus, jqXHR) {
console.debug("Ajax load completed!");
exports.ajaxUI.hideProgressBar();
//Parse response to DOM structure
var dom = $.parseHTML(responseText);
//And replace the content container
$("#content").replaceWith($("#content", dom));
//Replace login menu too (so everything is up to date)
$("#login-content").replaceWith($('#login-content', dom));
//Replace flash messages and show them
$("#message-container").replaceWith($('#message-container', dom));
$(".toast").toast('show');
//Set new title
var title = extractTitle(responseText);
document.title = title;
//Push to history, if we currently arent poping an old value.
if (!exports.ajaxUI.statePopped) {
// @ts-ignore
history.pushState(null, title, this.url);
}
else {
//Clear pop state
exports.ajaxUI.statePopped;
}
//Do things on the new dom
exports.ajaxUI.registerLinks();
exports.ajaxUI.registerForm();
};
return AjaxUI;
}());
exports.ajaxUI = new AjaxUI();
//# sourceMappingURL=ajax_ui.js.map

File diff suppressed because one or more lines are too long

View file

@ -50,15 +50,12 @@ function extractTitle(html : string) : string {
class AjaxUI {
protected BASE = "/";
private trees_filled : boolean = false;
private statePopped : boolean = false;
public test()
{
alert("Test");
}
public constructor()
{
//Make back in the browser go back in history
@ -74,14 +71,132 @@ class AjaxUI {
public start()
{
console.info("AjaxUI started!");
this.BASE = $("body").data("base-url") + "/";
console.info("Base path is " + this.BASE);
this.registerLinks();
this.registerForm();
this.fillTrees();
}
/**
* Fill the trees with the given data.
*/
public fillTrees()
{
let categories = Cookies.get("tree_datasource_tree-categories");
let devices = Cookies.get("tree_datasource_tree-devices");
let tools = Cookies.get("tree_datasource_tree-tools");
if(typeof categories == "undefined") {
categories = "categories";
}
if(typeof devices == "undefined") {
devices = "devices";
}
if(typeof tools == "undefined") {
tools = "tools";
}
this.treeLoadDataSource("tree-categories", categories);
this.treeLoadDataSource("tree-devices", devices);
this.treeLoadDataSource("tree-tools", tools);
this.trees_filled = true;
//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 {
Cookies.set("tree_datasource_" + target, mode);
ajaxUI.treeLoadDataSource(target, mode);
}
return false;
});
}
/**
* Load the given url into the tree with the given id.
* @param target_id
* @param datasource
*/
protected treeLoadDataSource(target_id, datasource) {
let text : string = $(".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":
ajaxUI.initTree("#" + target_id, 'tree/categories/');
break;
case "locations":
ajaxUI.initTree("#" + target_id, 'tree/locations');
break;
case "footprints":
ajaxUI.initTree("#" + target_id, 'tree/footprints');
break;
case "manufacturers":
ajaxUI.initTree("#" + target_id, 'tree/manufacturers');
break;
case "suppliers":
ajaxUI.initTree("#" + target_id, 'tree/suppliers');
break;
case "tools":
ajaxUI.initTree("#" + target_id, 'tree/tools/');
break;
case "devices":
ajaxUI.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
*/
public initTree(tree, url) {
//let contextmenu_handler = this.onNodeContextmenu;
$.getJSON(ajaxUI.BASE + url, function (data) {
// @ts-ignore
$(tree).treeview({
data: data,
enableLinks: false,
showIcon: false,
showBorder: true,
onNodeSelected: function(event, data) {
if(data.href) {
ajaxUI.navigateTo(data.href);
}
},
//onNodeContextmenu: contextmenu_handler,
expandIcon: "fas fa-plus fa-fw fa-treeview", collapseIcon: "fas fa-minus fa-fw fa-treeview"}).treeview('collapseAll', { silent: true });
});
}
/**
* Register all links, for loading via ajax.
*/
protected registerLinks()
public registerLinks()
{
$('a').not(".link-external, [data-no-ajax]").click(function (event) {
let a = $(this);
@ -92,14 +207,14 @@ class AjaxUI {
ajaxUI.navigateTo(href);
}
}
)
);
console.debug('Links registered!');
}
/**
* Register all forms for loading via ajax.
*/
protected registerForm()
public registerForm()
{
let options : JQueryFormOptions = {
success: this.onAjaxComplete,
@ -110,7 +225,7 @@ class AjaxUI {
}
return true;
}
}
};
$('form').not('[data-no-ajax]').ajaxForm(options);
console.debug('Forms registered!');
@ -168,7 +283,10 @@ class AjaxUI {
return;
}
console.error("Error getting the ajax data from server!");
console.log(event);
console.log(request);
console.log(settings);
//If it was a server error and response is not empty, show it to user.
if(request.status == 500 && request.responseText !== "")
{

View file

@ -4,7 +4,7 @@
"target": "es5",
"sourceMap": true,
"typeRoots": ["../node_modules"],
"types": ["jquery", "js-cookie", "bootstrap", "jquery.form"]
"types": ["jquery", "js-cookie", "bootstrap", "jquery.form", "bootstrap-treeview"]
},
"exclude": [
"node_modules"

View file

@ -18,6 +18,7 @@
"dependencies": {
"@ckeditor/ckeditor5-build-classic": "^12.0.0",
"@types/bootstrap": "^4.3.0",
"@types/bootstrap-treeview": "^1.20.0",
"@types/jquery": "^3.3.29",
"@types/jquery.form": "^3.26.30",
"@types/js-cookie": "^2.2.1",

View file

@ -30,9 +30,16 @@
namespace App\Controller;
use App\Entity\Category;
use App\Entity\Device;
use App\Entity\Footprint;
use App\Entity\Manufacturer;
use App\Entity\Storelocation;
use App\Entity\Supplier;
use App\Helpers\TreeViewNode;
use App\Services\ToolsTreeBuilder;
use App\Services\TreeBuilder;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Form\Extension\Core\Type\LocaleType;
use Symfony\Component\Routing\Annotation\Route;
/**
@ -55,6 +62,7 @@ class TreeController extends AbstractController
/**
* @Route("/tree/category/{id}", name="tree_category")
* @Route("/tree/categories")
*/
public function categoryTree(TreeBuilder $builder, Category $category = null)
{
@ -68,7 +76,85 @@ class TreeController extends AbstractController
return $this->json($tree, 200, [], ['skip_null_values' => true]);
}
/**
* @Route("/tree/footprint/{id}", name="tree_footprint")
* @Route("/tree/footprints")
*/
public function footprintTree(TreeBuilder $builder, Footprint $footprint = null)
{
if ($footprint != null) {
$tree[] = $builder->elementToTreeNode($footprint);
} else {
$tree = $builder->typeToTree(Footprint::class, null);
}
return $this->json($tree, 200, [], ['skip_null_values' => true]);
}
/**
* @Route("/tree/location/{id}", name="tree_location")
* @Route("/tree/locations")
*/
public function locationTree(TreeBuilder $builder, Storelocation $location = null)
{
if ($location != null) {
$tree[] = $builder->elementToTreeNode($location);
} else {
$tree = $builder->typeToTree(Storelocation::class, null);
}
return $this->json($tree, 200, [], ['skip_null_values' => true]);
}
/**
* @Route("/tree/manufacturer/{id}", name="tree_manufacturer")
* @Route("/tree/manufacturers")
*/
public function manufacturerTree(TreeBuilder $builder, Manufacturer $manufacturer = null)
{
if ($manufacturer != null) {
$tree[] = $builder->elementToTreeNode($manufacturer);
} else {
$tree = $builder->typeToTree(Manufacturer::class, null);
}
return $this->json($tree, 200, [], ['skip_null_values' => true]);
}
/**
* @Route("/tree/supplier/{id}", name="tree_supplier")
* @Route("/tree/suppliers")
*/
public function supplierTree(TreeBuilder $builder, Supplier $supplier = null)
{
if ($supplier != null) {
$tree[] = $builder->elementToTreeNode($supplier);
} else {
$tree = $builder->typeToTree(Supplier::class, null);
}
return $this->json($tree, 200, [], ['skip_null_values' => true]);
}
/**
* @Route("/tree/device/{id}", name="tree_device")
* @Route("/tree/devices")
*/
public function deviceTree(TreeBuilder $builder, Device $device = null)
{
if ($device != null) {
$tree[] = $builder->elementToTreeNode($device);
} else {
$tree = $builder->typeToTree(Device::class, null);
}
return $this->json($tree, 200, [], ['skip_null_values' => true]);
}
}

View file

@ -29,7 +29,7 @@ use Doctrine\ORM\Mapping as ORM;
/**
* Class AttachmentType.
*
* @ORM\Entity()
* @ORM\Entity(repositoryClass="App\Repository\StructuralDBElementRepository")
* @ORM\Table(name="attachement_types")
*/
class AttachmentType extends StructuralDBElement

View file

@ -28,7 +28,7 @@ use Doctrine\ORM\Mapping as ORM;
/**
* Class AttachmentType.
*
* @ORM\Entity
* @ORM\Entity(repositoryClass="App\Repository\StructuralDBElementRepository")
* @ORM\Table(name="categories")
*/
class Category extends PartsContainingDBElement

View file

@ -37,7 +37,7 @@ use Doctrine\ORM\Mapping as ORM;
/**
* Class AttachmentType.
*
* @ORM\Entity()
* @ORM\Entity(repositoryClass="App\Repository\StructuralDBElementRepository")
* @ORM\Table(name="devices")
*/
class Device extends PartsContainingDBElement

View file

@ -37,7 +37,7 @@ use Doctrine\ORM\Mapping as ORM;
/**
* Class Footprint.
*
* @ORM\Entity()
* @ORM\Entity(repositoryClass="App\Repository\StructuralDBElementRepository")
* @ORM\Table("footprints")
*/
class Footprint extends PartsContainingDBElement

View file

@ -37,7 +37,7 @@ use Doctrine\ORM\Mapping as ORM;
/**
* Class Manufacturer.
*
* @ORM\Entity()
* @ORM\Entity(repositoryClass="App\Repository\StructuralDBElementRepository")
* @ORM\Table("manufacturers")
*/
class Manufacturer extends Company

View file

@ -37,7 +37,7 @@ use Doctrine\ORM\Mapping as ORM;
/**
* Class Storelocation.
*
* @ORM\Entity()
* @ORM\Entity(repositoryClass="App\Repository\StructuralDBElementRepository")
* @ORM\Table("storelocations")
*/
class Storelocation extends PartsContainingDBElement

View file

@ -36,8 +36,7 @@ use Doctrine\ORM\PersistentCollection;
* It's allowed to have instances of root elements, but if you try to change
* an attribute of a root element, you will get an exception!
*
* @ORM\MappedSuperclass()
* //@ORM\Entity(repositoryClass="App\Repository\StructuralDBElementRepository")
* @ORM\MappedSuperclass(repositoryClass="App\Repository\StructuralDBElementRepository")
*/
abstract class StructuralDBElement extends AttachmentContainingDBElement
{
@ -310,50 +309,6 @@ abstract class StructuralDBElement extends AttachmentContainingDBElement
return implode("\n", $html);
}
public function buildBootstrapTree(
$page,
$parameter,
$recursive = false,
$show_root = false,
$use_db_root_name = true,
$root_name = '$$'
): array {
if ('$$' == $root_name) {
$root_name = _('Oberste Ebene');
}
$subelements = $this->getSubelements(false);
$nodes = array();
foreach ($subelements as $element) {
$nodes[] = $element->buildBootstrapTree($page, $parameter);
}
// if we are on root level?
if (-1 == $this->getParentID()) {
if ($show_root) {
$tree = array(
array('text' => $use_db_root_name ? htmlspecialchars($this->getName()) : $root_name,
'href' => $page.'?'.$parameter.'='.$this->getID(),
'nodes' => $nodes, ),
);
} else { //Dont show root node
$tree = $nodes;
}
} elseif (!empty($nodes)) {
$tree = array('text' => htmlspecialchars($this->getName()),
'href' => $page.'?'.$parameter.'='.$this->getID(),
'nodes' => $nodes,
);
} else {
$tree = array('text' => htmlspecialchars($this->getName()),
'href' => $page.'?'.$parameter.'='.$this->getID(),
);
}
return $tree;
}
/**
* Creates a template loop for a Breadcrumb bar, representing the structural DB element.
*

View file

@ -37,7 +37,7 @@ use Doctrine\ORM\Mapping as ORM;
/**
* Class Supplier.
*
* @ORM\Entity()
* @ORM\Entity(repositoryClass="App\Repository\StructuralDBElementRepository")
* @ORM\Table("suppliers")
*/
class Supplier extends Company

View file

@ -1,8 +1,9 @@
<?php
/**
*
* part-db version 0.1
* Copyright (C) 2005 Christoph Lechner
* http://www.cl-projects.de/.
* http://www.cl-projects.de/
*
* part-db version 0.2+
* Copyright (C) 2009 K. Jacobs and others (see authors.php)
@ -25,15 +26,14 @@
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*
*/
namespace App\Controller;
namespace App\Services;
use App\Entity\StructuralDBElement;
use App\Helpers\TreeViewNode;
use App\Repository\StructuralDBElementRepository;
use App\Services\EntityURLGenerator;
use App\Services\ToolsTreeBuilder;
use Doctrine\ORM\EntityManagerInterface;
/**
@ -59,13 +59,13 @@ class TreeBuilder
* See EntityURLGenerator::getURL for possible types.
* @return TreeViewNode The Node for the given Element.
*/
public function elementToTreeNode(StructuralDBElement $element, string $href_type = 'list_parts') : TreeViewNode
public function elementToTreeNode(StructuralDBElement $element, ?string $href_type = 'list_parts') : TreeViewNode
{
$children = $element->getSubelements();
$children_nodes = null;
foreach ($children as $child) {
$children_nodes[] = $this->elementToTreeNode($child);
$children_nodes[] = $this->elementToTreeNode($child, $href_type);
}
//Check if we need to generate a href type
@ -86,7 +86,7 @@ class TreeBuilder
* See EntityURLGenerator::getURL for possible types.
* @return TreeViewNode[] Returns an array, containing all nodes. It is empty if the given class has no elements.
*/
public function typeToTree(StructuralDBElement $class_name, string $href_type = 'list_parts') : array
public function typeToTree(string $class_name, ?string $href_type = 'list_parts') : array
{
/**
* @var $repo StructuralDBElementRepository
@ -96,7 +96,7 @@ class TreeBuilder
$array = array();
foreach ($root_nodes as $node) {
$array = $this->elementToTreeNode($node, $href_type);
$array[] = $this->elementToTreeNode($node, $href_type);
}
return $array;

View file

@ -13,13 +13,12 @@
<meta name="msapplication-config" content="{{ asset('icons/browserconfig.xml') }}">
<meta name="theme-color" content="#ffffff">
<title>{% filter trim %}{% block title %}{{ partdb_title}}{% endblock %}{% endfilter %}</title>
{% block stylesheets %}
{{ encore_entry_link_tags('app') }}
{% endblock %}
</head>
<body>
<body data-base-url="{{ app.request.schemeAndHttpHost }}">
{% block body %}
<header>
@ -279,6 +278,7 @@
<script>
{#
$.getJSON("{{ path("tree_tools") }}",null, function (data) {
$('#tree-tools').treeview({
data: data,
@ -293,6 +293,7 @@
enableLinks: true
});
});
#}
</script>
{% block scripts %}

View file

@ -650,6 +650,13 @@
resolved "https://registry.yarnpkg.com/@types/anymatch/-/anymatch-1.3.1.tgz#336badc1beecb9dacc38bea2cf32adf627a8421a"
integrity sha512-/+CRPXpBDpo2RK9C68N3b2cOvO0Cf5B9aPijHsoDQTHivnGSObdOF2BRQOYjojWTDy6nQvMjmqRXIxH55VjxxA==
"@types/bootstrap-treeview@^1.20.0":
version "1.20.0"
resolved "https://registry.yarnpkg.com/@types/bootstrap-treeview/-/bootstrap-treeview-1.20.0.tgz#08157e2f26b5b278dfd70e2054bbf8aa7d6f0b2d"
integrity sha512-o1FFKSNd68ohmyvrHna11q5cLd9aiVUp/Itr7B33OmFY37GFufQvVOH9Iv/+2xcE9tVc7pHfmxucBnQkjZzHCQ==
dependencies:
"@types/jquery" "*"
"@types/bootstrap@^4.3.0":
version "4.3.0"
resolved "https://registry.yarnpkg.com/@types/bootstrap/-/bootstrap-4.3.0.tgz#4cac01617f56239a5146945a98bde64274838c35"