Hinweis: Leere nach dem Veröffentlichen den Browser-Cache, um die Änderungen sehen zu können.

  • Firefox/Safari: Umschalttaste drücken und gleichzeitig Aktualisieren anklicken oder entweder Strg+F5 oder Strg+R (⌘+R auf dem Mac) drücken
  • Google Chrome: Umschalttaste+Strg+R (⌘+Umschalttaste+R auf dem Mac) drücken
  • Edge: Strg+F5 drücken oder Strg drücken und gleichzeitig Aktualisieren anklicken
/* Das folgende JavaScript wird für alle Benutzer geladen. */
/* =========================
   Site Announcement Modal
   =========================
   - Zeigt ein modales Popup einmal pro Tag pro Nutzer.
   - Mobilfreundlich (funktioniert mit Vector/Vector-2022/Minerva/Timeless).
   - Konfigurierbar über den CONFIG-Block.
   - Kein externes Framework nötig, nutzt jQuery (mit MediaWiki gebündelt).
*/

(function ($, mw) {
  'use strict';

  // ---- CONFIG ----
  var CONFIG = {
    enabled: true,                   // global an/aus
    id: 'site_announcement_v1',      // bei inhaltlicher Änderung erhöhen (z.B. v2), damit es wieder gezeigt wird
    title: 'Ankündigung',
    // HTML erlaubt. Halte es kurz & barrierearm.
    html: '<p>🎉 Nächste Woche Wartungsfenster: <strong>Di, 10:00–11:00</strong>. ' +
          'In dieser Zeit ist das Wiki nur eingeschränkt verfügbar.</p>' +
          '<p><a href="/wiki/Projekt:News" class="mw-ui-button">Mehr Infos</a></p>',
    showOnNamespaces: 'all',         // 'all' oder Array von NS-IDs, z.B. [0, 4]
    onlyForLoggedOut: false,         // nur für nicht angemeldete zeigen
    onlyForLoggedIn: false,          // nur für angemeldete zeigen
    startISO: null,                  // z.B. '2025-09-01T00:00:00Z' (null = sofort)
    endISO: null,                    // z.B. '2025-09-30T23:59:59Z' (null = kein Ende)
    dailyLimit: 1,                   // max. Anzeigen pro Kalendertag (idempotent, i.d.R. 1)
    closeBehavesAsShown: true,       // Schließen zählt als "heute bereits gesehen"
    escToClose: true,                // ESC schließt Modal
    clickBackdropToClose: true       // Klick auf Overlay schließt Modal
  };

  // ---- GUARD CLAUSES ----
  if (!CONFIG.enabled) return;
  if (mw.config.get('wgIsArticle') === false && mw.config.get('skin') === 'minerva') {
    // Minerva lädt Common.js teils auf Spezialseiten eingeschränkt – kein Modal auf reinen Spezialseiten nötig.
  }

  // Login-Filter
  var isAnon = mw.config.get('wgUserName') === null;
  if (CONFIG.onlyForLoggedOut && !isAnon) return;
  if (CONFIG.onlyForLoggedIn && isAnon) return;

  // Namespace-Filter
  var ns = mw.config.get('wgNamespaceNumber');
  if (CONFIG.showOnNamespaces !== 'all' && Array.isArray(CONFIG.showOnNamespaces) && CONFIG.showOnNamespaces.indexOf(ns) === -1) {
    return;
  }

  // Zeitfenster-Filter
  var now = new Date();
  if (CONFIG.startISO && now < new Date(CONFIG.startISO)) return;
  if (CONFIG.endISO && now > new Date(CONFIG.endISO)) return;

  // Storage-Helfer (mit Fallback)
  var storage = (function () {
    var prefix = 'mw_site_popup__';
    function safeGet(k) {
      try { return window.localStorage.getItem(prefix + k); } catch (e) { return null; }
    }
    function safeSet(k, v) {
      try { window.localStorage.setItem(prefix + k, v); } catch (e) { /* ignore */ }
    }
    return { get: safeGet, set: safeSet };
  })();

  // Schlüssel berechnen (pro Version + Nutzerstatus)
  var keyBase = CONFIG.id + (isAnon ? ':anon' : ':user');
  var lastShownKey = keyBase + ':lastShown';
  var countKey = keyBase + ':count:';
  var todayStr = (function (d) {
    // YYYY-MM-DD in Nutzer-Zeitzone
    var y = d.getFullYear();
    var m = String(d.getMonth() + 1).padStart(2, '0');
    var day = String(d.getDate()).padStart(2, '0');
    return y + '-' + m + '-' + day;
  })(now);

  var lastShown = storage.get(lastShownKey);
  var todayCount = parseInt(storage.get(countKey + todayStr) || '0', 10);

  // Bereits heute genug gezeigt?
  if (lastShown === todayStr && todayCount >= CONFIG.dailyLimit) {
    return;
  }

  // Modal-HTML erstellen
  function buildModal() {
    var $overlay = $('<div>', {
      class: 'mw-site-announcement-overlay',
      tabindex: '-1',
      'aria-hidden': 'true'
    });

    var $dialog = $('<div>', {
      class: 'mw-site-announcement-modal',
      role: 'dialog',
      'aria-modal': 'true',
      'aria-labelledby': 'mw-site-announcement-title'
    });

    var $header = $('<div>', { class: 'mw-site-announcement-header' })
      .append($('<h2>', { id: 'mw-site-announcement-title', text: CONFIG.title }));

    var $close = $('<button>', {
      type: 'button',
      class: 'mw-site-announcement-close',
      'aria-label': 'Schließen'
    }).text('×');

    var $content = $('<div>', { class: 'mw-site-announcement-content' }).html(CONFIG.html);

    var $footer = $('<div>', { class: 'mw-site-announcement-footer' });
    var $ok = $('<button>', {
      type: 'button',
      class: 'mw-ui-button mw-ui-progressive'
    }).text('OK');

    $header.append($close);
    $footer.append($ok);

    $dialog.append($header, $content, $footer);
    return { $overlay: $overlay, $dialog: $dialog, $ok: $ok, $close: $close };
  }

  function markShown() {
    storage.set(lastShownKey, todayStr);
    storage.set(countKey + todayStr, String((todayCount || 0) + 1));
  }

  function openModal() {
    var parts = buildModal();
    var $overlay = parts.$overlay, $dialog = parts.$dialog, $ok = parts.$ok, $close = parts.$close;

    $('body').append($overlay, $dialog);

    // Fokus steuern
    var previouslyFocused = document.activeElement;
    setTimeout(function () {
      $dialog.attr('tabindex', '-1').focus();
    }, 0);

    function close() {
      if (CONFIG.closeBehavesAsShown) {
        markShown();
      }
      $overlay.remove();
      $dialog.remove();
      if (previouslyFocused && previouslyFocused.focus) previouslyFocused.focus();
      $(document).off('keydown.mwSiteAnnouncement');
    }

    // Events
    $ok.on('click', function () {
      markShown();
      close();
    });
    $close.on('click', close);

    if (CONFIG.clickBackdropToClose) {
      $overlay.on('click', close);
    }

    if (CONFIG.escToClose) {
      $(document).on('keydown.mwSiteAnnouncement', function (e) {
        if (e.key === 'Escape') {
          e.preventDefault();
          close();
        }
      });
    }
  }

  // Beim DOM-Ready öffnen
  $(function () {
    openModal();
  });

})(jQuery, mediaWiki);