Files
A5-Tampermonkey/academyFIVE__AddSelectBox.user.js
T
2026-04-28 09:34:06 +02:00

131 lines
4.9 KiB
JavaScript

// ==UserScript==
// @name academyFIVE::AddSelectBox
// @namespace dakp/academyfive
// @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/*
// @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 = `
<div class="btn-group btn-group-sm btn-block">
<button type="button" class="actions-btn bs-select-all btn btn-default">Alles auswählen</button>
<button type="button" class="actions-btn bs-deselect-all btn btn-default">Nichts auswählen</button>
</div>
`;
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/show')) {
courseList_init();
} else {
console.log(LOG, 'URL passt zu keiner bekannten Seite, Script inaktiv');
}
}
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', init);
} else {
init();
}
})();