Warning: file_exists(): open_basedir restriction in effect. File(/bin/bash) is not within the allowed path(s): (/var/www/vhosts/nothing-news.de/:/tmp/) in /var/www/vhosts/nothing-news.de/wiki.nothing-news.de/w/includes/shell/CommandFactory.php on line 119
MediaWiki:Common.js: Difference between revisions - Nothing Wiki
Toggle menu
Toggle preferences menu
Toggle personal menu
Not logged in
Your IP address will be publicly visible if you make any edits.

MediaWiki:Common.js: Difference between revisions

MediaWiki interface page
No edit summary
No edit summary
Line 25: Line 25:
   document.body.appendChild(tooltip);
   document.body.appendChild(tooltip);


  // Pfeil erstellen
   const arrow = document.createElement('div');
   const arrow = document.createElement('div');
   Object.assign(arrow.style, {
   Object.assign(arrow.style, {
Line 48: Line 47:


     activeEl = el;
     activeEl = el;
     el.removeAttribute('title'); // Native verhindern
     el.removeAttribute('title'); // native verhindern
 
    // Tooltip vorbereiten, aber noch unsichtbar
     tooltip.textContent = storedTitle;
     tooltip.textContent = storedTitle;
     tooltip.appendChild(arrow); // Pfeil wieder anhängen
     tooltip.appendChild(arrow);
     tooltip.style.opacity = '1';
     tooltip.style.opacity = '0';
    tooltip.style.transform = 'translateY(0)';


     positionTooltip(el);
     // Force Reflow um korrekte Größe zu bekommen
    el.addEventListener('mouseleave', hideTooltip, { once: true });
     tooltip.getBoundingClientRect();
    el.addEventListener('mousemove', e => {}, { passive: true }); // optional, falls du hover-updates brauchst
  }
 
  function hideTooltip() {
    if (!activeEl) return;
     tooltip.style.opacity = '0';
    activeEl.setAttribute('title', storedTitle);
    activeEl = null;
    storedTitle = null;
  }


  function positionTooltip(el) {
    // Position berechnen
     const rect = el.getBoundingClientRect();
     const rect = el.getBoundingClientRect();
     const ttRect = tooltip.getBoundingClientRect();
     const ttRect = tooltip.getBoundingClientRect();
     const spacing = 6;
     const spacing = 6;
    let top, left;


    let top, left;
     const spaceAbove = rect.top;
     const spaceAbove = rect.top;
     const spaceBelow = window.innerHeight - rect.bottom;
     const spaceBelow = window.innerHeight - rect.bottom;
Line 77: Line 69:
     const spaceLeft = rect.left;
     const spaceLeft = rect.left;


     // Standard: Tooltip über dem Element
     // Intelligente Position: genug Platz bevorzugen
     let position = 'top';
     let position = 'bottom';
 
     if (spaceAbove > ttRect.height + spacing) position = 'top';
     if (spaceBelow > ttRect.height + spacing) position = 'bottom';
     else if (spaceRight > ttRect.width + spacing) position = 'right';
     else if (spaceRight > ttRect.width + spacing) position = 'right';
     else if (spaceLeft > ttRect.width + spacing) position = 'left';
     else if (spaceLeft > ttRect.width + spacing) position = 'left';


     switch(position) {
     switch (position) {
       case 'top':
       case 'top':
         top = rect.top - ttRect.height - spacing;
         top = rect.top - ttRect.height - spacing;
Line 91: Line 82:
           top: '100%',
           top: '100%',
           left: '50%',
           left: '50%',
           transform: 'translateX(-50%)',
           transform: 'translateX(-50%) rotate(0deg)',
           borderTopColor: 'rgba(20,20,20,0.95)',
           borderTopColor: 'rgba(20,20,20,0.95)',
          borderBottom: 'none',
         });
         });
         break;
         break;
Line 104: Line 94:
           transform: 'translateX(-50%) rotate(180deg)',
           transform: 'translateX(-50%) rotate(180deg)',
           borderTopColor: 'rgba(20,20,20,0.95)',
           borderTopColor: 'rgba(20,20,20,0.95)',
          borderBottom: 'none',
         });
         });
         break;
         break;
Line 115: Line 104:
           transform: 'translateY(-50%) rotate(90deg)',
           transform: 'translateY(-50%) rotate(90deg)',
           borderTopColor: 'rgba(20,20,20,0.95)',
           borderTopColor: 'rgba(20,20,20,0.95)',
          borderBottom: 'none',
         });
         });
         break;
         break;
Line 126: Line 114:
           transform: 'translateY(-50%) rotate(-90deg)',
           transform: 'translateY(-50%) rotate(-90deg)',
           borderTopColor: 'rgba(20,20,20,0.95)',
           borderTopColor: 'rgba(20,20,20,0.95)',
          borderBottom: 'none',
         });
         });
         break;
         break;
     }
     }


     // Kollision mit Viewport korrigieren
     // Clamp an Viewport
     if (left < 4) left = 4;
     if (left < 4) left = 4;
     if (left + ttRect.width > window.innerWidth - 4)
     if (left + ttRect.width > window.innerWidth - 4)
