Nota: dopo aver pubblicato, potrebbe essere necessario pulire la cache del proprio browser per vedere i cambiamenti.

  • Firefox / Safari: tieni premuto il tasto delle maiuscole Shift e fai clic su Ricarica, oppure premi Ctrl-F5 o Ctrl-R (⌘-R su Mac)
  • Google Chrome: premi Ctrl-Shift-R (⌘-Shift-R su un Mac)
  • Edge: tieni premuto il tasto Ctrl e fai clic su Aggiorna, oppure premi Ctrl-F5.
/*
 * Colonna destra di Vector 2022: due riquadri, sotto il menu Aspetto quando è fissato nella
 * colonna, da soli quando non lo è (il caso predefinito).
 *
 * Sorgente nel repo: wiki/bozze/MediaWiki_Vector-2022.js.wiki; scelte e prove in
 * wiki/tema/README.md, «Colonna destra». Lo stile è in MediaWiki:Vector-2022.css.
 *
 * - «In questa pagina»: data dell'ultima revisione sostanziale (dalla riga del template
 *   Ultimo aggiornamento, classe esn-aggiornamento), avviso se la pagina ha il riquadro del
 *   template Da verificare, numero di fonti (classe esn-fonte), categorie, «Segnala un errore».
 *   Solo pagine di contenuto (namespace 0), non sulla Pagina principale.
 * - «Pagine collegate»: le altre pagine della prima categoria di contenuto della pagina.
 *   Anche questa solo nel namespace 0, non sulla Pagina principale.
 *
 * La larghezza della colonna la riserva MediaWiki:Vector-2022.css sulle stesse pagine (classi
 * del body), così il testo non si sposta quando lo script aggiunge i riquadri.
 *
 * Solo Vector 2022 (questa pagina la carica solo quella skin): Minerva non ha colonna destra.
 * Nei commenti i template si nominano senza graffe (vedi Common.css).
 * Sintassi ES2015 (const, let, funzioni freccia): niente async né operatori ?. e ??.
 */
