MediaWiki:Common.js: Unterschied zwischen den Versionen

Aus CK-Wissen
Zur Navigation springen Zur Suche springen
Nachtmodus für alle: Schalter „Automatisch · Hell · Dunkel“ (Rechner oben rechts, Handy oben im Menü), Wahl im Browser gemerkt; ohne Wahl entscheidet die Einstellung des Geräts (MediaWiki:Common.css). Testbausteine entfernt, alte Testlinks funktionieren weiter.
Nachtmodus: Wahl zusätzlich im MediaWiki-Cookie merken (Klasse ckw-farbe-clientpref-…) – damit „Dunkel“ schon beim Laden greift, ohne Aufblitzen, sobald der Server die Grundklasse ausgibt; ohne sie wie bisher
Zeile 1: Zeile 1:
/* CK-Wissen (seit 25.09.2026): Nachtmodus.
/* CK-Wissen (seit 25.09.2026): Nachtmodus.
   Ohne Wahl richtet sich die Seite nach der Einstellung von Handy oder Rechner – das macht MediaWiki:Common.css allein
   Ohne Wahl richtet sich die Seite nach der Einstellung von Handy oder Rechner – das macht MediaWiki:Common.css allein
   (Block „Nachtmodus“, ohne Skript und ohne Aufblitzen). Dieses Skript zeigt den Schalter „Automatisch · Hell · Dunkel“
   (Block B, ohne Skript und ohne Aufblitzen). Dieses Skript zeigt den Schalter „Automatisch · Hell · Dunkel“
   (Rechner: oben rechts, Handy: oben im Menü ☰) und merkt sich eine Wahl im Browser (Klassen ckw-hell / ckw-nacht).
   (Rechner: oben rechts, Handy: oben im Menü ☰) und merkt sich eine Wahl an zwei Stellen:
  - im Browser-Speicher (localStorage „ckw-farbe“) – bleibt, solange niemand die Website-Daten löscht;
  - im Cookie von MediaWiki („…mwclientpreferences“, Eintrag ckw-farbe-clientpref-hell/-dunkel, 30 Tage, wird bei jedem
    Besuch erneuert). Dieses Cookie liest MediaWiki schon beim Laden und tauscht am <html> die Grundklasse
    ckw-farbe-clientpref-auto gegen die Wahl aus, bevor etwas zu sehen ist – ohne Aufblitzen. Die Grundklasse gibt der
    Server aus (LocalSettings.php, Block ckw-nachtmodus-2026), beim Bearbeiten nicht.
  Fehlt die Grundklasse, setzt dieses Skript wie bisher die Klassen ckw-nacht / ckw-hell (dann blitzt es kurz).
   Beim Bearbeiten bleibt die Seite hell. Alte Testlinks (&nachtmodus=test / aus) funktionieren weiter. */
   Beim Bearbeiten bleibt die Seite hell. Alte Testlinks (&nachtmodus=test / aus) funktionieren weiter. */
