Unterstützung für /course/show und Refactoring

- 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
This commit is contained in:
2026-04-28 09:37:17 +02:00
parent 194c3e70e8
commit 1771382287
2 changed files with 101 additions and 34 deletions
+3
View File
@@ -0,0 +1,3 @@
temp.html
+98 -34
View File
@@ -1,8 +1,8 @@
// ==UserScript== // ==UserScript==
// @name academyFIVE::AddSelectBox // @name academyFIVE::AddSelectBox
// @namespace dakp/academyfive // @namespace dakp/academyfive
// @version 2026.03.001 // @version 2026.04.007
// @description Füge Selectbox für Kohorten hinzu // @description Füge Selectbox für Kohorten/Planungsgruppen hinzu
// @author Dims Akpan // @author Dims Akpan
// @match https://a5.fhdw-hannover.de/* // @match https://a5.fhdw-hannover.de/*
// @match https://a5.fhdw.de/* // @match https://a5.fhdw.de/*
@@ -14,34 +14,35 @@
(function() { (function() {
'use strict'; 'use strict';
function addSelectButtons() { const LOG = '[A5-SelectBox]';
// Prüfe ob wir auf der richtigen Seite sind
if (!window.location.href.includes('/course/planning-group/list')) { // ─── Gemeinsame Hilfsfunktionen ───────────────────────────────────────────
return;
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[]"]'); const dropdownContainer = select.closest('.btn-group.bootstrap-select');
if (!dropdownContainer) {
if (!cohortsDropdown) { console.log(LOG, 'closest(.btn-group.bootstrap-select) nicht gefunden');
console.log('Kohorten-Dropdown nicht gefunden'); return false;
return;
} }
const dropdownContainer = cohortsDropdown.closest('.btn-group.bootstrap-select'); const searchBox = dropdownContainer.querySelector('.bs-searchbox');
const searchBox = dropdownContainer?.querySelector('.bs-searchbox');
if (!searchBox) { if (!searchBox) {
console.log('Searchbox nicht gefunden'); console.log(LOG, '.bs-searchbox nicht gefunden im Container');
return; return false;
} }
// Prüfe ob schon vorhanden
if (searchBox.nextElementSibling?.classList.contains('bs-actionsbox')) { if (searchBox.nextElementSibling?.classList.contains('bs-actionsbox')) {
console.log('Select/Deselect Buttons bereits vorhanden'); console.log(LOG, 'Buttons bereits vorhanden, überspringe');
return; return true;
} }
// Füge die Buttons hinzu
const actionsBox = document.createElement('div'); const actionsBox = document.createElement('div');
actionsBox.className = 'bs-actionsbox'; actionsBox.className = 'bs-actionsbox';
actionsBox.innerHTML = ` actionsBox.innerHTML = `
@@ -50,17 +51,80 @@
<button type="button" class="actions-btn bs-deselect-all btn btn-default">Nichts auswählen</button> <button type="button" class="actions-btn bs-deselect-all btn btn-default">Nichts auswählen</button>
</div> </div>
`; `;
searchBox.insertAdjacentElement('afterend', actionsBox); searchBox.insertAdjacentElement('afterend', actionsBox);
console.log(LOG, 'Buttons erfolgreich eingefügt für:', selectSelector);
console.log('Select/Deselect Buttons erfolgreich eingefügt'); return true;
} }
// Versuche es direkt function waitAndInsert(tryFn) {
addSelectButtons(); console.log(LOG, 'waitAndInsert gestartet | readyState:', document.readyState, '| URL:', window.location.href);
// Falls das Element noch nicht da ist, warte auf DOMContentLoaded 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') { if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', addSelectButtons); document.addEventListener('DOMContentLoaded', init);
} else {
init();
} }
})(); })();