MediaWiki:Common.js: Unterschied zwischen den Versionen
Zur Navigation springen
Zur Suche springen
| Zeile 217: | Zeile 217: | ||
} | } | ||
}); | }); | ||
}); | |||
})(); | |||
/* global mw, $ */ | |||
(function () { | |||
'use strict'; | |||
$.when($.ready).then(function () { | |||
var STORAGE_KEY = 'wiki_consent_v1'; | |||
var defaults = { | |||
functional: true, // technisch notwendig (immer an, gesperrt) | |||
analytics: false, // z.B. Matomo/GA – optional | |||
media: false, // z.B. YouTube/Maps – optional | |||
marketing: false // z.B. Ads/Remarketing – optional | |||
}; | |||
// ---- Helpers ---- | |||
function loadState() { | |||
try { | |||
var raw = localStorage.getItem(STORAGE_KEY); | |||
if (!raw) return null; | |||
var obj = JSON.parse(raw); | |||
// safety: ensure all keys exist | |||
for (var k in defaults) if (!(k in obj)) obj[k] = defaults[k]; | |||
return obj; | |||
} catch(e) { return null; } | |||
} | |||
function saveState(state) { | |||
localStorage.setItem(STORAGE_KEY, JSON.stringify(state)); | |||
window.wikiConsent = state; // global verfügbar | |||
} | |||
function ensureState() { | |||
var s = loadState(); | |||
if (!s) { window.wikiConsent = defaults; return null; } | |||
window.wikiConsent = s; | |||
return s; | |||
} | |||
function createEl(tag, attrs, html) { | |||
var el = document.createElement(tag); | |||
if (attrs) for (var k in attrs) el.setAttribute(k, attrs[k]); | |||
if (html != null) el.innerHTML = html; | |||
return el; | |||
} | |||
// ---- UI: Banner ---- | |||
function showBar() { | |||
if (document.getElementById('consent-bar')) return; | |||
var bar = createEl('div', { id: 'consent-bar' }, | |||
'<div class="inner">' + | |||
'<div class="text">Wir verwenden <b>technisch notwendige Cookies</b> und – nach deiner Zustimmung – ' + | |||
'optional <b>Analyse</b> und <b>externe Medien</b>. ' + | |||
'<a href="/index.php?title=Datenschutz">Mehr erfahren</a></div>' + | |||
'<div class="btn-group">' + | |||
'<button class="btn secondary" id="consent-customize">Auswahl</button>' + | |||
'<button class="btn" id="consent-accept">Alle akzeptieren</button>' + | |||
'</div>' + | |||
'</div>' | |||
); | |||
document.body.appendChild(bar); | |||
bar.style.display = 'block'; | |||
document.getElementById('consent-customize').onclick = openModal; | |||
document.getElementById('consent-accept').onclick = function () { | |||
var all = { functional: true, analytics: true, media: true, marketing: true }; | |||
saveState(all); | |||
bar.remove(); | |||
applyConsent(all); | |||
}; | |||
} | |||
// ---- UI: Modal ---- | |||
function openModal() { | |||
if (document.getElementById('consent-modal')) return; | |||
var s = loadState() || defaults; | |||
var modal = createEl('div', { id: 'consent-modal' }); | |||
var html = | |||
'<div class="dialog">' + | |||
'<div class="head"><div><b>Datenschutz-Einstellungen</b></div>' + | |||
'<div><span class="badge">DSGVO</span></div></div>' + | |||
'<div class="body">' + | |||
row('Funktional', 'functional', s.functional, 'Erforderlich für Login, Sitzung, Seitendarstellung. (immer aktiv)', true) + | |||
row('Analyse', 'analytics', s.analytics, 'Anonyme Statistiken zur Verbesserung (z. B. Matomo/GA).') + | |||
row('Externe Medien', 'media', s.media, 'Einbettungen wie YouTube, Karten, Social-Posts.') + | |||
row('Marketing', 'marketing', s.marketing, 'Optionale Marketing-/Affiliate-Skripte.') + | |||
'</div>' + | |||
'<div class="foot">' + | |||
'<button class="btn secondary" id="consent-cancel">Abbrechen</button>' + | |||
'<button class="btn" id="consent-save">Auswahl speichern</button>' + | |||
'</div>' + | |||
'</div>'; | |||
modal.innerHTML = html; | |||
document.body.appendChild(modal); | |||
modal.style.display = 'flex'; | |||
document.getElementById('consent-cancel').onclick = function () { modal.remove(); }; | |||
document.getElementById('consent-save').onclick = function () { | |||
var state = { | |||
functional: true, | |||
analytics: !!document.getElementById('consent-analytics').checked, | |||
media: !!document.getElementById('consent-media').checked, | |||
marketing: !!document.getElementById('consent-marketing').checked | |||
}; | |||
saveState(state); | |||
modal.remove(); | |||
var bar = document.getElementById('consent-bar'); if (bar) bar.remove(); | |||
applyConsent(state); | |||
}; | |||
function row(label, key, checked, hint, locked) { | |||
var disabled = locked ? ' disabled' : ''; | |||
var isChecked = checked ? ' checked' : ''; | |||
var id = 'consent-' + key; | |||
return '' + | |||
'<div class="row">' + | |||
'<div>' + | |||
'<div class="name">' + label + (locked ? ' <span class="badge">immer aktiv</span>' : '') + '</div>' + | |||
'<div class="hint">' + hint + '</div>' + | |||
'</div>' + | |||
'<label class="switch" for="' + id + '">' + | |||
'<input type="checkbox" id="' + id + '"' + isChecked + disabled + '>' + | |||
'<span class="slider"></span>' + | |||
'</label>' + | |||
'</div>'; | |||
} | |||
} | |||
// ---- Hooks: Lade nur, wenn erlaubt ---- | |||
function applyConsent(state) { | |||
// Beispiel: Analytics (Matomo/GA) – lade NUR bei Zustimmung | |||
if (state.analytics) { | |||
// loadAnalytics(); // hier deine Analytics-Init-Funktion aufrufen | |||
} | |||
// Beispiel: Externe Medien – ersetze Platzhalter durch Iframes | |||
if (state.media) { | |||
enableEmbeds(); | |||
} | |||
// Beispiel: Marketing (derzeit nicht genutzt) | |||
if (state.marketing) { | |||
// loadMarketing(); // falls ihr mal was braucht | |||
} | |||
} | |||
// ---- Externe Einbettungen on-demand (Platzhalter -> echte Iframes) ---- | |||
function enableEmbeds() { | |||
var placeholders = document.querySelectorAll('[data-embed-src]'); | |||
for (var i = 0; i < placeholders.length; i++) { | |||
var ph = placeholders[i]; | |||
var src = ph.getAttribute('data-embed-src'); | |||
var iframe = document.createElement('iframe'); | |||
iframe.src = src; iframe.width = ph.getAttribute('data-embed-width') || '560'; | |||
iframe.height = ph.getAttribute('data-embed-height') || '315'; | |||
iframe.allowFullscreen = true; | |||
iframe.loading = 'lazy'; | |||
ph.parentNode.replaceChild(iframe, ph); | |||
} | |||
} | |||
// ---- Footer-Link „Cookie-Einstellungen“ (optional) ---- | |||
// Füge irgendwo auf einer Seite <span class="cookie-settings-link" id="cookie-settings-open">Cookie-Einstellungen</span> ein | |||
var settingsLink = document.getElementById('cookie-settings-open'); | |||
if (settingsLink) settingsLink.addEventListener('click', function () { openModal(); }); | |||
// ---- Init: Zustand laden/anzeigen ---- | |||
var current = ensureState(); | |||
if (!current) { | |||
// keine Entscheidung -> Banner zeigen | |||
showBar(); | |||
} else { | |||
applyConsent(current); | |||
} | |||
}); | }); | ||
})(); | })(); | ||
Version vom 7. November 2025, 22:19 Uhr
/* global mw, $ */
(function () {
'use strict';
$.when( mw.loader.using( [ 'mediawiki.api', 'mediawiki.util' ] ), $.ready ).then( function () {
// 1) Referenz-Portlet finden (Werkzeuge = p-tb). Daran hängen wir unseren Block direkt DARUNTER an.
var tools = document.getElementById('p-tb') || document.getElementById('p-navigation');
if ( !tools ) {
console.warn('[NewPages] Referenz-Portlet nicht gefunden.');
return;
}
// 2) Eigenen Portlet-Block erstellen – Klassen/Struktur von bestehendem Portlet ableiten
var block = document.createElement('div');
block.id = 'p-newpages';
// Klassen vom Werkzeuge-Portlet übernehmen (wirkt in Timeless/Vector/MonoBook sauber)
block.className = tools.className || 'mw-portlet';
// passende Überschrift (h3 oder h2 – je nach Skin) ermitteln
var headingTag = (tools.querySelector('h3,h2') || { tagName: 'H3' }).tagName;
var heading = document.createElement(headingTag);
heading.textContent = 'Neueste Beiträge';
// Body + UL wie bei anderen Portlets
var body = document.createElement('div');
body.className = 'body';
var list = document.createElement('ul');
body.appendChild(list);
block.appendChild(heading);
block.appendChild(body);
// Block direkt UNTERHALB von "Werkzeuge" einfügen
if (tools.insertAdjacentElement) {
tools.insertAdjacentElement('afterend', block);
} else if (tools.parentNode) {
tools.parentNode.insertBefore(block, tools.nextSibling);
}
// 3) Einträge via API laden
var api = new mw.Api();
api.get({
action: 'query',
list: 'recentchanges',
rctype: 'new',
rcprop: 'title|timestamp',
rcnamespace: 0, // nur Artikel
rcshow: '!bot|!redirect', // Bots & Weiterleitungen ausblenden
rclimit: 3,
format: 'json'
}).done(function (data) {
var items = (data.query && data.query.recentchanges) || [];
// Helper: <li><a/></li> hinzufügen
function addItem(href, text, title) {
var li = document.createElement('li');
var a = document.createElement('a');
a.href = href;
a.textContent = text;
if (title) a.title = title;
li.appendChild(a);
list.appendChild(li);
}
if (!items.length) {
addItem(mw.util.getUrl('Special:NewPages'), 'Keine neuen Seiten', 'Zur vollständigen Liste');
return;
}
for (var i = 0; i < items.length; i++) {
var rc = items[i];
var href = mw.util.getUrl(rc.title);
var tip = new Date(rc.timestamp).toLocaleString('de-DE', { dateStyle: 'medium', timeStyle: 'short' });
addItem(href, rc.title, tip);
}
// Abschluss-Link
addItem(mw.util.getUrl('Special:NewPages'), 'Alle neuen Seiten →', 'Zur vollständigen Liste');
}).fail(function (err) {
console.error('[NewPages] API-Fehler:', err);
var li = document.createElement('li');
li.textContent = 'Fehler beim Laden';
list.appendChild(li);
});
});
})();
/* global mw, $ */
(function () {
'use strict';
$.when( $.ready ).then(function () {
// 1) Mögliche Einfügepunkte (Timeless/Vector/MonoBook)
var content =
document.getElementById('mw-content-text') ||
document.getElementById('mw-content') ||
document.getElementById('bodyContent') ||
document.getElementById('content');
if (!content) {
console.warn('[ad-box] Kein Content-Container gefunden.');
return;
}
// Doppelt vermeiden
if (document.getElementById('ad-box')) {
console.log('[ad-box] existiert bereits');
return;
}
// 2) Box bauen
var box = document.createElement('aside');
box.id = 'ad-box';
box.setAttribute('role','complementary');
box.setAttribute('aria-label','Werbung');
// Notfall-Styles, falls Common.css noch nicht greift (damit du es SOFORT siehst)
box.style.cssText = 'float:right;width:300px;margin:0 0 1rem 1rem;background:#fffef7;border:1px solid #e5dfb3;border-radius:6px;box-shadow:0 1px 3px rgba(0,0,0,.06);font-size:90%;';
var header = document.createElement('div');
header.className = 'ad-header';
header.innerHTML = '<span class="ad-badge" style="background:#ffea9e;border:1px solid #e0c200;padding:2px 6px;border-radius:4px;font-weight:700;text-transform:uppercase;">Anzeige</span> <span style="font-weight:700;margin-left:.5em;">Unterstütze dieses Wiki</span>';
var body = document.createElement('div');
body.className = 'ad-body';
body.style.padding = '.6em .8em';
// 3) Amazon-URL dynamisch (Spamfilter umgehen)
var amazonHost = 'amazon.' + 'de';
var amazonBase = 'https://www.' + amazonHost + '/';
var partnerTag = 'rettungsdie00-21'; // <-- anpassen
var u = new URL(amazonBase);
u.searchParams.set('tag', partnerTag);
var amazonUrl = u.toString();
// 4) Inhalt
var html = '' +
'<ul style="list-style:none;margin:.2em 0;padding:0">' +
' <li style="margin:.35em 0"><a href="' + amazonUrl + '" target="_blank" rel="nofollow sponsored noopener noreferrer">Bei Amazon einkaufen (Affiliate)</a></li>' +
' <li style="margin:.35em 0"><a href="https://www.paypal.me/rettungsdienstblog" target="_blank" rel="nofollow noopener noreferrer">PayPal – jetzt unterstützen</a></li>' +
' <li style="margin:.35em 0"><a href="/index.php?title=Spezial:Zufällige_Seite">Zufälliger Artikel →</a></li>' +
'</ul>' +
'<div style="font-size:85%; color:#555; margin-top:.5em;">' +
' * Als Amazon-Partner verdienen wir an qualifizierten Verkäufen.' +
'</div>';
body.innerHTML = html;
box.appendChild(header);
box.appendChild(body);
// 5) Einfügen – zuerst im Content oben
try {
content.insertBefore(box, content.firstChild);
console.log('[ad-box] eingefügt in', content.id || content.className);
} catch (e) {
console.warn('[ad-box] insertBefore fehlgeschlagen, versuche Fallback:', e);
(content.appendChild || function(){ })(box);
}
// 6) Hard-Check: Wenn du ihn immer noch nicht siehst, als Test FIXIERT rechts oben einblenden
// Kommentiere die nächsten 5 Zeilen EIN, um zu testen:
/*
box.style.position = 'fixed';
box.style.right = '1rem';
box.style.top = '6rem';
box.style.zIndex = 1000;
console.log('[ad-box] testweise fixed positioniert');
*/
});
})();
/* global mw, $ */
(function () {
'use strict';
$.when($.ready).then(function () {
// Funktion, um festzustellen, ob Adblocker aktiv ist
function detectAdblocker(callback) {
var bait = document.createElement('div');
bait.className = 'adsbox ad-banner ad-unit text-ad'; // typische Adblocker-Keywords
bait.style.cssText = 'height:1px; width:1px; position:absolute; left:-9999px;';
document.body.appendChild(bait);
window.setTimeout(function () {
var blocked = !bait.offsetHeight || !bait.clientHeight;
document.body.removeChild(bait);
callback(blocked);
}, 300);
}
function showAdblockNotice() {
if (document.getElementById('adblock-hinweis')) return;
var div = document.createElement('div');
div.id = 'adblock-hinweis';
div.innerHTML =
'<button id="adblock-close">×</button>' +
'<strong>Hinweis:</strong> Wir finanzieren dieses Wiki durch Affiliate-Links und freiwillige Unterstützung. ' +
'Bitte deaktiviere deinen Adblocker für <b>' + window.location.hostname + '</b>, um uns zu unterstützen. ❤️';
document.body.appendChild(div);
div.style.display = 'block';
document.getElementById('adblock-close').onclick = function () {
div.remove();
};
}
// Nur zeigen, wenn Adblocker erkannt wird
detectAdblocker(function (isBlocked) {
if (isBlocked) {
// Optional: Nur einmal pro Nutzer (mit LocalStorage)
if (!localStorage.getItem('adblock_notice_shown')) {
showAdblockNotice();
localStorage.setItem('adblock_notice_shown', 'yes');
}
}
});
});
})();
/* global mw, $ */
(function () {
'use strict';
$.when($.ready).then(function () {
var STORAGE_KEY = 'wiki_consent_v1';
var defaults = {
functional: true, // technisch notwendig (immer an, gesperrt)
analytics: false, // z.B. Matomo/GA – optional
media: false, // z.B. YouTube/Maps – optional
marketing: false // z.B. Ads/Remarketing – optional
};
// ---- Helpers ----
function loadState() {
try {
var raw = localStorage.getItem(STORAGE_KEY);
if (!raw) return null;
var obj = JSON.parse(raw);
// safety: ensure all keys exist
for (var k in defaults) if (!(k in obj)) obj[k] = defaults[k];
return obj;
} catch(e) { return null; }
}
function saveState(state) {
localStorage.setItem(STORAGE_KEY, JSON.stringify(state));
window.wikiConsent = state; // global verfügbar
}
function ensureState() {
var s = loadState();
if (!s) { window.wikiConsent = defaults; return null; }
window.wikiConsent = s;
return s;
}
function createEl(tag, attrs, html) {
var el = document.createElement(tag);
if (attrs) for (var k in attrs) el.setAttribute(k, attrs[k]);
if (html != null) el.innerHTML = html;
return el;
}
// ---- UI: Banner ----
function showBar() {
if (document.getElementById('consent-bar')) return;
var bar = createEl('div', { id: 'consent-bar' },
'<div class="inner">' +
'<div class="text">Wir verwenden <b>technisch notwendige Cookies</b> und – nach deiner Zustimmung – ' +
'optional <b>Analyse</b> und <b>externe Medien</b>. ' +
'<a href="/index.php?title=Datenschutz">Mehr erfahren</a></div>' +
'<div class="btn-group">' +
'<button class="btn secondary" id="consent-customize">Auswahl</button>' +
'<button class="btn" id="consent-accept">Alle akzeptieren</button>' +
'</div>' +
'</div>'
);
document.body.appendChild(bar);
bar.style.display = 'block';
document.getElementById('consent-customize').onclick = openModal;
document.getElementById('consent-accept').onclick = function () {
var all = { functional: true, analytics: true, media: true, marketing: true };
saveState(all);
bar.remove();
applyConsent(all);
};
}
// ---- UI: Modal ----
function openModal() {
if (document.getElementById('consent-modal')) return;
var s = loadState() || defaults;
var modal = createEl('div', { id: 'consent-modal' });
var html =
'<div class="dialog">' +
'<div class="head"><div><b>Datenschutz-Einstellungen</b></div>' +
'<div><span class="badge">DSGVO</span></div></div>' +
'<div class="body">' +
row('Funktional', 'functional', s.functional, 'Erforderlich für Login, Sitzung, Seitendarstellung. (immer aktiv)', true) +
row('Analyse', 'analytics', s.analytics, 'Anonyme Statistiken zur Verbesserung (z. B. Matomo/GA).') +
row('Externe Medien', 'media', s.media, 'Einbettungen wie YouTube, Karten, Social-Posts.') +
row('Marketing', 'marketing', s.marketing, 'Optionale Marketing-/Affiliate-Skripte.') +
'</div>' +
'<div class="foot">' +
'<button class="btn secondary" id="consent-cancel">Abbrechen</button>' +
'<button class="btn" id="consent-save">Auswahl speichern</button>' +
'</div>' +
'</div>';
modal.innerHTML = html;
document.body.appendChild(modal);
modal.style.display = 'flex';
document.getElementById('consent-cancel').onclick = function () { modal.remove(); };
document.getElementById('consent-save').onclick = function () {
var state = {
functional: true,
analytics: !!document.getElementById('consent-analytics').checked,
media: !!document.getElementById('consent-media').checked,
marketing: !!document.getElementById('consent-marketing').checked
};
saveState(state);
modal.remove();
var bar = document.getElementById('consent-bar'); if (bar) bar.remove();
applyConsent(state);
};
function row(label, key, checked, hint, locked) {
var disabled = locked ? ' disabled' : '';
var isChecked = checked ? ' checked' : '';
var id = 'consent-' + key;
return '' +
'<div class="row">' +
'<div>' +
'<div class="name">' + label + (locked ? ' <span class="badge">immer aktiv</span>' : '') + '</div>' +
'<div class="hint">' + hint + '</div>' +
'</div>' +
'<label class="switch" for="' + id + '">' +
'<input type="checkbox" id="' + id + '"' + isChecked + disabled + '>' +
'<span class="slider"></span>' +
'</label>' +
'</div>';
}
}
// ---- Hooks: Lade nur, wenn erlaubt ----
function applyConsent(state) {
// Beispiel: Analytics (Matomo/GA) – lade NUR bei Zustimmung
if (state.analytics) {
// loadAnalytics(); // hier deine Analytics-Init-Funktion aufrufen
}
// Beispiel: Externe Medien – ersetze Platzhalter durch Iframes
if (state.media) {
enableEmbeds();
}
// Beispiel: Marketing (derzeit nicht genutzt)
if (state.marketing) {
// loadMarketing(); // falls ihr mal was braucht
}
}
// ---- Externe Einbettungen on-demand (Platzhalter -> echte Iframes) ----
function enableEmbeds() {
var placeholders = document.querySelectorAll('[data-embed-src]');
for (var i = 0; i < placeholders.length; i++) {
var ph = placeholders[i];
var src = ph.getAttribute('data-embed-src');
var iframe = document.createElement('iframe');
iframe.src = src; iframe.width = ph.getAttribute('data-embed-width') || '560';
iframe.height = ph.getAttribute('data-embed-height') || '315';
iframe.allowFullscreen = true;
iframe.loading = 'lazy';
ph.parentNode.replaceChild(iframe, ph);
}
}
// ---- Footer-Link „Cookie-Einstellungen“ (optional) ----
// Füge irgendwo auf einer Seite <span class="cookie-settings-link" id="cookie-settings-open">Cookie-Einstellungen</span> ein
var settingsLink = document.getElementById('cookie-settings-open');
if (settingsLink) settingsLink.addEventListener('click', function () { openModal(); });
// ---- Init: Zustand laden/anzeigen ----
var current = ensureState();
if (!current) {
// keine Entscheidung -> Banner zeigen
showBar();
} else {
applyConsent(current);
}
});
})();