// ==UserScript== // @name academyFIVE::AddSelectBox // @namespace dakp/academyfive // @version 2026.04.006 // @description Füge Selectbox für Kohorten/Planungsgruppen hinzu // @author Dims Akpan // @match https://a5.fhdw-hannover.de/* // @match https://a5.fhdw.de/* // @match https://fhdw.academyfive-preview.net/* // @match https://fhdw-hannover.academyfive-preview.net/* // @grant none // @icon https://www.academyfive.com/typo3conf/ext/sitepackage/Resources/Public/build/assets/images/favicon-academyfive.ico // ==/UserScript== (function() { 'use strict'; 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 dropdownContainer = select.closest('.btn-group.bootstrap-select'); if (!dropdownContainer) { console.log(LOG, 'closest(.btn-group.bootstrap-select) nicht gefunden'); return false; } const searchBox = dropdownContainer.querySelector('.bs-searchbox'); if (!searchBox) { console.log(LOG, '.bs-searchbox nicht gefunden im Container'); return false; } if (searchBox.nextElementSibling?.classList.contains('bs-actionsbox')) { console.log(LOG, 'Buttons bereits vorhanden, überspringe'); return true; } const actionsBox = document.createElement('div'); actionsBox.className = 'bs-actionsbox'; actionsBox.innerHTML = `
`; searchBox.insertAdjacentElement('afterend', actionsBox); console.log(LOG, 'Buttons erfolgreich eingefügt für:', selectSelector); return true; } 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/list')) { courseList_init(); } else { console.log(LOG, 'URL passt zu keiner bekannten Seite, Script inaktiv'); } } if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', init); } else { init(); } })();