Custom Tooltip-System: eigenes Tooltip statt Browser-Standard, 200ms Delay, bevorzugt oben, individuelle Tooltips pro Git-Badge
This commit is contained in:
1 parent
6b7df138de
commit
c3812fbf2b
4 files changed
+153
-10
No files matched your search
@@ -0,0 +1,123 @@
|
||||
// ── Custom Tooltip ──
|
||||
// Ersetzt native browser-tooltips für alle [title]-Elemente
|
||||
|
||||
(function () {
|
||||
const DELAY = 200;
|
||||
|
||||
let tooltipEl = null;
|
||||
let timeout = null;
|
||||
let currentTarget = null;
|
||||
|
||||
function createTooltipEl() {
|
||||
const el = document.createElement('div');
|
||||
el.className = 'tooltip';
|
||||
document.body.appendChild(el);
|
||||
return el;
|
||||
}
|
||||
|
||||
function show(target) {
|
||||
const text = target.getAttribute('data-tooltip');
|
||||
if (!text) return;
|
||||
|
||||
if (!tooltipEl) tooltipEl = createTooltipEl();
|
||||
|
||||
tooltipEl.textContent = '';
|
||||
const lines = text.split('\n');
|
||||
for (let i = 0; i < lines.length; i++) {
|
||||
if (i > 0) tooltipEl.appendChild(document.createElement('br'));
|
||||
tooltipEl.appendChild(document.createTextNode(lines[i]));
|
||||
}
|
||||
|
||||
tooltipEl.classList.add('visible');
|
||||
position(target);
|
||||
currentTarget = target;
|
||||
}
|
||||
|
||||
function position(target) {
|
||||
if (!tooltipEl) return;
|
||||
|
||||
const rect = target.getBoundingClientRect();
|
||||
const gap = 8;
|
||||
|
||||
// Reset für Messung
|
||||
tooltipEl.style.left = '0';
|
||||
tooltipEl.style.top = '0';
|
||||
|
||||
const tw = tooltipEl.offsetWidth;
|
||||
const th = tooltipEl.offsetHeight;
|
||||
|
||||
// Versuche oben zu platzieren
|
||||
let top = rect.top - th - gap;
|
||||
let left = rect.left + rect.width / 2 - tw / 2;
|
||||
|
||||
// Wenn oben kein Platz → unten
|
||||
if (top < gap) {
|
||||
top = rect.bottom + gap;
|
||||
}
|
||||
|
||||
// Horizontal begrenzen
|
||||
if (left < gap) left = gap;
|
||||
if (left + tw > window.innerWidth - gap) left = window.innerWidth - gap - tw;
|
||||
|
||||
tooltipEl.style.left = left + 'px';
|
||||
tooltipEl.style.top = top + 'px';
|
||||
}
|
||||
|
||||
function hide() {
|
||||
clearTimeout(timeout);
|
||||
timeout = null;
|
||||
if (tooltipEl) tooltipEl.classList.remove('visible');
|
||||
if (currentTarget) {
|
||||
// title zurücksetzen
|
||||
const text = currentTarget.getAttribute('data-tooltip');
|
||||
if (text) {
|
||||
currentTarget.setAttribute('title', text);
|
||||
currentTarget.removeAttribute('data-tooltip');
|
||||
}
|
||||
currentTarget = null;
|
||||
}
|
||||
}
|
||||
|
||||
function findTitleTarget(el) {
|
||||
while (el && el !== document.body) {
|
||||
if (el.getAttribute && (el.getAttribute('title') || el.getAttribute('data-tooltip'))) return el;
|
||||
el = el.parentElement;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
document.addEventListener('mouseenter', function (e) {
|
||||
const target = findTitleTarget(e.target);
|
||||
if (!target) return;
|
||||
|
||||
// title → data-tooltip verschieben (native tooltip unterdrücken)
|
||||
const title = target.getAttribute('title');
|
||||
if (title) {
|
||||
target.setAttribute('data-tooltip', title);
|
||||
target.removeAttribute('title');
|
||||
}
|
||||
|
||||
const text = target.getAttribute('data-tooltip');
|
||||
if (!text) return;
|
||||
|
||||
// Falls bereits ein anderer tooltip offen → sofort wechseln
|
||||
if (currentTarget && currentTarget !== target) {
|
||||
hide();
|
||||
}
|
||||
|
||||
clearTimeout(timeout);
|
||||
timeout = setTimeout(function () { show(target); }, DELAY);
|
||||
}, true);
|
||||
|
||||
document.addEventListener('mouseleave', function (e) {
|
||||
const target = findTitleTarget(e.target);
|
||||
if (!target) return;
|
||||
if (target === currentTarget || timeout) {
|
||||
hide();
|
||||
}
|
||||
}, true);
|
||||
|
||||
// Auch bei Scroll/Resize verstecken
|
||||
document.addEventListener('scroll', hide, true);
|
||||
window.addEventListener('resize', hide);
|
||||
})();
|
||||
Reference in new issue
Block a user