Line 141: Line 128:
     tooltip.style.top = top + 'px';
     tooltip.style.top = top + 'px';
     tooltip.style.left = left + 'px';
     tooltip.style.left = left + 'px';
    tooltip.style.opacity = '1';
    // Verstecken bei Mouseleave
    el.addEventListener('mouseleave', hideTooltip, { once: true });
  }
  function hideTooltip() {
    if (!activeEl) return;
    tooltip.style.opacity = '0';
    activeEl.setAttribute('title', storedTitle);
    activeEl = null;
    storedTitle = null;
   }
   }


   document.addEventListener('mouseover', showTooltip);
   document.addEventListener('mouseover', showTooltip);
})();
})();

Revision as of 23:51, 1 November 2025

/* Any JavaScript here will be loaded for all users on every page load. */
/* Schönes Tooltip-System auf Basis von alt-Attributen
   Funktioniert sicher mit Citizen & MediaWiki UI */

(function() {
  'use strict';

  const tooltip = document.createElement('div');
  tooltip.id = 'mw-smart-tooltip';
  Object.assign(tooltip.style, {
    position: 'absolute',
    zIndex: 999999,
    background: 'rgba(20,20,20,0.95)',
    color: '#fff',
    padding: '8px 12px',
    borderRadius: '6px',
    fontSize: '13px',
    lineHeight: '1.4',
    maxWidth: '220px',
    wordWrap: 'break-word',
    pointerEvents: 'none',
    opacity: '0',
    transition: 'opacity 0.2s, transform 0.15s',
  });
  document.body.appendChild(tooltip);

  const arrow = document.createElement('div');
  Object.assign(arrow.style, {
    position: 'absolute',
    width: '0',
    height: '0',
    borderLeft: '6px solid transparent',
    borderRight: '6px solid transparent',
    borderTop: '6px solid rgba(20,20,20,0.95)',
    pointerEvents: 'none',
  });
  tooltip.appendChild(arrow);

  let activeEl = null;
  let storedTitle = null;

  function showTooltip(e) {
    const el = e.target.closest('[title]');
    if (!el) return;
    storedTitle = el.getAttribute('title');
    if (!storedTitle) return;

    activeEl = el;
    el.removeAttribute('title'); // native verhindern

    // Tooltip vorbereiten, aber noch unsichtbar
    tooltip.textContent = storedTitle;
    tooltip.appendChild(arrow);
    tooltip.style.opacity = '0';
    tooltip.style.transform = 'translateY(0)';

    // Force Reflow um korrekte Größe zu bekommen
    tooltip.getBoundingClientRect();

    // Position berechnen
    const rect = el.getBoundingClientRect();
    const ttRect = tooltip.getBoundingClientRect();
    const spacing = 6;
    let top, left;

    const spaceAbove = rect.top;
    const spaceBelow = window.innerHeight - rect.bottom;
    const spaceRight = window.innerWidth - rect.right;
    const spaceLeft = rect.left;

    // Intelligente Position: genug Platz bevorzugen
    let position = 'bottom';
    if (spaceAbove > ttRect.height + spacing) position = 'top';
    else if (spaceRight > ttRect.width + spacing) position = 'right';
    else if (spaceLeft > ttRect.width + spacing) position = 'left';

    switch (position) {
      case 'top':
        top = rect.top - ttRect.height - spacing;
        left = rect.left + rect.width/2 - ttRect.width/2;
        Object.assign(arrow.style, {
          top: '100%',
          left: '50%',
          transform: 'translateX(-50%) rotate(0deg)',
          borderTopColor: 'rgba(20,20,20,0.95)',
        });
        break;
      case 'bottom':
        top = rect.bottom + spacing;
        left = rect.left + rect.width/2 - ttRect.width/2;
        Object.assign(arrow.style, {
          top: '-6px',
          left: '50%',
          transform: 'translateX(-50%) rotate(180deg)',
          borderTopColor: 'rgba(20,20,20,0.95)',
        });
        break;
      case 'right':
        top = rect.top + rect.height/2 - ttRect.height/2;
        left = rect.right + spacing;
        Object.assign(arrow.style, {
          top: '50%',
          left: '-6px',
          transform: 'translateY(-50%) rotate(90deg)',
          borderTopColor: 'rgba(20,20,20,0.95)',
        });
        break;
      case 'left':
        top = rect.top + rect.height/2 - ttRect.height/2;
        left = rect.left - ttRect.width - spacing;
        Object.assign(arrow.style, {
          top: '50%',
          left: '100%',
          transform: 'translateY(-50%) rotate(-90deg)',
          borderTopColor: 'rgba(20,20,20,0.95)',
        });
        break;
    }

    // Clamp an Viewport
    if (left < 4) left = 4;
    if (left + ttRect.width > window.innerWidth - 4)
      left = window.innerWidth - ttRect.width - 4;
    if (top < 4) top = 4;
    if (top + ttRect.height > window.innerHeight - 4)
      top = window.innerHeight - ttRect.height - 4;

    tooltip.style.top = top + 'px';
    tooltip.style.left = left + 'px';
    tooltip.style.opacity = '1';

    // Verstecken bei Mouseleave
    el.addEventListener('mouseleave', hideTooltip, { once: true });
  }

  function hideTooltip() {
    if (!activeEl) return;
    tooltip.style.opacity = '0';
    activeEl.setAttribute('title', storedTitle);
    activeEl = null;
    storedTitle = null;
  }

  document.addEventListener('mouseover', showTooltip);
})();
Cookies help us deliver our services. By using our services, you agree to our use of cookies.