From 1771382287776a2e259e814daed65063d561853a Mon Sep 17 00:00:00 2001 From: Dims Akpan Date: Tue, 28 Apr 2026 09:37:17 +0200 Subject: [PATCH] =?UTF-8?q?Unterst=C3=BCtzung=20f=C3=BCr=20/course/show=20?= =?UTF-8?q?und=20Refactoring?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Seitenrouting auf /course/show korrigiert (/course/list leitet um) - Planungsgruppen-Dropdown (planningGroupIds[]) für /course/show ergänzt - Funktionsblöcke je Seite eingeführt (courseList_*, planningGroupList_*) - MutationObserver + Polling für zuverlässiges Timing beim Seitenladen - .gitignore ergänzt --- .gitignore | 3 + academyFIVE__AddSelectBox.user.js | 132 ++++++++++++++++++++++-------- 2 files changed, 101 insertions(+), 34 deletions(-) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..06e56e3 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ + + +temp.html diff --git a/academyFIVE__AddSelectBox.user.js b/academyFIVE__AddSelectBox.user.js index e0feafa..87e98b7 100644 --- a/academyFIVE__AddSelectBox.user.js +++ b/academyFIVE__AddSelectBox.user.js @@ -1,8 +1,8 @@ // ==UserScript== // @name academyFIVE::AddSelectBox // @namespace dakp/academyfive -// @version 2026.03.001 -// @description Füge Selectbox für Kohorten hinzu +// @version 2026.04.007 +// @description Füge Selectbox für Kohorten/Planungsgruppen hinzu // @author Dims Akpan // @match https://a5.fhdw-hannover.de/* // @match https://a5.fhdw.de/* @@ -14,34 +14,35 @@ (function() { 'use strict'; - - function addSelectButtons() { - // Prüfe ob wir auf der richtigen Seite sind - if (!window.location.href.includes('/course/planning-group/list')) { - return; + + const LOG = '[A5-SelectBox]'; + + // ─── Gemeinsame Hilfsfunktionen ─────────────────────────────────────────── + + function insertSelectButtons(selectSelector) { + const select = document.querySelector(selectSelector); + if (!select) { + console.log(LOG, 'select nicht gefunden:', selectSelector); + return false; } - - const cohortsDropdown = document.querySelector('select[name="cohort-ids[]"]'); - - if (!cohortsDropdown) { - console.log('Kohorten-Dropdown nicht gefunden'); - return; + + const dropdownContainer = select.closest('.btn-group.bootstrap-select'); + if (!dropdownContainer) { + console.log(LOG, 'closest(.btn-group.bootstrap-select) nicht gefunden'); + return false; } - - const dropdownContainer = cohortsDropdown.closest('.btn-group.bootstrap-select'); - const searchBox = dropdownContainer?.querySelector('.bs-searchbox'); - + + const searchBox = dropdownContainer.querySelector('.bs-searchbox'); if (!searchBox) { - console.log('Searchbox nicht gefunden'); - return; + console.log(LOG, '.bs-searchbox nicht gefunden im Container'); + return false; } - - // Prüfe ob schon vorhanden + if (searchBox.nextElementSibling?.classList.contains('bs-actionsbox')) { - console.log('Select/Deselect Buttons bereits vorhanden'); - return; + console.log(LOG, 'Buttons bereits vorhanden, überspringe'); + return true; } - // Füge die Buttons hinzu + const actionsBox = document.createElement('div'); actionsBox.className = 'bs-actionsbox'; actionsBox.innerHTML = ` @@ -50,17 +51,80 @@ `; - + searchBox.insertAdjacentElement('afterend', actionsBox); - - console.log('Select/Deselect Buttons erfolgreich eingefügt'); + console.log(LOG, 'Buttons erfolgreich eingefügt für:', selectSelector); + return true; } - - // Versuche es direkt - addSelectButtons(); - - // Falls das Element noch nicht da ist, warte auf DOMContentLoaded + + function waitAndInsert(tryFn) { + console.log(LOG, 'waitAndInsert gestartet | readyState:', document.readyState, '| URL:', window.location.href); + + if (tryFn()) return; + + console.log(LOG, 'Erster Versuch fehlgeschlagen, starte Observer + Polling'); + + const observer = new MutationObserver(() => { + if (tryFn()) { + console.log(LOG, 'Observer: Buttons eingefügt, Observer beendet'); + observer.disconnect(); + } + }); + + observer.observe(document.body, { childList: true, subtree: true }); + + let attempts = 0; + const poll = setInterval(() => { + attempts++; + if (tryFn()) { + console.log(LOG, 'Polling: Buttons eingefügt nach', attempts, 'Versuchen'); + clearInterval(poll); + } else if (attempts >= 50) { + console.log(LOG, 'Polling: Timeout nach 50 Versuchen'); + clearInterval(poll); + observer.disconnect(); + } + }, 100); + } + + // ─── /course/list ───────────────────────────────────────────────────────── + + function courseList_tryInsert() { + return insertSelectButtons('select[name="planningGroupIds[]"]'); + } + + function courseList_init() { + waitAndInsert(courseList_tryInsert); + } + + // ─── /course/planning-group/list ────────────────────────────────────────── + + function planningGroupList_tryInsert() { + return insertSelectButtons('select[name="cohort-ids[]"]'); + } + + function planningGroupList_init() { + waitAndInsert(planningGroupList_tryInsert); + } + + // ─── Routing ────────────────────────────────────────────────────────────── + + function init() { + const url = window.location.href; + console.log(LOG, 'init() | URL:', url); + + if (url.includes('/course/planning-group/list')) { + planningGroupList_init(); + } else if (url.includes('/course/show')) { + courseList_init(); + } else { + console.log(LOG, 'URL passt zu keiner bekannten Seite, Script inaktiv'); + } + } + if (document.readyState === 'loading') { - document.addEventListener('DOMContentLoaded', addSelectButtons); + document.addEventListener('DOMContentLoaded', init); + } else { + init(); } -})(); \ No newline at end of file +})();