MediaWiki:Gadget-DiscutiRevisioneBlocco.js
Questa pagina definisce alcuni parametri di aspetto e comportamento generale di tutte le pagine. Per personalizzarli vedi Aiuto:Stile utente.
Nota: dopo aver salvato è necessario pulire la cache del proprio browser per vedere i cambiamenti (per le pagine globali è comunque necessario attendere qualche minuto). Per Mozilla / Firefox / Safari: fare clic su Ricarica tenendo premuto il tasto delle maiuscole, oppure premere Ctrl-F5 o Ctrl-R (Command-R su Mac); per Chrome: premere Ctrl-Shift-R (Command-Shift-R su un Mac); per Konqueror: premere il pulsante Ricarica o il tasto F5; per Opera può essere necessario svuotare completamente la cache dal menù Strumenti → Preferenze; per Internet Explorer: mantenere premuto il tasto Ctrl mentre si preme il pulsante Aggiorna o premere Ctrl-F5.
/**
* Questo accessorio automatizza tutte le operazioni necessarie per avviare la
* discussione della richiesta di revisione di un blocco.
*
* Quando l'utente clicca il pulsante "Crea la pagina di discussione" del
* template:Revisione blocco, visualizza una richiesta di conferma e poi
* riceve riscontro delle operazioni in corso in una finestra di dialogo.
*
* Per ulteriori informazioni: [[Aiuto:Accessori/Discuti revisione blocco]].
*
* @author https://it.wikipedia.org/wiki/Utente:Sakretsu
*/
/* global mediaWiki, jQuery, OO */
( function ( mw, $ ) {
'use strict';
const conf = mw.config.get( [
'wgArticleId',
'wgNamespaceNumber',
'wgRelevantUserName',
'wgRevisionId',
'wgUserGroups',
'wgUserName'
] );
const dependencies = [
'ext.gadget.CommentWidget',
'ext.gadget.ProgressDialog',
'mediawiki.api',
'mediawiki.util',
'oojs-ui-core',
'oojs-ui-widgets',
'oojs-ui-windows'
];
const monthNames = [
'gennaio', 'febbraio', 'marzo', 'aprile', 'maggio', 'giugno',
'luglio', 'agosto', 'settembre', 'ottobre', 'novembre', 'dicembre'
];
const rfcRootPage = isOwnSandbox() ?
`Utente:${ conf.wgUserName }/Sandbox/Test revisione del blocco` :
'Wikipedia:Richieste di revisione del blocco';
const rfcTemplate = 'Wikipedia:Richieste di revisione del blocco/ModelloDiscussione';
const appealTemplate = isOwnSandbox() ? 'Revisione blocco/Sandbox' : 'Revisione blocco';
/**
* Verifica se è stato compilato solo il parametro "motivo" del
* template:Revisione blocco passato in input.
*
* @param {object} [appeal] Il template:Revisione blocco da esaminare
* @return {boolean}
*/
function isAppealNew( appeal ) {
const result = appeal.args.esito,
discussionLink = appeal.args[ 'link discussione' ],
reason = appeal.args.motivo;
return ( !result || !result.value.trim() ) &&
( !discussionLink || !discussionLink.value.trim() ) &&
( reason && reason.value.trim() );
}
/**
* Controlla i template:Revisione blocco passati in input.
* Restituisce il primo template che corrisponde a una nuova richiesta.
*
* @param {object} [appeals] Array di template:Revisione blocco
* @return {object}
*/
function findNewAppeal( appeals ) {
let newAppeal;
for ( const appeal of appeals ) {
if ( isAppealNew( appeal ) ) {
newAppeal = appeal;
break;
}
}
return newAppeal;
}
/**
* Restituisce una data in formato d mmmm yyyy.
*
* @param {object} [date] L'oggetto che rappresenta la data
* @return {string}
*/
function formatDate( date ) {
return date
.toLocaleDateString( 'it-IT', { timeZone: 'Europe/Berlin' } )
.replace(
/\/\d\d?\//,
match => ` ${ monthNames[ match.replaceAll( '/', '' ) - 1 ] } `
);
}
/**
* Restituisce il link a una pagina wiki.
*
* @param {string} [title] Il titolo della pagina da linkare
* @return {string}
*/
function link( title ) {
return `<a href=${ mw.util.getUrl( title ) }>${ title }</a>`;
}
/**
* Effettua una chiamata API per chiedere la modifica di una pagina.
*
* @param {object} [customParams] I parametri della chiamata che si
* integrano con quelli precompilati (o li sovrascrivono)
* @return {jQuery.Promise}
*/
function editContent( customParams ) {
return new mw.Api( {
parameters: {
action: 'edit',
format: 'json',
watchlist: 'nochange'
}
} ).postWithToken( 'csrf', customParams );
}
/**
* Effettua una chiamata API per ottenere l'ID dell'ultima versione di una pagina.
*
* @param {number} [pageid] L'ID della pagina
* @return {jQuery.Promise}
*/
function getCurrentRevisionId( pageid ) {
return new mw.Api().get( {
action: 'query',
pageids: pageid,
prop: 'revisions',
rvprop: 'ids',
format: 'json',
formatversion: 2
} );
}
/**
* Effettua una chiamata API per ottenere la versione desiderata di una pagina,
* compreso un array di tutti i template:Revisione blocco in essa contenuti.
*
* @param {number} [revid] L'ID della versione della pagina
* @return {jQuery.Promise}
*/
function getRevision( revid ) {
return $.ajax( {
url: '//itwikiapi.toolforge.org/v1/revisions',
data: {
revid: revid,
rvprop: 'ids|content|timestamp',
templatenames: appealTemplate,
}
} );
}
/**
* Inserisce il link alla discussione della revisione del blocco nel parametro
* "link discussione" del template:Revisione blocco che corrisponde alla
* richiesta di revisione aperta.
* Restituisce il wikitesto modificato.
*
* @param {string} [link] Il link alla discussione
* @param {object} [appeal] Il template della richiesta aperta
* @param {string} [wikitext] Il wikitesto da modificare
* @return {string}
*/
function insertDiscussionLink( link, appeal, wikitext ) {
let name, value, startIndex, endIndex;
if ( appeal.args[ 'link discussione' ] ) {
( { name, value } = appeal.args[ 'link discussione' ] );
value = value.replace( /(\n?$)/, link + '$1' );
[ startIndex, endIndex ] = appeal.args[ 'link discussione' ].span;
} else {
// aggiunge il parametro mantenendo la stessa spaziatura di "motivo"
( { name, value } = appeal.args.motivo );
name = name.replace( 'motivo', 'link discussione' );
value = value.replace( value.trim(), link );
startIndex = endIndex = appeal.span[ 1 ] - 2;
}
return wikitext.substring( 0, startIndex )
+ `|${ name }=${ value }`
+ wikitext.substring( endIndex );
}
/**
* Crea la discussione della richiesta di revisione del blocco e la linka o
* include in tutte le pagine correlate.
*
* @param {string} [reviewingAdminComment] Il parere dell'admin che crea la discussione
* @param {function} [progressMsgHandler] La funzione per mostrare progressi
* @param {function} [errorMsgHandler] La funzione per mostrare errori
* @param {function} [successMsgHandler] La funzione per mostrare successo
* @return {jQuery.Promise}
*/
function createRequestForComment(
reviewingAdminComment, progressMsgHandler, errorMsgHandler, successMsgHandler
) {
const currentDate = formatDate( new Date() );
const rfcTitle = `${ rfcRootPage }/${ conf.wgRelevantUserName }/${ currentDate }`;
const currentRevisionIdPromise = getCurrentRevisionId( conf.wgArticleId );
let revision, newAppeal;
progressMsgHandler( mw.msg( 'fetchingTalkPage' ) );
// ottiene i dati della versione visualizzata della talk
return getRevision( conf.wgRevisionId ).then( result => {
if ( !result.query.badrevids ) {
revision = result.query.pages[ 0 ].revisions[ 0 ];
newAppeal = findNewAppeal( revision.templates );
}
if ( !newAppeal ) {
currentRevisionIdPromise.abort();
return $.Deferred().reject( 'templatemissing' );
}
// ottiene l'ID dell'ultima versione della talk
return currentRevisionIdPromise;
} ).then( result => {
// verifica che la pagina non sia stata modificata nel frattempo
if (
result.query.pages[ 0 ].missing ||
result.query.pages[ 0 ].revisions[ 0 ].revid !== revision.revid
) {
return $.Deferred().reject( 'oldrevision' );
}
// compila il modello predefinito delle discussioni delle richieste
const text = '{{subst:' + rfcTemplate +
'|nome richiedente=' + conf.wgRelevantUserName +
'|motivo richiesta=' + newAppeal.args.motivo.value.trim() +
'|oldid motivo=' + revision.revid +
'|data apertura discussione=' + currentDate +
'|primo parere=' + reviewingAdminComment +
'}}';
progressMsgHandler( mw.msg( 'creatingRfC', link( rfcTitle ) ) );
// crea la pagina di discussione della richiesta di revisione del blocco
return editContent( {
title: rfcTitle,
text: text,
summary: mw.msg( 'rfcEditSummary' ),
createonly: 1,
watchlist: 'watch'
} );
} ).then( () => {
const archivePage = `${ rfcRootPage }/${ conf.wgRelevantUserName }`;
progressMsgHandler( mw.msg( 'updatingArchive', link( archivePage ) ) );
// linka la pagina di discussione nell'archivio delle discussioni che
// si sono tenute sui blocchi dello stesso utente
return editContent( {
title: archivePage,
appendtext: `\n# [[${ rfcTitle }]]`,
summary: mw.msg( 'archiveEditSummary', currentDate )
} );
} ).then( () => {
progressMsgHandler( mw.msg( 'transcludingRfC', link( rfcRootPage ) ) );
// include la pagina di discussione nella pagina di servizio dove sono
// elencate le discussioni in corso delle richieste di revisione
return editContent( {
title: rfcRootPage,
appendtext: `\n\n{{${ rfcTitle }}}`,
summary: mw.msg( 'rfcRootPageEditSummary', conf.wgRelevantUserName )
} );
} ).then( () => {
progressMsgHandler( mw.msg( 'notifyingUser' ) );
// aggiorna il template:Revisione blocco nella talk dell'utente
// compilando il parametro "link discussione" col nome della pagina
// di discussione appena creata
const text = insertDiscussionLink(
rfcTitle,
newAppeal,
revision.slots.main.content
);
// pubblica la modifica
return editContent( {
pageid: conf.wgArticleId,
text: text,
summary: mw.msg( 'talkPageEditSummary', rfcTitle ),
starttimestamp: revision.timestamp,
baserevid: revision.revid
} );
} ).done( () => {
successMsgHandler( mw.msg( 'success' ) );
} ).fail( code => {
let errorText = mw.msg( 'errorOccurred' ) + ' ';
switch( code ) {
case 'articleexists':
case 'editconflict':
case 'oldrevision':
case 'templatemissing':
errorText += mw.msg( code );
break;
default:
errorText += mw.msg( 'unknownError', code );
}
errorMsgHandler( errorText );
} );
}
/**
* Verifica se l'utente che sta usando l'accessorio è un amministratore.
*
* @return {boolean}
*/
function isUserAdmin() {
return conf.wgUserGroups.includes( 'sysop' );
}
/**
* Verifica se la pagina visualizzata è la pagina di discussione di un utente.
*
* @return {boolean}
*/
function isTalkPage() {
return conf.wgNamespaceNumber === 3 &&
conf.wgRelevantUserName !== null &&
conf.wgArticleId !== 0;
}
/**
* Verifica se la pagina visualizzata è una sandbox dell'utente che sta
* usando l'accessorio.
*
* @return {boolean}
*/
function isOwnSandbox() {
return conf.wgNamespaceNumber === 2 &&
conf.wgRelevantUserName === conf.wgUserName;
}
/**
* Verifica se la pagina visualizzata rientra fra quelle dove è previsto che
* sia eseguito l'accessorio.
*
* @return {boolean}
*/
function isPageValid() {
return isOwnSandbox() || isTalkPage();
}
$( () => {
const newRfCButton = $( '.pulsante-discuti-revisione-blocco' );
// termina l'esecuzione se riscontra anomalie
if ( !isPageValid() || !isUserAdmin() || !newRfCButton.length ) return;
// aspetta il corretto caricamento delle dipendenze prima di procedere
mw.loader.using( dependencies ).done( () => {
let windowManager, commentWidget;
// carica i messaggi di sistema dell'accessorio
mw.messages.set( require( './DiscutiRevisioneBlocco-Messages.json' ) );
// modifica il comportamento del pulsante "Crea la pagina di discussione"
newRfCButton.on( 'click', event => {
event.preventDefault();
// avvisa l'utente che non può esserci più di una richiesta aperta
if ( newRfCButton.length > 1 ) {
OO.ui.alert( mw.msg( 'toomanyappeals' ), {
title: mw.msg( 'errorOccurred' )
} );
return;
}
if ( !commentWidget ) {
const CommentWidget = require( 'ext.gadget.CommentWidget' );
// crea un'area di testo dove l'utente può inserire il suo
// parere sulla revisione del blocco e confermare
commentWidget = new CommentWidget( {
cancelButtonLabel: mw.msg( 'cancelButtonLabel' ),
commentIndent: '*',
confirmButtonLabel: mw.msg( 'confirmButtonLabel' ),
placeholder: mw.msg( 'commentBodyPlaceholder' ),
previewLabel: mw.msg( 'previewLabel' ),
storageId: conf.wgArticleId
} ).on( 'detach', () => {
newRfCButton.find( 'input' ).addClass( 'mw-ui-progressive' );
} ).on( 'confirm', data => {
if ( !windowManager ) {
commentWidget.setReadOnly( true );
commentWidget.confirmButton
.on( 'click', () => commentWidget.emit( 'confirm' ) )
.disconnect( commentWidget, { click: 'onConfirmClick' } );
// crea la finestra che mostra le operazioni in corso
const ProgressDialog = require( 'ext.gadget.ProgressDialog' );
const progressDialog = new ProgressDialog( {
closeButtonLabel: mw.msg( 'closeButtonLabel' ),
dialogTitle: mw.msg( 'dialogTitle' )
} );
windowManager = new OO.ui.WindowManager();
$( 'body' ).append( windowManager.$element );
windowManager.addWindows( [ progressDialog ] );
// esegue le operazioni tenendo aggiornata la finestra
createRequestForComment(
data.value,
text => progressDialog.appendProgressMsg( text ),
text => progressDialog.appendErrorMsg( text ),
text => progressDialog.appendSuccessMsg( text )
).done(
() => commentWidget.clearStorage()
).always(
() => progressDialog.showCloseButton()
);
}
windowManager.openWindow( 'progressDialog' );
} );
commentWidget.disconnect( commentWidget, { confirm: 'teardown' } );
commentWidget.cancelButton
.connect( commentWidget, { click: 'detach' } )
.disconnect( commentWidget, { click: 'tryTeardown' } );
}
if ( !commentWidget.isElementAttached() ) {
newRfCButton.find( 'input' ).removeClass( 'mw-ui-progressive' );
newRfCButton.after( commentWidget.$element );
}
commentWidget.focus().scrollElementIntoView();
} );
} );
} );
}( mediaWiki, jQuery ) );