( function () {
( function () {
'use strict';
'use strict';
var SCHLUESSEL = 'ckw-farbe';
var SCHLUESSEL = 'ckw-farbe';
var KEKS = 'mwclientpreferences'; // mw.cookie ergänzt den Namen des Wikis davor
var WERTE = [ 'auto', 'hell', 'dunkel' ];
var html = document.documentElement;
var html = document.documentElement;
var bearbeiten = [ 'edit', 'submit' ].indexOf( mw.config.get( 'wgAction' ) ) !== -1;
var bearbeiten = [ 'edit', 'submit' ].indexOf( mw.config.get( 'wgAction' ) ) !== -1;


function gueltig( w ) { return WERTE.indexOf( w ) !== -1; }
// Wert der Klasse ckw-farbe-clientpref-… am <html> (null, wenn der Server die Grundklasse nicht ausgibt)
function klassenwert() {
var m = html.className.match( /(?:^|\s)ckw-farbe-clientpref-(\w+)(?=\s|$)/ );
return m ? m[ 1 ] : null;
}
function lesen() {
function lesen() {
try {
var w = null;
var w = localStorage.getItem( SCHLUESSEL );
try { w = localStorage.getItem( SCHLUESSEL ); } catch ( e ) {}
return w === 'hell' || w === 'dunkel' ? w : 'auto';
if ( gueltig( w ) ) { return w; }
} catch ( e ) { return 'auto'; }
w = klassenwert();
return gueltig( w ) ? w : 'auto';
}
// Cookie für MediaWiki: Einträge anderer Funktionen bleiben erhalten; „auto“ = kein Eintrag
function keks( w ) {
mw.loader.using( 'mediawiki.cookie' ).then( function () {
var alt = mw.cookie.get( KEKS ) || '';
var teile = alt.split( ',' ).filter( function ( t ) {
return /^[\w-]+-clientpref-\w+$/.test( t ) && t.indexOf( SCHLUESSEL + '-clientpref-' ) !== 0;
} );
if ( w !== 'auto' ) { teile.push( SCHLUESSEL + '-clientpref-' + w ); }
var neu = teile.join( ',' );
if ( neu !== alt || w !== 'auto' ) { mw.cookie.set( KEKS, neu || null ); }
} );
}
}
function merken( w ) {
function merken( w ) {
try {
try { localStorage.setItem( SCHLUESSEL, w ); } catch ( e ) {}
if ( w === 'auto' ) { localStorage.removeItem( SCHLUESSEL ); } else { localStorage.setItem( SCHLUESSEL, w ); }
keks( w );
} catch ( e ) {}
}
}
function anwenden( w ) {
function anwenden( w ) {
var k = klassenwert();
if ( k !== null && k !== w ) {
html.classList.remove( 'ckw-farbe-clientpref-' + k );
html.classList.add( 'ckw-farbe-clientpref-' + w );
}
html.classList.toggle( 'ckw-nacht', w === 'dunkel' && !bearbeiten );
html.classList.toggle( 'ckw-nacht', w === 'dunkel' && !bearbeiten );
html.classList.toggle( 'ckw-hell', w === 'hell' );
html.classList.toggle( 'ckw-hell', w === 'hell' );
Zeile 47: Zeile 78:
}
}
} catch ( e ) {}
} catch ( e ) {}
anwenden( lesen() );
var jetzt = lesen();
anwenden( jetzt );
keks( jetzt ); // Cookie anlegen, angleichen oder um 30 Tage verlängern


function schalter( lang ) {
function schalter( lang ) {

Version vom 25. September 2026, 15:46 Uhr

/* CK-Wissen (seit 25.09.2026): Nachtmodus.
   Ohne Wahl richtet sich die Seite nach der Einstellung von Handy oder Rechner – das macht MediaWiki:Common.css allein
   (Block B, ohne Skript und ohne Aufblitzen). Dieses Skript zeigt den Schalter „Automatisch · Hell · Dunkel“
   (Rechner: oben rechts, Handy: oben im Menü ☰) und merkt sich eine Wahl an zwei Stellen:
   - im Browser-Speicher (localStorage „ckw-farbe“) – bleibt, solange niemand die Website-Daten löscht;
   - im Cookie von MediaWiki („…mwclientpreferences“, Eintrag ckw-farbe-clientpref-hell/-dunkel, 30 Tage, wird bei jedem
     Besuch erneuert). Dieses Cookie liest MediaWiki schon beim Laden und tauscht am <html> die Grundklasse
     ckw-farbe-clientpref-auto gegen die Wahl aus, bevor etwas zu sehen ist – ohne Aufblitzen. Die Grundklasse gibt der
     Server aus (LocalSettings.php, Block ckw-nachtmodus-2026), beim Bearbeiten nicht.
   Fehlt die Grundklasse, setzt dieses Skript wie bisher die Klassen ckw-nacht / ckw-hell (dann blitzt es kurz).
   Beim Bearbeiten bleibt die Seite hell. Alte Testlinks (&nachtmodus=test / aus) funktionieren weiter. */
( function () {
	'use strict';
	var SCHLUESSEL = 'ckw-farbe';
	var KEKS = 'mwclientpreferences'; // mw.cookie ergänzt den Namen des Wikis davor
	var WERTE = [ 'auto', 'hell', 'dunkel' ];
	var html = document.documentElement;
	var bearbeiten = [ 'edit', 'submit' ].indexOf( mw.config.get( 'wgAction' ) ) !== -1;

	function gueltig( w ) { return WERTE.indexOf( w ) !== -1; }
	// Wert der Klasse ckw-farbe-clientpref-… am <html> (null, wenn der Server die Grundklasse nicht ausgibt)
	function klassenwert() {
		var m = html.className.match( /(?:^|\s)ckw-farbe-clientpref-(\w+)(?=\s|$)/ );
		return m ? m[ 1 ] : null;
	}
	function lesen() {
		var w = null;
		try { w = localStorage.getItem( SCHLUESSEL ); } catch ( e ) {}
		if ( gueltig( w ) ) { return w; }
		w = klassenwert();
		return gueltig( w ) ? w : 'auto';
	}
	// Cookie für MediaWiki: Einträge anderer Funktionen bleiben erhalten; „auto“ = kein Eintrag
	function keks( w ) {
		mw.loader.using( 'mediawiki.cookie' ).then( function () {
			var alt = mw.cookie.get( KEKS ) || '';
			var teile = alt.split( ',' ).filter( function ( t ) {
				return /^[\w-]+-clientpref-\w+$/.test( t ) && t.indexOf( SCHLUESSEL + '-clientpref-' ) !== 0;
			} );
			if ( w !== 'auto' ) { teile.push( SCHLUESSEL + '-clientpref-' + w ); }
			var neu = teile.join( ',' );
			if ( neu !== alt || w !== 'auto' ) { mw.cookie.set( KEKS, neu || null ); }
		} );
	}
	function merken( w ) {
		try { localStorage.setItem( SCHLUESSEL, w ); } catch ( e ) {}
		keks( w );
	}
	function anwenden( w ) {
		var k = klassenwert();
		if ( k !== null && k !== w ) {
			html.classList.remove( 'ckw-farbe-clientpref-' + k );
			html.classList.add( 'ckw-farbe-clientpref-' + w );
		}
		html.classList.toggle( 'ckw-nacht', w === 'dunkel' && !bearbeiten );
		html.classList.toggle( 'ckw-hell', w === 'hell' );
		Array.prototype.forEach.call( document.querySelectorAll( '.ckw-farbe button' ), function ( knopf ) {
			knopf.setAttribute( 'aria-pressed', knopf.value === w ? 'true' : 'false' );
		} );
	}

	// Aus der Testphase: Testlink und gemerkter Test-Schalter
	var wert = null;
	try { wert = new URLSearchParams( location.search ).get( 'nachtmodus' ); } catch ( e ) {}
	if ( wert !== null ) {
		if ( wert === 'test' || wert === 'an' ) { merken( 'dunkel' ); }
		if ( wert === 'aus' ) { merken( 'auto' ); }
		try {
			var sauber = new URL( location.href );
			sauber.searchParams.delete( 'nachtmodus' );
			history.replaceState( history.state, '', sauber.toString() );
		} catch ( e ) {}
	}
	try {
		if ( localStorage.getItem( 'ckw-nachtmodus-test' ) !== null ) {
			localStorage.removeItem( 'ckw-nachtmodus-test' );
			if ( localStorage.getItem( SCHLUESSEL ) === null ) { localStorage.setItem( SCHLUESSEL, 'dunkel' ); }
		}
	} catch ( e ) {}
	var jetzt = lesen();
	anwenden( jetzt );
	keks( jetzt ); // Cookie anlegen, angleichen oder um 30 Tage verlängern

	function schalter( lang ) {
		var gruppe = document.createElement( 'div' );
		gruppe.className = 'ckw-farbe';
		gruppe.setAttribute( 'role', 'group' );
		gruppe.setAttribute( 'aria-label', 'Darstellung' );
		[
			[ 'auto', lang ? 'Automatisch' : 'Auto', 'Wie am Gerät eingestellt' ],
			[ 'hell', 'Hell', 'Immer hell' ],
			[ 'dunkel', 'Dunkel', 'Immer dunkel (Nachtmodus)' ]
		].forEach( function ( o ) {
			var knopf = document.createElement( 'button' );
			knopf.type = 'button';
			knopf.value = o[ 0 ];
			knopf.textContent = o[ 1 ];
			knopf.title = o[ 2 ];
			knopf.addEventListener( 'click', function () { merken( o[ 0 ] ); anwenden( o[ 0 ] ); } );
			gruppe.appendChild( knopf );
		} );
		return gruppe;
	}

	$( function () {
		if ( mw.config.get( 'skin' ) === 'minerva' ) {
			var menue = document.getElementById( 'mw-mf-page-left' );
			if ( menue && !menue.querySelector( '.ckw-farbe-menue' ) ) {
				var box = document.createElement( 'div' );
				box.className = 'ckw-farbe-menue';
				var kopf = document.createElement( 'div' );
				kopf.className = 'ckw-farbe-kopf';
				kopf.textContent = 'Darstellung';
				box.appendChild( kopf );
				box.appendChild( schalter( true ) );
				var nav = menue.querySelector( '#p-navigation' );
				if ( nav ) { nav.parentNode.insertBefore( box, nav ); } else { menue.insertBefore( box, menue.firstChild ); }
			}
		} else {
			var liste = document.querySelector( '#p-personal ul' );
			if ( liste && !document.getElementById( 'pt-ckw-farbe' ) ) {
				var li = document.createElement( 'li' );
				li.id = 'pt-ckw-farbe';
				li.className = 'mw-list-item';
				li.appendChild( schalter( false ) );
				liste.insertBefore( li, liste.firstChild );
			}
		}
		anwenden( lesen() );
	} );

	// Wahl in einem anderen Tab geändert
	window.addEventListener( 'storage', function ( e ) {
		if ( e.key === SCHLUESSEL ) { anwenden( lesen() ); }
	} );
}() );

/* CK-Wissen (seit 24.09.2026): linke Leiste zum Aufklappen, „Auf dieser Seite“ rechts neben dem Text,
   Kleinigkeiten für die Lesespalte. Gestaltung dazu am Ende von MediaWiki:Common.css.
   Ohne Skript bleibt alles sichtbar (die Leiste geht nach 4 Sekunden von selbst auf). */
( function () {
	'use strict';

	var each = function ( liste, fn ) { Array.prototype.forEach.call( liste, fn ); };

	function titelAus( href ) {
		if ( !href ) { return null; }
		// nur einfache Seitenlinks (ohne &action=…, &oldid=… usw.)
		var m = href.match( /^[^?#]*\?title=([^&#]+)$/ ) || href.match( /\/index\.php\/([^?#]+)$/ );
		if ( !m ) { return null; }
		try { return decodeURIComponent( m[ 1 ] ).replace( / /g, '_' ); } catch ( e ) { return null; }
	}

	/* ---------- Linke Leiste ---------- */
	function leiste() {
		var panel = document.getElementById( 'mw-panel' );
		if ( !panel ) { return; }
		var hier = mw.config.get( 'wgPageName' );
		var SPEICHER = 'ckw-leiste';
		var gemerkt = {};
		try { gemerkt = JSON.parse( localStorage.getItem( SPEICHER ) || '{}' ) || {}; } catch ( e ) { gemerkt = {}; }
		var immerOffen = { 'p-navigation': true, 'p-Gegen_die_Attacke': true };

		each( panel.querySelectorAll( '.vector-menu-portal' ), function ( portal ) {
			var hatHier = false;
			each( portal.querySelectorAll( 'li > a' ), function ( a ) {
				if ( titelAus( a.getAttribute( 'href' ) ) === hier ) {
					a.parentNode.classList.add( 'ckw-hier' );
					a.setAttribute( 'aria-current', 'page' );
					hatHier = true;
				}
			} );
			if ( immerOffen[ portal.id ] ) { return; }
			var kopf = portal.querySelector( '.vector-menu-heading' );
			var inhalt = portal.querySelector( '.vector-menu-content' );
			if ( !kopf || !inhalt ) { return; }

			var anzahl = inhalt.querySelectorAll( 'li' ).length;
			if ( !inhalt.id ) { inhalt.id = portal.id + '-inhalt'; }
			var knopf = document.createElement( 'button' );
			knopf.type = 'button';
			knopf.className = 'ckw-klapp';
			knopf.setAttribute( 'aria-controls', inhalt.id );
			var text = document.createElement( 'span' );
			text.className = 'ckw-klapp-text';
			text.textContent = kopf.textContent.trim();
			var zahl = document.createElement( 'span' );
			zahl.className = 'ckw-klapp-zahl';
			zahl.textContent = String( anzahl );
			zahl.setAttribute( 'aria-hidden', 'true' );
			knopf.appendChild( text );
			knopf.appendChild( zahl );
			kopf.textContent = '';
			kopf.appendChild( knopf );

			var setze = function ( offen ) {
				knopf.setAttribute( 'aria-expanded', offen ? 'true' : 'false' );
				knopf.title = ( offen ? 'Zuklappen' : 'Aufklappen' ) + ' (' + anzahl + ' Seiten)';
				portal.classList.toggle( 'ckw-zu', !offen );
			};
			setze( hatHier || gemerkt[ portal.id ] === true );
			knopf.addEventListener( 'click', function () {
				var offen = knopf.getAttribute( 'aria-expanded' ) !== 'true';
				setze( offen );
				gemerkt[ portal.id ] = offen;
				try { localStorage.setItem( SPEICHER, JSON.stringify( gemerkt ) ); } catch ( e ) {}
			} );
		} );
		document.documentElement.classList.add( 'ckw-leiste-bereit' );
	}

	/* ---------- Lesespalte ---------- */
	function istLeseseite() {
		return mw.config.get( 'skin' ) === 'vector' &&
			mw.config.get( 'wgAction' ) === 'view' &&
			!mw.config.get( 'wgIsMainPage' ) &&
			[ 0, 1, 4, 5, 12 ].indexOf( mw.config.get( 'wgNamespaceNumber' ) ) !== -1;
	}

	function lesespalte( spalte ) {
		// Einleitung: erster Absatz vor der ersten Zwischenüberschrift, wenn er nicht zu lang ist
		var ersterAbsatz = null, kind = spalte.firstElementChild;
		while ( kind && kind.tagName !== 'H2' ) {
			if ( kind.tagName === 'P' && kind.textContent.trim().length > 40 ) { ersterAbsatz = kind; break; }
			kind = kind.nextElementSibling;
		}
		if ( ersterAbsatz && ersterAbsatz.textContent.length <= 650 ) { ersterAbsatz.classList.add( 'ckw-einleitung' ); }

		// Zu breite Tabellen seitlich schiebbar machen (nicht bei umflossenen Tabellen)
		each( spalte.querySelectorAll( 'table.wikitable' ), function ( t ) {
			if ( t.parentNode.classList.contains( 'ckw-tabelle' ) ) { return; }
			if ( window.getComputedStyle( t ).cssFloat !== 'none' ) { return; }
			var huelle = document.createElement( 'div' );
			huelle.className = 'ckw-tabelle';
			t.parentNode.insertBefore( huelle, t );
			huelle.appendChild( t );
		} );
	}

	/* ---------- „Auf dieser Seite“ ---------- */
	function seitennav( spalte ) {
		var toc = document.getElementById( 'toc' );
		var inhalt = document.getElementById( 'mw-content-text' );
		if ( !toc || !inhalt || !toc.querySelector( 'li.toclevel-1' ) ) { return; }

		var eintraege = [];
		var baue = function ( ul, ebene ) {
			var ol = document.createElement( 'ol' );
			each( ul.children, function ( li ) {
				var a = li.querySelector( ':scope > a' );
				if ( !a ) { return; }
				var neuLi = document.createElement( 'li' );
				var neuA = document.createElement( 'a' );
				neuA.href = a.getAttribute( 'href' );
				var t = a.querySelector( '.toctext' );
				neuA.textContent = ( t || a ).textContent;
				neuLi.appendChild( neuA );
				var ziel = null;
				try { ziel = document.getElementById( decodeURIComponent( neuA.hash.slice( 1 ) ) ); } catch ( e ) {}
				if ( ziel ) { eintraege.push( { a: neuA, li: neuLi, ziel: ziel.closest( 'h2, h3, h4' ) || ziel, ebene: ebene } ); }
				var unter = li.querySelector( ':scope > ul' );
				if ( unter && ebene < 2 ) { neuLi.appendChild( baue( unter, ebene + 1 ) ); }
				ol.appendChild( neuLi );
			} );
			return ol;
		};

		var nav = document.createElement( 'nav' );
		nav.className = 'ckw-seitennav';
		nav.setAttribute( 'aria-label', 'Auf dieser Seite' );
		var titel = document.createElement( 'div' );
		titel.className = 'ckw-seitennav-titel';
		titel.textContent = 'Auf dieser Seite';
		nav.appendChild( titel );
		nav.appendChild( baue( toc.querySelector( 'ul' ), 1 ) );
		var hoch = document.createElement( 'a' );
		hoch.href = '#top';
		hoch.className = 'ckw-nach-oben';
		hoch.textContent = 'Nach oben';
		nav.appendChild( hoch );
		inhalt.appendChild( nav );
		document.body.classList.add( 'ckw-mit-seitennav' );

		// Mitlaufende Markierung: welcher Abschnitt ist gerade zu sehen?
		var aktiv = null, geplant = false;
		var markiere = function () {
			geplant = false;
			if ( window.getComputedStyle( nav ).display === 'none' ) { return; }
			var neu = null;
			for ( var i = 0; i < eintraege.length; i++ ) {
				if ( eintraege[ i ].ziel.getBoundingClientRect().top <= 120 ) { neu = eintraege[ i ]; } else { break; }
			}
			if ( neu === aktiv ) { return; }
			each( nav.querySelectorAll( '.ckw-aktiv' ), function ( x ) { x.classList.remove( 'ckw-aktiv' ); } );
			each( nav.querySelectorAll( '.ckw-offen' ), function ( x ) { x.classList.remove( 'ckw-offen' ); } );
			aktiv = neu;
			if ( !neu ) { return; }
			neu.a.classList.add( 'ckw-aktiv' );
			var li = neu.li;
			while ( li && li !== nav ) {
				if ( li.tagName === 'LI' ) { li.classList.add( 'ckw-offen' ); }
				li = li.parentNode;
			}
			// Markierten Eintrag in der Liste sichtbar halten, ohne die Seite zu verschieben
			var oben = neu.a.offsetTop, unten = oben + neu.a.offsetHeight;
			if ( oben < nav.scrollTop + 40 ) { nav.scrollTop = Math.max( 0, oben - 60 ); }
			else if ( unten > nav.scrollTop + nav.clientHeight - 40 ) { nav.scrollTop = unten - nav.clientHeight + 60; }
		};
		var plane = function () {
			if ( !geplant ) { geplant = true; window.requestAnimationFrame( markiere ); }
		};
		window.addEventListener( 'scroll', plane, { passive: true } );
		window.addEventListener( 'resize', plane );
		markiere();
	}

	$( function () {
		// Themen der Leiste für „Weiter im Thema“ melden (vor dem Umbau der Überschriften)
		try {
			var panel = document.getElementById( 'mw-panel' ), gruppen = [];
			each( panel ? panel.querySelectorAll( '.vector-menu-portal' ) : [], function ( p ) {
				if ( p.id === 'p-tb' ) { return; }
				var kopf = p.querySelector( '.vector-menu-heading' ), links = [];
				each( p.querySelectorAll( 'li > a' ), function ( a ) {
					var text = a.textContent.trim(), href = a.getAttribute( 'href' );
					if ( text && href ) { links.push( [ text, href ] ); }
				} );
				if ( links.length ) { gruppen.push( { id: p.id, label: kopf ? kopf.textContent.trim() : '', links: links } ); }
			} );
			if ( gruppen.length ) { mw.hook( 'ckw.themen' ).fire( gruppen ); }
		} catch ( e ) { mw.log.warn( 'CK-Wissen Themen:', e ); }
		try { leiste(); } catch ( e ) {
			document.documentElement.classList.add( 'ckw-leiste-offen' );
			mw.log.warn( 'CK-Wissen Leiste:', e );
		}
		if ( !istLeseseite() ) { return; }
		var spalte = document.querySelector( '#mw-content-text > .mw-parser-output' );
		if ( !spalte ) { return; }
		try { lesespalte( spalte ); } catch ( e ) { mw.log.warn( 'CK-Wissen Lesespalte:', e ); }
		try { seitennav( spalte ); } catch ( e ) { mw.log.warn( 'CK-Wissen Seitennavigation:', e ); }
	} );
}() );

/* CK-Wissen (seit 24.09.2026): Handy-Ansicht – alle Themen der linken Leiste im Menü (☰) und unten auf jeder Seite,
   „Gegen die Attacke“ dort aufgeklappt gleich nach „Start“. Oben auf den Seiten steht seit 25.09.2026 kein
   Akut-Kasten mehr: In einer Attacke kann man kaum lesen, oben soll zuerst der Text der Seite kommen.
   Die Themen kommen automatisch aus MediaWiki:Sidebar: Das Skript liest die Desktop-Leiste einer
   leeren Seite und merkt sie sich im Browser für 12 Stunden. Gestaltung am Ende von MediaWiki:Common.css. */
( function () {
	'use strict';
	if ( mw.config.get( 'skin' ) !== 'minerva' ) { return; }

	var SPEICHER = 'ckw-themen-v2'; // v2 seit 25.09.2026: neue Gruppennamen der Leiste sofort zeigen
	try { localStorage.removeItem( 'ckw-themen-v1' ); } catch ( e ) {}
	var HALTBAR = 12 * 60 * 60 * 1000;
	var skript = mw.config.get( 'wgScript' );
	var hier = mw.config.get( 'wgPageName' );
	var istInhalt = mw.config.get( 'wgAction' ) === 'view' &&
		mw.config.get( 'wgNamespaceNumber' ) >= 0 &&
		!mw.config.get( 'wgIsMainPage' );

	function titelAus( href ) {
		if ( !href ) { return null; }
		var m = href.match( /^[^?#]*\?title=([^&#]+)$/ ) || href.match( /\/index\.php\/([^?#]+)$/ );
		if ( !m ) { return null; }
		try { return decodeURIComponent( m[ 1 ] ).replace( / /g, '_' ); } catch ( e ) { return null; }
	}

	function el( tag, klasse, text ) {
		var e = document.createElement( tag );
		if ( klasse ) { e.className = klasse; }
		if ( text ) { e.textContent = text; }
		return e;
	}

	function verweis( paar ) {
		var a = el( 'a', null, paar[ 0 ] );
		a.href = paar[ 1 ];
		if ( titelAus( paar[ 1 ] ) === hier ) {
			a.className = 'ckw-hier';
			a.setAttribute( 'aria-current', 'page' );
		}
		return a;
	}

	function gruppenBlock( gruppen, klasse ) {
		var box = el( 'div', klasse );
		gruppen.forEach( function ( g ) {
			var liste = el( 'ul' ), hatHier = false;
			g.links.forEach( function ( paar ) {
				var li = el( 'li' );
				var a = verweis( paar );
				if ( a.className === 'ckw-hier' ) { hatHier = true; }
				li.appendChild( a );
				liste.appendChild( li );
			} );
			if ( g.id === 'p-navigation' ) {
				var start = el( 'div', 'ckw-gruppe ckw-gruppe-start' );
				start.appendChild( liste );
				box.appendChild( start );
				return;
			}
			var akut = g.id === 'p-Gegen_die_Attacke';
			var d = el( 'details', 'ckw-gruppe' + ( akut ? ' ckw-gruppe-akut' : '' ) );
			d.open = akut || hatHier;
			var s = el( 'summary' );
			s.appendChild( el( 'span', 'ckw-gruppe-name', g.label ) );
			var zahl = el( 'span', 'ckw-gruppe-zahl', String( g.links.length ) );
			zahl.setAttribute( 'aria-hidden', 'true' );
			s.appendChild( zahl );
			d.appendChild( s );
			d.appendChild( liste );
			box.appendChild( d );
		} );
		return box;
	}

	function zeigen( gruppen ) {
		// Menü (☰): Themen nach „Start“ und „Zufällige Seite“
		var menue = document.getElementById( 'mw-mf-page-left' );
		if ( menue ) {
			var altM = menue.querySelector( '.ckw-menue-themen' );
			if ( altM ) { altM.parentNode.removeChild( altM ); }
			var themenM = gruppenBlock( gruppen.filter( function ( g ) { return g.id !== 'p-navigation'; } ), 'ckw-menue-themen' );
			var nav = menue.querySelector( '#p-navigation' );
			if ( nav ) { nav.parentNode.insertBefore( themenM, nav.nextSibling ); } else { menue.appendChild( themenM ); }
		}

		// Unten auf der Seite: alle Themen
		var haupt = document.getElementById( 'content' );
		if ( istInhalt && haupt ) {
			var altU = document.querySelector( '.ckw-mobil-themen' );
			if ( altU ) { altU.parentNode.removeChild( altU ); }
			var unten = el( 'nav', 'ckw-mobil-themen' );
			unten.setAttribute( 'aria-labelledby', 'ckw-mobil-themen-titel' );
			var h = el( 'h2', 'ckw-mobil-themen-titel', 'Themen' );
			h.id = 'ckw-mobil-themen-titel';
			unten.appendChild( h );
			unten.appendChild( gruppenBlock( gruppen, 'ckw-mobil-themen-liste' ) );
			haupt.appendChild( unten );
		}
		mw.hook( 'ckw.themen' ).fire( gruppen );
	}

	function ausLeiste( html ) {
		var doc = new DOMParser().parseFromString( html, 'text/html' );
		var gruppen = [];
		Array.prototype.forEach.call( doc.querySelectorAll( '#mw-panel .vector-menu-portal' ), function ( p ) {
			if ( p.id === 'p-tb' ) { return; }
			var kopf = p.querySelector( '.vector-menu-heading' );
			var links = [];
			Array.prototype.forEach.call( p.querySelectorAll( 'li > a' ), function ( a ) {
				var text = a.textContent.trim(), href = a.getAttribute( 'href' );
				if ( text && href ) { links.push( [ text, href ] ); }
			} );
			if ( links.length ) { gruppen.push( { id: p.id, label: kopf ? kopf.textContent.trim() : '', links: links } ); }
		} );
		return gruppen;
	}

	$( function () {
		try {
			var gemerkt = null;
			try { gemerkt = JSON.parse( localStorage.getItem( SPEICHER ) || 'null' ); } catch ( e ) {}
			if ( gemerkt && gemerkt.gruppen && Date.now() - gemerkt.zeit < HALTBAR ) {
				zeigen( gemerkt.gruppen );
				return;
			}
			fetch( skript + '?title=Special:BlankPage&useskin=vector&useformat=desktop', { credentials: 'omit' } )
				.then( function ( r ) { return r.ok ? r.text() : Promise.reject( r.status ); } )
				.then( function ( html ) {
					var gruppen = ausLeiste( html );
					if ( !gruppen.length ) { return; }
					try { localStorage.setItem( SPEICHER, JSON.stringify( { zeit: Date.now(), gruppen: gruppen } ) ); } catch ( e ) {}
					zeigen( gruppen );
				} )
				.catch( function () {
					if ( gemerkt && gemerkt.gruppen ) { zeigen( gemerkt.gruppen ); }
				} );
		} catch ( e ) {
			mw.log.warn( 'CK-Wissen Handy-Navigation:', e );
		}
	} );
}() );

/* CK-Wissen (seit 25.09.2026): „Weiter im Thema“ am Ende jedes Artikels – vorherige und nächste Seite
   aus derselben Gruppe der linken Leiste (MediaWiki:Sidebar), am Rechner und auf dem Handy.
   Steht vor „Siehe auch“, „Literatur“, „Weblinks“ bzw. „Einzelnachweise“, sonst am Ende des Textes. */
( function () {
	'use strict';
	var ENDE = /^(Siehe auch|Literatur|Weblinks|Externe Links|Einzelnachweise|Quellen|Belege|Referenzen|Fußnoten|Anmerkungen)\b/i;

	function titelAus( href ) {
		if ( !href ) { return null; }
		var m = href.match( /^[^?#]*\?title=([^&#]+)$/ ) || href.match( /\/index\.php\/([^?#]+)$/ );
		if ( !m ) { return null; }
		try { return decodeURIComponent( m[ 1 ] ).replace( / /g, '_' ); } catch ( e ) { return null; }
	}

	function el( tag, klasse, text ) {
		var e = document.createElement( tag );
		if ( klasse ) { e.className = klasse; }
		if ( text ) { e.textContent = text; }
		return e;
	}

	function karte( paar, richtung, klasse ) {
		var a = el( 'a', 'ckw-weiter-karte ' + klasse );
		a.href = paar[ 1 ];
		a.appendChild( el( 'span', 'ckw-weiter-richtung', richtung ) );
		a.appendChild( el( 'span', 'ckw-weiter-titel', paar[ 0 ] ) );
		return a;
	}

	function weiter( gruppen ) {
		if ( mw.config.get( 'wgAction' ) !== 'view' || mw.config.get( 'wgIsMainPage' ) ||
			mw.config.get( 'wgNamespaceNumber' ) < 0 ||
			mw.config.get( 'wgRevisionId' ) !== mw.config.get( 'wgCurRevisionId' ) ) { return; }
		var namen = [ mw.config.get( 'wgPageName' ) ];
		if ( mw.config.get( 'wgRedirectedFrom' ) ) { namen.push( String( mw.config.get( 'wgRedirectedFrom' ) ).replace( / /g, '_' ) ); }
		var spalte = document.querySelector( '#mw-content-text > .mw-parser-output' );
		if ( !spalte ) { return; }

		var gruppe = null, liste = null, stelle = -1;
		gruppen.some( function ( g ) {
			if ( g.id === 'p-navigation' ) { return false; }
			var seiten = g.links.filter( function ( p ) {
				var t = titelAus( p[ 1 ] );
				return t && !/^(Spezial|Special):/.test( t );
			} );
			for ( var i = 0; i < seiten.length; i++ ) {
				if ( namen.indexOf( titelAus( seiten[ i ][ 1 ] ) ) !== -1 ) { gruppe = g; liste = seiten; stelle = i; return true; }
			}
			return false;
		} );
		if ( !gruppe || liste.length < 2 ) { return; }

		var alt = spalte.querySelector( '.ckw-weiter' );
		if ( alt ) { alt.parentNode.removeChild( alt ); }
		var nav = el( 'nav', 'ckw-weiter' );
		nav.setAttribute( 'aria-label', 'Weiter im Thema ' + gruppe.label );
		var kopf = el( 'div', 'ckw-weiter-kopf', 'Weiter im Thema ' );
		kopf.appendChild( el( 'b', null, gruppe.label ) );
		kopf.appendChild( document.createTextNode( ' ' ) );
		kopf.appendChild( el( 'span', 'ckw-weiter-stelle', '· Seite ' + ( stelle + 1 ) + ' von ' + liste.length ) );
		nav.appendChild( kopf );
		var karten = el( 'div', 'ckw-weiter-karten' );
		if ( stelle > 0 ) { karten.appendChild( karte( liste[ stelle - 1 ], '← Zurück', 'ckw-weiter-zurueck' ) ); }
		if ( stelle < liste.length - 1 ) { karten.appendChild( karte( liste[ stelle + 1 ], 'Weiter →', 'ckw-weiter-vor' ) ); }
		else if ( stelle >= 2 ) { karten.appendChild( karte( liste[ 0 ], 'Zum Anfang des Themas ↺', 'ckw-weiter-vor' ) ); }
		nav.appendChild( karten );

		// Vor „Siehe auch“, „Literatur“, „Einzelnachweise“ … einsetzen, sonst ans Ende
		var ziel = null;
		Array.prototype.some.call( spalte.querySelectorAll( 'h2' ), function ( h ) {
			if ( h.parentNode !== spalte ) { return false; }
			var t = ( h.querySelector( '.mw-headline' ) || h ).textContent.trim();
			if ( ENDE.test( t ) ) { ziel = h; return true; }
			return false;
		} );
		if ( ziel ) { spalte.insertBefore( nav, ziel ); } else { spalte.appendChild( nav ); }
	}

	mw.hook( 'ckw.themen' ).add( function ( gruppen ) {
		try { weiter( gruppen ); } catch ( e ) { mw.log.warn( 'CK-Wissen Weiter im Thema:', e ); }
	} );
}() );

/* CK-Wissen (seit 25.09.2026): Tabellen, die nicht in die Seitenbreite passen, werden als Karten gezeigt.
   Jede Zeile wird eine Karte, die Spaltenüberschriften stehen als kleine Beschriftung über jedem Wert.
   Passt die Tabelle in die Breite, bleibt sie eine Tabelle. Gilt am Rechner und am Handy und prüft neu,
   wenn sich die Breite ändert oder ein zugeklappter Abschnitt aufgeht. Nur für einfache Tabellen mit
   Kopfzeile und ohne zusammengefasste Zellen (Zwischenüberschriften über die ganze Breite gehen). Abschalten für eine Tabelle: class="wikitable ckw-nie-karten".
   Die Gestaltung steht in MediaWiki:Common.css unter „Zu breite Tabellen als Karten“. */
( function () {
	'use strict';
	if ( mw.config.get( 'wgAction' ) !== 'view' ) { return; }

	function geeignet( t ) {
		if ( t.classList.contains( 'ckw-nie-karten' ) || t.classList.contains( 'ckw-karten-bereit' ) ) { return false; }
		if ( t.querySelector( 'table' ) || ( t.parentElement && t.parentElement.closest( 'table' ) ) ) { return false; }
		var zeilen = t.rows;
		if ( zeilen.length < 2 ) { return false; }
		var kopf = zeilen[ 0 ].cells;
		if ( kopf.length < 2 ) { return false; }
		for ( var i = 0; i < kopf.length; i++ ) {
			if ( kopf[ i ].tagName !== 'TH' || kopf[ i ].colSpan > 1 || kopf[ i ].rowSpan > 1 ) { return false; }
		}
		for ( var z = 1; z < zeilen.length; z++ ) {
			var zellen = zeilen[ z ].cells;
			// Zwischenüberschrift über die ganze Breite: wird in der Kartenansicht zur Überschrift
			if ( zellen.length === 1 && zellen[ 0 ].colSpan === kopf.length && zellen[ 0 ].rowSpan === 1 ) { continue; }
			if ( zellen.length !== kopf.length ) { return false; }
			for ( var k = 0; k < zellen.length; k++ ) {
				if ( zellen[ k ].colSpan > 1 || zellen[ k ].rowSpan > 1 ) { return false; }
			}
		}
		return true;
	}

	function beschrifte( t ) {
		var kopf = t.rows[ 0 ].cells;
		t.rows[ 0 ].classList.add( 'ckw-karten-kopf' );
		for ( var z = 1; z < t.rows.length; z++ ) {
			var zellen = t.rows[ z ].cells;
			if ( zellen.length === 1 && zellen[ 0 ].colSpan > 1 ) { t.rows[ z ].classList.add( 'ckw-karten-gruppe' ); continue; }
			for ( var k = 0; k < zellen.length; k++ ) {
				var name = kopf[ k ].textContent.replace( /\[\d+\]/g, '' ).replace( /\s+/g, ' ' ).trim();
				zellen[ k ].setAttribute( 'data-ckw-spalte', name );
				if ( !zellen[ k ].textContent.trim() && !zellen[ k ].querySelector( 'img' ) ) { zellen[ k ].classList.add( 'ckw-karten-leer' ); }
			}
		}
		t.classList.add( 'ckw-karten-bereit' );
	}

	function pruefe( t ) {
		var huelle = t.parentElement;
		if ( !huelle ) { return; }
		var platz = huelle.clientWidth;
		if ( !platz ) { return; } // unsichtbar, etwa in einem zugeklappten Abschnitt
		var war = t.classList.contains( 'ckw-karten' );
		if ( war ) { t.classList.remove( 'ckw-karten' ); }
		var zuBreit = t.scrollWidth > platz + 2;
		if ( zuBreit ) { t.classList.add( 'ckw-karten' ); }
		if ( huelle.classList.contains( 'ckw-tabelle' ) ) { huelle.classList.toggle( 'ckw-tabelle-karten', zuBreit ); }
	}

	function einrichten( wurzel ) {
		var tabellen = [];
		var liste = wurzel.querySelectorAll( '.mw-parser-output table.wikitable' );
		for ( var i = 0; i < liste.length; i++ ) {
			if ( geeignet( liste[ i ] ) ) { beschrifte( liste[ i ] ); tabellen.push( liste[ i ] ); }
		}
		if ( !tabellen.length ) { return; }
		var alle = function () { tabellen.forEach( pruefe ); };
		alle();
		if ( window.ResizeObserver ) {
			var breiten = new Map();
			var ro = new ResizeObserver( function ( eintraege ) {
				eintraege.forEach( function ( e ) {
					var b = Math.round( e.contentRect.width );
					if ( breiten.get( e.target ) === b ) { return; }
					breiten.set( e.target, b );
					tabellen.forEach( function ( t ) { if ( t.parentElement === e.target ) { pruefe( t ); } } );
				} );
			} );
			tabellen.forEach( function ( t ) { if ( t.parentElement ) { ro.observe( t.parentElement ); } } );
		} else {
			var warte;
			window.addEventListener( 'resize', function () { clearTimeout( warte ); warte = setTimeout( alle, 200 ); } );
		}
	}

	window.ckwTabellenAlsKarten = einrichten;
	// Immer die ganze Seite prüfen: Andere Skripte melden über denselben Haken auch kleine eingefügte Teile,
	// und ein später angemeldeter Empfänger bekommt nur die letzte Meldung. Bereits erledigte Tabellen werden übersprungen.
	var spaeter = function () { setTimeout( function () { einrichten( document ); }, 0 ); };
	mw.hook( 'wikipage.content' ).add( spaeter );
	$( spaeter );
}() );