diff --git a/academyFIVE__HighlightStudyRow.user.js b/academyFIVE__HighlightStudyRow.user.js
index bf4aa79..6c78733 100644
--- a/academyFIVE__HighlightStudyRow.user.js
+++ b/academyFIVE__HighlightStudyRow.user.js
@@ -1,7 +1,7 @@
// ==UserScript==
// @name academyFIVE::HighlightStudyRow
// @namespace dakp/academyfive
-// @version 2026.10.003
+// @version 2026.10.004
// @description Hebt beim Hovern einer Zelle die gesamte
-Zeile der Studiensemester-Tabelle (profil_studenten_edit.php4) per CSS hervor
// @author Dims Akpan
// @match https://a5.fhdw-hannover.de/admin/*
@@ -15,27 +15,48 @@
(function() {
'use strict';
- const STYLE_CLASS = 'a5-row-hl';
const HOVER_COLOR = 'rgba(0, 120, 200, 0.12)';
+ const STUDY_INPUTS = 'input[name*="hochschulsemester"], input[name*="fachsemester"], input[name*="as_gesamt"]';
- // Reines CSS: Hover wird nativ vom Browser verfolgt
- const style = document.createElement('style');
- style.textContent = `
+ function injectStyle(css) {
+ const style = document.createElement('style');
+ style.textContent = css;
+ (document.head || document.documentElement).appendChild(style);
+ }
+
+ // Bevorzugter Pfad: reines CSS über :has(). Kein JavaScript, kein Observer,
+ // keine DOM-Änderungen -> das Script kann Eigenheiten der Seite (z.B.
+ // Kontextmenüs, die auf DOM-Änderungen/Mausbewegung reagieren) nicht stören.
+ const HAS_TABLE = `table:has(${STUDY_INPUTS})`;
+ const cssSupportsHas = typeof CSS !== 'undefined'
+ && typeof CSS.supports === 'function'
+ && CSS.supports(`selector(${HAS_TABLE})`);
+
+ if (cssSupportsHas) {
+ injectStyle(`
+ ${HAS_TABLE} tr:hover th,
+ ${HAS_TABLE} tr:hover td {
+ background-color: ${HOVER_COLOR} !important;
+ }
+ `);
+ return;
+ }
+
+ // Fallback für ältere Browser ohne :has()-Unterstützung:
+ const STYLE_CLASS = 'a5-row-hl';
+ injectStyle(`
table.${STYLE_CLASS} tr:hover th,
table.${STYLE_CLASS} tr:hover td {
background-color: ${HOVER_COLOR} !important;
}
- `;
- (document.head || document.documentElement).appendChild(style);
+ `);
- // Studiensemester-Tabelle anhand typischer Eingabefelder erkennen
function isStudyTable(table) {
- return !!table.querySelector('input[name*="hochschulsemester"], input[name*="fachsemester"], input[name*="as_gesamt"]');
+ return !!table.querySelector(STUDY_INPUTS);
}
function markTable(table) {
- if (table.dataset.a5RowHl || table.classList.contains(STYLE_CLASS)) return;
- table.dataset.a5RowHl = 'true';
+ if (table.classList.contains(STYLE_CLASS)) return;
table.classList.add(STYLE_CLASS);
}
@@ -45,12 +66,30 @@
});
}
+ // Entprellter Observer, der nur auf neu eingefügte Tabellen/Inputs reagiert
+ // und nicht auf jede beliebige DOM-Änderung (Kontextmenü, Tooltips, Hover-Klassen).
+ let scanScheduled = false;
+ function scheduleScan() {
+ if (scanScheduled) return;
+ scanScheduled = true;
+ setTimeout(() => {
+ scanScheduled = false;
+ scanTables();
+ }, 200);
+ }
+
function onDocReady() {
scanTables();
- // Für dynamisch nachgeladene Tabellen: Klassenzuweisung ist idempotent,
- // daher dünner Observer mit kindList/childList.
- new MutationObserver(scanTables)
- .observe(document.documentElement, { childList: true, subtree: true });
+ new MutationObserver(mutations => {
+ const relevant = mutations.some(m =>
+ Array.from(m.addedNodes).some(n =>
+ n.nodeType === Node.ELEMENT_NODE &&
+ (n.tagName === 'TABLE' || n.tagName === 'INPUT' ||
+ n.querySelector('table') || n.querySelector('input'))
+ )
+ );
+ if (relevant) scheduleScan();
+ }).observe(document.documentElement, { childList: true, subtree: true });
}
if (document.readyState === 'loading') {