( function () {
	'use strict';

	// Categorie di servizio: non dicono di che cosa parla la pagina.
	const CATEGORIE_DI_SERVIZIO = [ 'Da verificare', 'Wiki', 'Pagine che richiamano file inesistenti' ];
	const MAX_COLLEGATE = 8;
	const MESI = [ 'gennaio', 'febbraio', 'marzo', 'aprile', 'maggio', 'giugno', 'luglio', 'agosto',
		'settembre', 'ottobre', 'novembre', 'dicembre' ];

	const conf = mw.config.get( [ 'wgAction', 'wgNamespaceNumber', 'wgIsMainPage', 'wgPageName',
		'wgTitle', 'wgCategories', 'wgIsRedirect', 'wgArticleId' ] );

	if ( conf.wgAction !== 'view' || conf.wgNamespaceNumber !== 0 || conf.wgIsMainPage ) {
		return;
	}
	if ( conf.wgIsRedirect || !( conf.wgArticleId > 0 ) ) {
		// Pagina inesistente o redirect: il CSS ha riservato la colonna, la si restituisce.
		document.documentElement.classList.add( 'esn-senza-colonna' );
		return;
	}

	function el( tag, attrs, figli ) {
		const e = document.createElement( tag );
		Object.keys( attrs || {} ).forEach( ( k ) => e.setAttribute( k, attrs[ k ] ) );
		( figli || [] ).forEach( ( f ) => e.append( f ) );
		return e;
	}

	function riquadro( id, titolo, colore ) {
		const h = el( 'h2', { class: 'esn-colonna-titolo', id: id + '-titolo' }, [ titolo ] );
		return el( 'section', { class: 'esn-colonna-riquadro esn-colonna-' + colore, id: id,
			'aria-labelledby': id + '-titolo' }, [ h ] );
	}

	function link( titolo, testo ) {
		return el( 'a', { href: mw.util.getUrl( titolo ), title: titolo }, [ testo || titolo ] );
	}

	function dataItaliana( iso ) {
		const m = /^(\d{4})-(\d{2})-(\d{2})$/.exec( iso );
		if ( !m || +m[ 2 ] < 1 || +m[ 2 ] > 12 ) {
			return iso;
		}
		return +m[ 3 ] + ' ' + MESI[ +m[ 2 ] - 1 ] + ' ' + m[ 1 ];
	}

	function categorieDiContenuto() {
		return ( conf.wgCategories || [] ).filter( ( c ) => CATEGORIE_DI_SERVIZIO.indexOf( c ) < 0 );
	}

	// «In questa pagina»
	function inQuestaPagina() {
		const corpo = document.querySelector( '#mw-content-text .mw-parser-output' );
		if ( !corpo ) {
			return null;
		}
		const box = riquadro( 'esn-in-questa-pagina', 'In questa pagina', 'ciano' );
		const righe = el( 'ul', { class: 'esn-colonna-elenco esn-colonna-fatti' } );

		const agg = corpo.querySelector( '.esn-aggiornamento' );
		const data = agg && /(\d{4}-\d{2}-\d{2})/.exec( agg.textContent );
		righe.append( el( 'li', {}, data ?
			[ 'Rivista il ', el( 'time', { datetime: data[ 1 ] }, [ dataItaliana( data[ 1 ] ) ] ) ] :
			[ el( 'span', { class: 'esn-colonna-tenue' }, [ 'Data di revisione non indicata' ] ) ] ) );

		const fonti = corpo.querySelectorAll( '.esn-fonte' ).length;
		righe.append( el( 'li', {}, [ fonti === 0 ?
			el( 'span', { class: 'esn-colonna-tenue' }, [ 'Nessuna fonte citata' ] ) :
			( fonti === 1 ? '1 fonte citata' : fonti + ' fonti citate' ) ] ) );

		const cat = categorieDiContenuto();
		if ( cat.length ) {
			const li = el( 'li', {}, [ cat.length === 1 ? 'Categoria: ' : 'Categorie: ' ] );
			cat.forEach( ( c, i ) => {
				if ( i ) {
					li.append( ', ' );
				}
				li.append( link( 'Categoria:' + c, c ) );
			} );
			righe.append( li );
		}
		box.append( righe );

		const banner = corpo.querySelector( '.esn-da-verificare' );
		if ( banner ) {
			const a = el( 'a', { href: '#', class: 'esn-colonna-avviso' },
				[ 'Contiene informazioni da verificare' ] );
			a.addEventListener( 'click', ( e ) => {
				e.preventDefault();
				banner.scrollIntoView( { behavior: 'smooth', block: 'center' } );
			} );
			box.append( a );
		}

		// Segnalazioni nella pagina di discussione, sezione nuova. Chi non è entrato passa dal
		// login (i lettori anonimi non possono modificare) e poi torna al modulo.
		const discussione = mw.Title.newFromText( conf.wgPageName ).getTalkPage().getPrefixedText();
		const query = { action: 'edit', section: 'new', preloadtitle: 'Errore segnalato' };
		const href = mw.user.isAnon() ?
			mw.util.getUrl( 'Speciale:Entra', { returnto: discussione, returntoquery: $.param( query ) } ) :
			mw.util.getUrl( discussione, query );
		box.append( el( 'p', { class: 'esn-colonna-segnala' },
			[ el( 'a', { href: href }, [ 'Segnala un errore' ] ) ] ) );
		return box;
	}

	// «Pagine collegate»
	function collegate( api ) {
		const cat = categorieDiContenuto()[ 0 ];
		if ( !cat ) {
			return null;
		}
		const box = riquadro( 'esn-pagine-collegate', 'Pagine collegate', 'verde' );
		box.hidden = true;
		api.get( { action: 'query', list: 'categorymembers', cmtitle: 'Categoria:' + cat,
			cmnamespace: 0, cmtype: 'page', cmlimit: 500, formatversion: 2, maxage: 600,
			smaxage: 600 } )
			.then( ( r ) => {
				const tutte = r.query.categorymembers.map( ( p ) => p.title );
				const qui = tutte.indexOf( conf.wgTitle );
				const altre = tutte.filter( ( t ) => t !== conf.wgTitle );
				if ( !altre.length ) {
					return;
				}
				// Le vicine in ordine alfabetico, a partire da quella che segue la pagina.
				const da = qui < 0 ? 0 : qui;
				const scelte = altre.slice( da ).concat( altre.slice( 0, da ) ).slice( 0, MAX_COLLEGATE )
					.sort( ( a, b ) => a.localeCompare( b, 'it' ) );
				box.append( el( 'p', { class: 'esn-colonna-sottotitolo' },
					[ 'Altre pagine in ', link( 'Categoria:' + cat, cat ) ] ) );
				box.append( el( 'ul', { class: 'esn-colonna-elenco' },
					scelte.map( ( t ) => el( 'li', {}, [ link( t ) ] ) ) ) );
				if ( altre.length > scelte.length ) {
					box.append( el( 'p', { class: 'esn-colonna-piede' }, [ link( 'Categoria:' + cat,
						'Tutte le ' + tutte.length + ' pagine →' ) ] ) );
				}
				box.hidden = false;
			} );
		return box;
	}

	mw.loader.using( [ 'mediawiki.api', 'mediawiki.util', 'mediawiki.Title', 'mediawiki.user' ] )
		.then( () => {
			$( () => {
				const dove = document.querySelector( '.vector-column-end .vector-sticky-pinned-container' );
				if ( !dove ) {
					return;
				}
				const api = new mw.Api();
				const colonna = el( 'div', { class: 'esn-colonna noprint' } );
				[ inQuestaPagina(), collegate( api ) ].forEach( ( b ) => b && colonna.append( b ) );
				dove.append( colonna );
			} );
		} );
}() );