diff --git a/assets/ts_src/ajax_ui.js b/assets/ts_src/ajax_ui.js new file mode 100644 index 00000000..1bf94e3a --- /dev/null +++ b/assets/ts_src/ajax_ui.js @@ -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 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 \ No newline at end of file diff --git a/assets/ts_src/ajax_ui.js.map b/assets/ts_src/ajax_ui.js.map new file mode 100644 index 00000000..aa016c85 --- /dev/null +++ b/assets/ts_src/ajax_ui.js.map @@ -0,0 +1 @@ +{"version":3,"file":"ajax_ui.js","sourceRoot":"","sources":["ajax_ui.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/assets/ts_src/ajax_ui.ts b/assets/ts_src/ajax_ui.ts index 300d36b6..7ed18ea1 100644 --- a/assets/ts_src/ajax_ui.ts +++ b/assets/ts_src/ajax_ui.ts @@ -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 !== "") { diff --git a/assets/tsconfig.json b/assets/tsconfig.json index 36c1e869..1dbb6fc8 100644 --- a/assets/tsconfig.json +++ b/assets/tsconfig.json @@ -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" diff --git a/package.json b/package.json index c17d0de8..72bae9c9 100644 --- a/package.json +++ b/package.json @@ -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", diff --git a/src/Controller/TreeController.php b/src/Controller/TreeController.php index 10898734..980814d0 100644 --- a/src/Controller/TreeController.php +++ b/src/Controller/TreeController.php @@ -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,10 +62,11 @@ class TreeController extends AbstractController /** * @Route("/tree/category/{id}", name="tree_category") + * @Route("/tree/categories") */ public function categoryTree(TreeBuilder $builder, Category $category = null) { - if($category != null) { + if ($category != null) { $tree[] = $builder->elementToTreeNode($category); } else { $tree = $builder->typeToTree(Category::class); @@ -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]); + } + } diff --git a/src/Entity/AttachmentType.php b/src/Entity/AttachmentType.php index ba4d4f98..5c99c437 100644 --- a/src/Entity/AttachmentType.php +++ b/src/Entity/AttachmentType.php @@ -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 diff --git a/src/Entity/Category.php b/src/Entity/Category.php index f2f6d8fb..c4d97a36 100644 --- a/src/Entity/Category.php +++ b/src/Entity/Category.php @@ -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 diff --git a/src/Entity/Device.php b/src/Entity/Device.php index 8a60f686..905b119a 100644 --- a/src/Entity/Device.php +++ b/src/Entity/Device.php @@ -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 diff --git a/src/Entity/Footprint.php b/src/Entity/Footprint.php index dfd96b53..49cb887e 100644 --- a/src/Entity/Footprint.php +++ b/src/Entity/Footprint.php @@ -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 diff --git a/src/Entity/Manufacturer.php b/src/Entity/Manufacturer.php index 0cfccf4b..7a327f16 100644 --- a/src/Entity/Manufacturer.php +++ b/src/Entity/Manufacturer.php @@ -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 diff --git a/src/Entity/Storelocation.php b/src/Entity/Storelocation.php index a0f43f23..63e424ad 100644 --- a/src/Entity/Storelocation.php +++ b/src/Entity/Storelocation.php @@ -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 diff --git a/src/Entity/StructuralDBElement.php b/src/Entity/StructuralDBElement.php index 8390e69d..c76e090a 100644 --- a/src/Entity/StructuralDBElement.php +++ b/src/Entity/StructuralDBElement.php @@ -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. * diff --git a/src/Entity/Supplier.php b/src/Entity/Supplier.php index 9a7a04b3..0042baa8 100644 --- a/src/Entity/Supplier.php +++ b/src/Entity/Supplier.php @@ -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 diff --git a/src/Controller/TreeBuilder.php b/src/Services/TreeBuilder.php similarity index 88% rename from src/Controller/TreeBuilder.php rename to src/Services/TreeBuilder.php index 2545c429..13956069 100644 --- a/src/Controller/TreeBuilder.php +++ b/src/Services/TreeBuilder.php @@ -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; diff --git a/templates/base.html.twig b/templates/base.html.twig index a3818f82..57c6fa1d 100644 --- a/templates/base.html.twig +++ b/templates/base.html.twig @@ -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 %} {% block stylesheets %} {{ encore_entry_link_tags('app') }} {% endblock %} - + {% block body %}
@@ -279,6 +278,7 @@ {% block scripts %} diff --git a/yarn.lock b/yarn.lock index 7dce30ec..997797a8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -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"