From 23c83ea0209e08b59f27aeb50b2670cc163fc0d8 Mon Sep 17 00:00:00 2001 From: mjansen Date: Mon, 4 May 2026 10:14:55 +0200 Subject: [PATCH] [IMPROVEMENT] UI/Dropdown: Make `Dropdown` instantiation more verbose/robust See: https://mantis.ilias.de/view.php?id=47310 --- .../ILIAS/UI/resources/js/Dropdown/dist/dropdown.js | 2 +- .../ILIAS/UI/resources/js/Dropdown/src/Dropdown.js | 6 ++++++ .../Implementation/Component/Dropdown/Renderer.php | 11 +++++++---- 3 files changed, 14 insertions(+), 5 deletions(-) diff --git a/components/ILIAS/UI/resources/js/Dropdown/dist/dropdown.js b/components/ILIAS/UI/resources/js/Dropdown/dist/dropdown.js index 3bae077f0c29..616292a499d0 100644 --- a/components/ILIAS/UI/resources/js/Dropdown/dist/dropdown.js +++ b/components/ILIAS/UI/resources/js/Dropdown/dist/dropdown.js @@ -12,4 +12,4 @@ * https://www.ilias.de * https://github.com/ILIAS-eLearning */ -!function(t){"use strict";class e{#t;#e;#i;#n;constructor(t){if(this.#e=t,this.#t=t.ownerDocument,this.#i=this.#e.querySelector(":scope > button"),null===this.#i)throw new Error("Dropdown: Expected exactly one button in dropdown element.",this.#e);if(this.#n=this.#e.querySelector(".dropdown-menu"),null===this.#n)throw new Error("Dropdown: Expected exactly a dropdown element.",this.#e);this.#i.addEventListener("click",this.#s)}#o=t=>{27===t.key&&this.hide()};#s=t=>{t.stopPropagation(),this.show()};#d=()=>{this.hide()};#l=()=>{const t=this.#t.documentElement.clientWidth;this.#i.getBoundingClientRect().left+this.#n.getBoundingClientRect().width>t?(this.#n.classList.remove("dropdown-menu__right"),this.#n.classList.add("dropdown-menu__left")):(this.#n.classList.remove("dropdown-menu__left"),this.#n.classList.add("dropdown-menu__right"))};show(){il.UI.dropdown.opened?.hide(),il.UI.dropdown.opened=this,this.#n.style.display="block",this.#l(),this.#i.setAttribute("aria-expanded","true"),this.#t.addEventListener("keydown",this.#o),this.#t.addEventListener("click",this.#d),this.#i.removeEventListener("click",this.#s)}hide(){this.#n.style.display="none",this.#i.setAttribute("aria-expanded","false"),this.#t.removeEventListener("keydown",this.#o),this.#t.removeEventListener("click",this.#d),this.#i.addEventListener("click",this.#s)}}t.UI=t.UI||{},t.UI.dropdown={},t.UI.dropdown.opened=null,t.UI.dropdown.init=function(t){return new e(t)}}(il); +!function(t){"use strict";class e{#t;#e;#n;#i;constructor(t){if(!(t&&t instanceof HTMLElement))throw new TypeError("Dropdown: Expected an HTMLElement root (.dropdown); received "+(null===t?"null":typeof t));if(this.#e=t,this.#t=t.ownerDocument,this.#n=this.#e.querySelector(":scope > button"),null===this.#n)throw new Error("Dropdown: Expected exactly one button in dropdown element.",this.#e);if(this.#i=this.#e.querySelector(".dropdown-menu"),null===this.#i)throw new Error("Dropdown: Expected exactly a dropdown element.",this.#e);this.#n.addEventListener("click",this.#o)}#s=t=>{27===t.key&&this.hide()};#o=t=>{t.stopPropagation(),this.show()};#d=()=>{this.hide()};#l=()=>{const t=this.#t.documentElement.clientWidth;this.#n.getBoundingClientRect().left+this.#i.getBoundingClientRect().width>t?(this.#i.classList.remove("dropdown-menu__right"),this.#i.classList.add("dropdown-menu__left")):(this.#i.classList.remove("dropdown-menu__left"),this.#i.classList.add("dropdown-menu__right"))};show(){il.UI.dropdown.opened?.hide(),il.UI.dropdown.opened=this,this.#i.style.display="block",this.#l(),this.#n.setAttribute("aria-expanded","true"),this.#t.addEventListener("keydown",this.#s),this.#t.addEventListener("click",this.#d),this.#n.removeEventListener("click",this.#o)}hide(){this.#i.style.display="none",this.#n.setAttribute("aria-expanded","false"),this.#t.removeEventListener("keydown",this.#s),this.#t.removeEventListener("click",this.#d),this.#n.addEventListener("click",this.#o)}}t.UI=t.UI||{},t.UI.dropdown={},t.UI.dropdown.opened=null,t.UI.dropdown.init=function(t){return new e(t)}}(il); diff --git a/components/ILIAS/UI/resources/js/Dropdown/src/Dropdown.js b/components/ILIAS/UI/resources/js/Dropdown/src/Dropdown.js index fb973fac1e28..e69368aaaf0a 100644 --- a/components/ILIAS/UI/resources/js/Dropdown/src/Dropdown.js +++ b/components/ILIAS/UI/resources/js/Dropdown/src/Dropdown.js @@ -38,6 +38,12 @@ export default class Dropdown { * @param {HTMLElement} element */ constructor(element) { + if (!element || !(element instanceof HTMLElement)) { + throw new TypeError( + `Dropdown: Expected an HTMLElement root (.dropdown); received ${ + element === null ? 'null' : typeof element}`, + ); + } this.#element = element; this.#document = element.ownerDocument; diff --git a/components/ILIAS/UI/src/Implementation/Component/Dropdown/Renderer.php b/components/ILIAS/UI/src/Implementation/Component/Dropdown/Renderer.php index 1a2adae90013..1db8507f0873 100755 --- a/components/ILIAS/UI/src/Implementation/Component/Dropdown/Renderer.php +++ b/components/ILIAS/UI/src/Implementation/Component/Dropdown/Renderer.php @@ -76,10 +76,13 @@ protected function renderDropdown(Dropdown $component, RendererInterface $defaul $tpl->parseCurrentBlock(); } - $component = $component->withAdditionalOnLoadCode( - fn($id) => - "il.UI.dropdown.init(document.getElementById(\"$id\"));" - ); + $component = $component->withAdditionalOnLoadCode(fn($id) => " + try { + il.UI.dropdown.init(document.getElementById(\"$id\")); + } catch (e) { + console?.error(e); + } + "); $this->renderId($component, $tpl);