MediaWiki:Common.js
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);