Utente:Ricordisamoa/PDC.js: differenze tra le versioni

Da Wikipedia, l'enciclopedia libera.
Vai alla navigazione Vai alla ricerca
Contenuto cancellato Contenuto aggiunto
fix preInit
+progressi
(6 versioni intermedie di uno stesso utente non sono mostrate)
Riga 10: Riga 10:
namespaces: namespaces,
namespaces: namespaces,


dependencies: [
dependencies: {
'mediawiki.jqueryMsg',
'mediawiki.api.edit',
'mediawiki.ui.button',
'mediawiki.ui.input'
],


/**
* Moduli ResourceLoader da cui dipende lo script.
*/
general: [
'mediawiki.jqueryMsg',
'mediawiki.api.edit',
'mediawiki.ui.button',
'mediawiki.ui.input'
],

/**
* Moduli ResourceLoader da cui dipende la funzionalità della finestra di dialogo.
*/
dialog: [
'jquery.spinner',
'jquery.ui.autocomplete',
'jquery.ui.dialog'
]

},

/**
* Configurazione per Wikipedia in italiano.
*/
config: {
config: {
baseSummary: '[[Utente:Ricordisamoa/PDC.js|PDC.js]]: $1',
baseSummary: '[[Utente:Ricordisamoa/PDC.js|PDC.js]]: $1',
Riga 62: Riga 81:
},
},


/**
* Messaggi di interfaccia per la lingua italiana.
*/
i18n: {
i18n: {
it: {
it: {
Riga 260: Riga 282:
* vedi [[Wikipedia:Requisiti di voto#Requisiti relativi alle votazioni sulle pagine]]
* vedi [[Wikipedia:Requisiti di voto#Requisiti relativi alle votazioni sulle pagine]]
* @param {string} [utente] - Il nome dell'utente del quale verificare i contributi
* @param {string} [utente] - Il nome dell'utente del quale verificare i contributi
* @return {jQuery.Promise}
* @param {function} callback - La funzione invocata in caso di esito positivo
*/
*/
verificaRequisiti: function ( utente, callback ) {
verificaRequisiti: function ( utente ) {
if ( !callback && typeof utente === 'function' ) {
if ( utente === undefined ) {
callback = utente;
utente = mw.config.get( 'wgUserName' );
utente = mw.config.get( 'wgUserName' );
}
}
if ( mw.config.get( 'wgDBname' ) === 'testwiki' ) {
if ( mw.config.get( 'wgDBname' ) === 'testwiki' ) {
return $.Deferred().resolve( true );
callback();
return;
}
}
var self = this;
var self = this;
self.api.get( {
return self.api.get( {
action: 'query',
action: 'query',
format: 'json',
format: 'json',
Riga 283: Riga 303:
uclimit: 1
uclimit: 1
} )
} )
.done( function ( data ) {
.then( function ( data ) {
if ( !data.query || !data.query.users || data.query.users.length !== 1 ) {
if ( !data.query || !data.query.users || data.query.users.length !== 1 ) {
return;
return false;
}
}
var user = data.query.users[0];
var user = data.query.users[0];
if ( !user.name || user.name !== utente || !user.editcount || user.editcount < self.config.minEdits || !data.query.usercontribs ) {
if ( !user.name || user.name !== utente || !user.editcount || user.editcount < self.config.minEdits || !data.query.usercontribs ) {
return;
return false;
}
}
var uc = data.query.usercontribs;
var uc = data.query.usercontribs;
if ( uc.length !== 1 || !uc[0].user || !uc[0].timestamp || ( new Date() - new Date( uc[0].timestamp ) ) / 86400000 < self.config.minDaysOld ) {
if ( uc.length !== 1 || !uc[0].user || !uc[0].timestamp || ( new Date() - new Date( uc[0].timestamp ) ) / 86400000 < self.config.minDaysOld ) {
return;
return false;
}
}
callback();
return true;
} );
} );
},
},
Riga 424: Riga 444:


/**
/**
* Aggiunge il template {{Cancellazione}} in una nuova sezione di una pagina di discussione.
* Aggiunge il template {{Cancellazione}} in una nuova sezione di una o più pagine di discussione.
* @param {string} titolo - Il titolo della pagina da proporre per la cancellazione
* @param {string} titolo - Il titolo della pagina da proporre per la cancellazione
* @param {Array.<string>} discussioni - Le pagine di discussione degli utenti o dei progetti da avvisare
* @param {Array.<string>} discussioni - I titoli delle pagine di discussione degli utenti o dei progetti da avvisare
* @return {jQuery.Promise}
* @param {function} callback - La funzione da eseguire in caso di esito positivo
*/
*/
notificaProcedura: function ( titolo, discussioni, callback ) {
notificaProcedura: function ( titolo, discussioni ) {
var self = this;
var self = this,
deferreds = [],
self.progresso( 'notify-wait' );
sectionTitle = self.l10nMsg( 'notificationNewSectionTitle', titolo ),
if ( discussioni.length === 0 ) {
sectionContent = '{{' + self.config.notificationNewSectionTemplate + '|' + titolo + '}}--~~~~';
callback();
$.each( discussioni, function ( i, discussione ) {
return;
deferreds.push(
}
self.api.newSection( discussione, sectionTitle, sectionContent )
var paginaAdesso = discussioni.shift();
.done( function () {
self.api.newSection(
console.info( self.msg( 'notify-done', discussione ) );
paginaAdesso,
} )
self.l10nMsg( 'notificationNewSectionTitle', titolo ),
);
'{{' + self.config.notificationNewSectionTemplate + '|' + titolo + '}}--~~~~'
)
.done( function ( data ) {
if ( data && data.error && data.error.info ) {
self.errore( 'notify-error', data.error.info );
} else {
console.info( self.msg( 'notify-done', paginaAdesso ) );
if ( discussioni.length > 0 ) {
self.notificaProcedura( titolo, discussioni, callback );
} else {
callback();
}
}
} )
.fail( function () {
self.errore( 'notify-error' );
} );
} );
return $.when.apply( $, deferreds );
},
},


Riga 467: Riga 473:
creaProcedura: function ( titolo, motivazione ) {
creaProcedura: function ( titolo, motivazione ) {
var numero = 1,
var numero = 1,
procedura = this.config.base + '/' + titolo;
procedura = this.config.base + '/' + titolo;
return this.api.postWithToken( 'edit', {
return this.api.postWithToken( 'edit', {
action: 'edit',
action: 'edit',
Riga 565: Riga 571:
* Controlla se una pagina contiene già un avviso di cancellazione.
* Controlla se una pagina contiene già un avviso di cancellazione.
* @param {string} titolo - Il titolo della pagina da controllare
* @param {string} titolo - Il titolo della pagina da controllare
* @return {jQuery.Promise}
* @param {function} callback - La funzione da eseguire al termine del controllo
*/
*/
inCancellazione: function ( titolo, callback ) {
inCancellazione: function ( titolo ) {
this.api.get( {
return this.api.get( {
action: 'query',
action: 'query',
format: 'json',
format: 'json',
Riga 575: Riga 581:
tltemplates: this.config.baseTemplate
tltemplates: this.config.baseTemplate
} )
} )
.done( function ( data ) {
.then( function ( data ) {
callback( data.query && data.query.pages && Object.keys( data.query.pages ).length === 1 && ( data.query.pages[Object.keys( data.query.pages )[0]].templates || [] ).length === 1 );
if ( data.query && data.query.pages ) {
var pages = data.query.pages;
return (
Object.keys( pages ).length === 1 &&
( pages[Object.keys( pages )[0]].templates || [] ).length === 1
);
}
return false;
} );
} );
},
},
Riga 736: Riga 749:
var self = this;
var self = this;
titolo = titolo.replace( /_/g, ' ' );
titolo = titolo.replace( /_/g, ' ' );
mw.loader.using( ['jquery.spinner', 'jquery.ui.autocomplete', 'jquery.ui.dialog'], function () {
mw.loader.using( self.dependencies.dialog )
.done( function () {
var cancelButton = {
var cancelButton = {
text: self.msg( 'dialog-button-cancel' ),
text: self.msg( 'dialog-button-cancel' ),
Riga 862: Riga 876:
self.avvisoVoce( titolo, numero, argomenti )
self.avvisoVoce( titolo, numero, argomenti )
.done( function () {
.done( function () {
self.notificaProcedura( titolo, daNotificare, function () {
self.progresso( 'notify-wait' );
self.notificaProcedura( titolo, daNotificare )
.done( function () {
window.location = mw.util.getUrl( procedura );
window.location = mw.util.getUrl( procedura );
} )
.fail( function () {
self.errore( 'notify-error' );
} );
} );
} )
} )
Riga 893: Riga 912:
}
}
return $obj[m]();
return $obj[m]();
},

/**
* Trasforma alcune frasi appositamente configurate
* in link per richiedere la cancellazione della pagina.
*/
autoRfd: function () {
var self = this;
if ( self.config.autoRfd.length === 0 ) {
return;
}
$( 'div' ).each( function () {
$( this )
.contents()
.filter( function () {
// solo testo semplice
return this.nodeType === this.TEXT_NODE;
} )
.each( function () {
var htmlDiv = this;
$.each( self.config.autoRfd, function ( replIdx, replParts ) {
// cerca la frase intera,
var find = htmlDiv.textContent.indexOf( replParts.join( '' ) );
if ( find !== -1 ) {
// ...la isola
var node = htmlDiv.splitText( find + replParts[0].length );
// ...e la rende cliccabile
$( node.splitText( replParts[1].length ).previousSibling )
.wrap( '<a>' ).parent()
.attr( {
href: '#',
title: self.msg( 'menu-link-tooltip' )
} )
.click( function ( event ) {
event.preventDefault();
self.proceduraGuidata( mw.config.get( 'wgPageName' ) );
} );
}
} );
} );
} );
},

/**
* Genera il contenitore per pulsanti che richiedono permessi di amministratore.
* @param {Object} stato - Lo stato della procedura di cancellazione
* @return {jQuery}
*/
buildSysopButtons: function ( stato ) {
var self = this,
$sysopButtons = $( '<div>' )
.attr( 'id', 'PDC-toolbox-sysop' )
.append( [
// Pulsante "avvia votazione" con effetto immediato
$( '<button>' )
.addClass( 'mw-ui-button mw-ui-constructive' )
.attr( !stato.votazione && stato.consensuale ? {} : { disabled: 'disabled' } )
.text( self.msg( 'toolbox-vote-start' ) )
.click( function ( event ) {
event.preventDefault();
var $cont = $( this ).prev();
$cont.next().remove();
$cont.after( '<p>' + self.msg( 'toolbox-vote-start-wait' ) + '</p>' );
self.avviaVotazione( mw.config.get( 'wgPageName' ) )
.done( function () {
window.location.reload();
} )
.fail( function () {
$cont.next().remove();
$cont.after( self.msg( 'toolbox-vote-start-error' ) );
} );
} ),
'&nbsp;',
// Pulsante "chiudi la procedura" con conferma richiesta
$( '<button>' )
.addClass( 'mw-ui-button mw-ui-progressive' )
.text( self.msg( 'toolbox-close' ) )
.click( function ( event ) {
event.preventDefault();
$( '<div>' )
.append( [
// Cancellare la pagina?
self.msg( 'toolbox-close-delete' ),
'<br>',
// Sì
$( '<button>' )
.addClass( 'mw-ui-button mw-ui-destructive' )
.text( self.msg( 'toolbox-close-delete-yes' ) )
.click( function ( event ) {
event.preventDefault();
var $div = $( this ).parent(),
modalità = stato.consensuale ? 'consensuale' : 'simple';
self.progresso( 'toolbox-close-delete-wait', $div );
self.cancellaPagina( stato.pagina, mw.config.get( 'wgPageName' ), modalità )
.done( function () {
self.progresso( 'toolbox-close-notice-wait', $div );
self.avvisoCancellata( mw.config.get( 'wgPageName' ), modalità )
.done( function () {
self.progresso( 'toolbox-close-protect-wait', $div );
self.proteggiPagina( mw.config.get( 'wgPageName' ) )
.done( function () {
self.progresso( 'toolbox-purge-wait', $div );
self.purgaPagina( mw.config.get( 'wgPageName' ) )
.done( function () {
window.location.reload();
} );
} )
.fail( function ( code, info ) {
self.errore( 'toolbox-close-protect-error', info, $div );
} );
} )
.fail( function ( code, info ) {
self.errore( 'toolbox-close-notice-error', info, $div );
} );
} )
.fail( function ( code, info ) {
self.errore( 'toolbox-close-delete-error', info, $div );
} );
} ),
'&nbsp;',
// No
$( '<button>' )
.addClass( 'mw-ui-button mw-ui-constructive' )
.text( self.msg( 'toolbox-close-delete-no' ) )
.click( function ( event ) {
event.preventDefault();
var $div = $( this ).parent();
self.mantenuta( stato.pagina, votazione, numero, favorevoli, contrari )
.done( function () {
self.progresso( 'toolbox-close-protect-wait', $div );
self.proteggiPagina( mw.config.get( 'wgPageName' ) )
.done( function () {
self.progresso( 'toolbox-purge-wait', $div );
self.purgaPagina( mw.config.get( 'wgPageName' ) )
.done( function () {
window.location.reload();
} );
} )
.fail( function ( code, info ) {
self.errore( 'toolbox-close-protect-error', info, $div );
} );
} )
.fail( function ( code, info ) {
self.errore( 'toolbox-close-kept-error', info, $div );
} );
self.progresso( 'toolbox-close-kept-wait', $div );
} ),
'&nbsp;',
// Annulla
$( '<button>' )
.addClass( 'mw-ui-button' )
.text( self.msg( 'toolbox-close-cancel' ) )
.click( function ( event ) {
event.preventDefault();
self.switchButtons( $sysopButtons, true );
} )
] )
.insertAfter( self.switchButtons( $sysopButtons ) );
} )
] );
return $sysopButtons;
},
},


Riga 900: Riga 1 080:
preInit: function () {
preInit: function () {
if (
if (
// in modalità di visualizzazione
mw.config.get( 'wgAction' ) === 'view' &&
mw.config.get( 'wgAction' ) === 'view' &&
// solo utenti registrati
mw.user.isAnon() === false &&
mw.user.isAnon() === false &&
// niente redirect
mw.config.get( 'wgIsRedirect' ) === false &&
mw.config.get( 'wgIsRedirect' ) === false &&
// niente diff
mw.util.getParamValue( 'diff' ) === null &&
mw.util.getParamValue( 'diff' ) === null &&
// solo ultime versioni
mw.util.getParamValue( 'oldid' ) === null
mw.util.getParamValue( 'oldid' ) === null
) {
) {
Riga 909: Riga 1 094:
sp = mw.config.get( 'wgPageName' ).replace( /_/g, ' ' ).split( '/' ),
sp = mw.config.get( 'wgPageName' ).replace( /_/g, ' ' ).split( '/' ),
modes = {
modes = {
// visualizzare la casella "Strumenti PDC"?
toolbox: ( sp.length > 1 && sp[0] === self.config.base ),
toolbox: ( sp.length > 1 && sp[0] === self.config.base ),
// aggiungere il link per la finestra di dialogo alla sezione "Strumenti" della barra laterale?
portlet: (
portlet: (
mw.config.get( 'wgIsArticle' ) === true &&
mw.config.get( 'wgIsArticle' ) === true &&
Riga 920: Riga 1 107:
if ( values.indexOf( true ) !== -1 ) {
if ( values.indexOf( true ) !== -1 ) {
self.modes = modes;
self.modes = modes;
mw.loader.using( self.dependencies ).done( function () {
mw.loader.using( self.dependencies.general )
.done( function () {
self.init();
self.init();
} );
} );
Riga 932: Riga 1 120:
init: function () {
init: function () {
var self = this;
var self = this;
// Prepara i messaggi nella lingua dell'utente, e in alternativa in inglese.
self.i18n = $.extend( true, ( self.i18n.en || {} ), ( self.i18n[mw.config.get( 'wgUserLanguage' )] || {} ) );
self.i18n = $.extend( true, ( self.i18n.en || {} ), ( self.i18n[mw.config.get( 'wgUserLanguage' )] || {} ) );
$.each( self.i18n, function ( k, v ) {
$.each( self.i18n, function ( k, v ) {
Riga 937: Riga 1 126:
} );
} );
if ( self.modes.portlet === true ) {
if ( self.modes.portlet === true ) {
self.inCancellazione( mw.config.get( 'wgPageName' ), function ( val ) {
self.inCancellazione( mw.config.get( 'wgPageName' ) )
.done( function ( val ) {
if ( val === false ) {
if ( val === false ) {
self.verificaRequisiti( function () {
self.verificaRequisiti()
.done( function ( accettato ) {
if ( accettato !== true ) {
return;
}
$( mw.util.addPortletLink( 'p-tb', '#', self.msg( 'menu-link-label' ), 'PDC-init', self.msg( 'menu-link-tooltip' ) ) )
$( mw.util.addPortletLink( 'p-tb', '#', self.msg( 'menu-link-label' ), 'PDC-init', self.msg( 'menu-link-tooltip' ) ) )
.click( function ( event ) {
.click( function ( event ) {
Riga 945: Riga 1 139:
self.proceduraGuidata( mw.config.get( 'wgPageName' ) );
self.proceduraGuidata( mw.config.get( 'wgPageName' ) );
} );
} );
if ( self.config.autoRfd.length > 0 ) {
self.autoRfd();
$( 'div' ).each( function () {
$( this )
.contents()
.filter( function () {
return this.nodeType === 3;
} )
.each( function () {
var htmlDiv = this;
$.each( self.config.autoRfd, function ( replIdx, replParts ) {
var find = htmlDiv.textContent.indexOf( replParts.join( '' ) );
if ( find !== -1 ) {
var node = htmlDiv.splitText( find + replParts[0].length );
$( node.splitText( replParts[1].length ).previousSibling )
.wrap( '<a>' ).parent()
.attr( {
href: '#',
title: self.msg( 'menu-link-tooltip' )
} )
.click( function ( event ) {
event.preventDefault();
self.proceduraGuidata( mw.config.get( 'wgPageName' ) );
} );
}
} );
} );
} );
}
} );
} );
}
}
Riga 978: Riga 1 145:
}
}
if ( self.modes.toolbox === true ) {
if ( self.modes.toolbox === true ) {
self.verificaRequisiti( function () {
self.verificaRequisiti()
self.titoloPagina( mw.config.get( 'wgPageName' ) ).done( function ( titoloPagina ) {
.done( function ( accettato ) {
if ( accettato !== true ) {
return;
}
self.titoloPagina( mw.config.get( 'wgPageName' ) )
.done( function ( titoloPagina ) {
if ( !titoloPagina ) {
if ( !titoloPagina ) {
return;
return;
}
}
self.statoProcedura( mw.config.get( 'wgPageName' ) ).done( function ( stato ) {
self.statoProcedura( mw.config.get( 'wgPageName' ) )
.done( function ( stato ) {
stato.pagina = titoloPagina;
var prorogabile = false,
var prorogabile = false,
adesso = new Date(),
adesso = new Date(),
Riga 995: Riga 1 169:
}
}
}
}
var toolbox = $( '<div>' )
var $toolbox = $( '<div>' )
.attr( 'id', 'PDC-toolbox' )
.attr( 'id', 'PDC-toolbox' )
.addClass( 'toccolours' )
.addClass( 'toccolours' )
Riga 1 001: Riga 1 175:
.append(
.append(
$( '<h3>' )
$( '<h3>' )
.text( self.msg( 'toolbox-title', titoloPagina ) )
.text( self.msg( 'toolbox-title', stato.pagina ) )
),
),
statusMsg = self.msg( 'toolbox-open-generic' );
statusMsg = self.msg( 'toolbox-open-generic' );
Riga 1 008: Riga 1 182:
} else if ( apertaDaGiorni ) {
} else if ( apertaDaGiorni ) {
var days,
var days,
user;
user;
if ( parseInt( apertaDaGiorni ) > 1 ) {
if ( parseInt( apertaDaGiorni ) > 1 ) {
days = self.msg( 'toolbox-days-ago', parseInt( apertaDaGiorni ) );
days = self.msg( 'toolbox-days-ago', parseInt( apertaDaGiorni ) );
Riga 1 026: Riga 1 200:
$( '<p>' )
$( '<p>' )
.append( statusMsg )
.append( statusMsg )
.appendTo( toolbox );
.appendTo( $toolbox );

/**
* Contenitore per pulsanti che non richiedono permessi particolari.
*/
var $publicButtons = $( '<div>' )
var $publicButtons = $( '<div>' )
.attr( 'id', 'PDC-toolbox-public' )
.attr( 'id', 'PDC-toolbox-public' )
.appendTo( toolbox );
.appendTo( $toolbox );

// Pulsante "aggiorna" con effetto immediato (innocuo)
$( '<button>' )
$( '<button>' )
.addClass( 'mw-ui-button' )
.addClass( 'mw-ui-button' )
Riga 1 037: Riga 1 217:
var $box = $( this ).parent();
var $box = $( this ).parent();
self.progresso( 'toolbox-purge-wait', $box );
self.progresso( 'toolbox-purge-wait', $box );
self.purgaPagina( mw.config.get( 'wgPageName' ) ).done( function () {
self.purgaPagina( mw.config.get( 'wgPageName' ) )
.done( function () {
window.location.reload();
window.location.reload();
} );
} );
Riga 1 053: Riga 1 234:
deferButtonMsg = 'toolbox-not-deferrable-yet';
deferButtonMsg = 'toolbox-not-deferrable-yet';
}
}
// Pulsante "proroga" con conferma richiesta
$( '<button>' )
$( '<button>' )
.addClass( 'mw-ui-button mw-ui-progressive' )
.addClass( 'mw-ui-button mw-ui-progressive' )
Riga 1 061: Riga 1 243:
$( '<div>' )
$( '<div>' )
.append( [
.append( [
// Di quanti giorni?
$( '<label>' )
$( '<label>' )
.attr( 'for', 'PDC-defer-days' )
.attr( 'for', 'PDC-defer-days' )
Riga 1 073: Riga 1 256:
} )
} )
.val( self.config.deferDefaultDays ),
.val( self.config.deferDefaultDays ),
// Conferma
$( '<button>' )
$( '<button>' )
.addClass( 'mw-ui-button mw-ui-constructive' )
.addClass( 'mw-ui-button mw-ui-constructive' )
Riga 1 083: Riga 1 267:
.done( function () {
.done( function () {
self.progresso( 'toolbox-purge-wait', $box );
self.progresso( 'toolbox-purge-wait', $box );
self.purgaPagina( mw.config.get( 'wgPageName' ) ).done( function () {
self.purgaPagina( mw.config.get( 'wgPageName' ) )
.done( function () {
window.location.reload();
window.location.reload();
} );
} );
Riga 1 092: Riga 1 277:
} ),
} ),
'&nbsp;',
'&nbsp;',
// Annulla
$( '<button>' )
$( '<button>' )
.addClass( 'mw-ui-button' )
.addClass( 'mw-ui-button' )
Riga 1 104: Riga 1 290:
.appendTo( $publicButtons );
.appendTo( $publicButtons );
} else {
} else {
// Pulsante "passa alla modalità consensuale" con conferma richiesta
$( '<button>' )
$( '<button>' )
.addClass( 'mw-ui-button mw-ui-progressive' )
.addClass( 'mw-ui-button mw-ui-progressive' )
Riga 1 111: Riga 1 298:
$( '<div>' )
$( '<div>' )
.append( [
.append( [
// Motivazione
$( '<textarea>' )
$( '<textarea>' )
.addClass( 'mw-ui-input' )
.addClass( 'mw-ui-input' )
.css( 'background', '#fff' )
.css( 'background', '#fff' )
.attr( 'placeholder', self.msg( 'toolbox-consensuale-reason' ) ),
.attr( 'placeholder', self.msg( 'toolbox-consensuale-reason' ) ),
// Conferma
$( '<button>' )
$( '<button>' )
.addClass( 'mw-ui-button mw-ui-constructive' )
.addClass( 'mw-ui-button mw-ui-constructive' )
Riga 1 131: Riga 1 320:
} ),
} ),
'&nbsp;',
'&nbsp;',
// Annulla
$( '<button>' )
$( '<button>' )
.addClass( 'mw-ui-button' )
.addClass( 'mw-ui-button' )
Riga 1 144: Riga 1 334:
}
}
$publicButtons.append( '&nbsp;' );
$publicButtons.append( '&nbsp;' );
// Pulsante "annulla la procedura" con conferma richiesta
$( '<button>' )
$( '<button>' )
.addClass( 'mw-ui-button mw-ui-progressive' )
.addClass( 'mw-ui-button mw-ui-progressive' )
Riga 1 151: Riga 1 342:
$( '<div>' )
$( '<div>' )
.append( [
.append( [
// Motivazione
$( '<textarea>' )
$( '<textarea>' )
.addClass( 'mw-ui-input' )
.addClass( 'mw-ui-input' )
.css( 'background', '#fff' )
.css( 'background', '#fff' )
.attr( 'placeholder', self.msg( 'toolbox-cancel-reason' ) ),
.attr( 'placeholder', self.msg( 'toolbox-cancel-reason' ) ),
// Conferma
$( '<button>' )
$( '<button>' )
.addClass( 'mw-ui-button mw-ui-destructive' )
.addClass( 'mw-ui-button mw-ui-destructive' )
Riga 1 167: Riga 1 360:
} ),
} ),
'&nbsp;',
'&nbsp;',
// Annulla
$( '<button>' )
$( '<button>' )
.addClass( 'mw-ui-button' )
.addClass( 'mw-ui-button' )
Riga 1 180: Riga 1 374:
}
}
if ( self.sysop && stato.terminata === false ) {
if ( self.sysop && stato.terminata === false ) {
$( '<h4>' )
// Strumenti per amministratori
.text( self.msg( 'toolbox-sysops' ) )
$toolbox
.appendTo( toolbox );
.append( [
var $sysopButtons = $( '<div>' )
$( '<h4>' )
.attr( 'id', 'PDC-toolbox-sysop' )
.text( self.msg( 'toolbox-sysops' ) ),
.appendTo( toolbox );
self.buildSysopButtons( stato )
$sysopButtons.append( [
$( '<button>' )
.addClass( 'mw-ui-button mw-ui-constructive' )
.attr( !stato.votazione && stato.consensuale ? {} : { disabled: 'disabled' } )
.text( self.msg( 'toolbox-vote-start' ) )
.click( function ( event ) {
event.preventDefault();
var $cont = $( this ).prev();
$cont.next().remove();
$cont.after( '<p>' + self.msg( 'toolbox-vote-start-wait' ) + '</p>' );
self.avviaVotazione( mw.config.get( 'wgPageName' ) )
.done( function () {
window.location.reload();
} )
.fail( function () {
$cont.next().remove();
$cont.after( self.msg( 'toolbox-vote-start-error' ) );
} );
} ),
'&nbsp;',
$( '<button>' )
.addClass( 'mw-ui-button mw-ui-progressive' )
.text( self.msg( 'toolbox-close' ) )
.click( function ( event ) {
event.preventDefault();
$( '<div>' )
.append( [
self.msg( 'toolbox-close-delete' ),
'<br>',
$( '<button>' )
.addClass( 'mw-ui-button mw-ui-destructive' )
.text( self.msg( 'toolbox-close-delete-yes' ) )
.click( function ( event ) {
event.preventDefault();
var $div = $( this ).parent(),
modalità = stato.consensuale ? 'consensuale' : 'simple';
self.progresso( 'toolbox-close-delete-wait', $div );
self.cancellaPagina( titoloPagina, mw.config.get( 'wgPageName' ), modalità )
.done( function () {
self.progresso( 'toolbox-close-notice-wait', $div );
self.avvisoCancellata( mw.config.get( 'wgPageName' ), modalità )
.done( function () {
self.progresso( 'toolbox-close-protect-wait', $div );
self.proteggiPagina( mw.config.get( 'wgPageName' ) )
.done( function () {
self.progresso( 'toolbox-purge-wait', $div );
self.purgaPagina( mw.config.get( 'wgPageName' ) ).done( function () {
window.location.reload();
} );
} )
.fail( function ( code, info ) {
self.errore( 'toolbox-close-protect-error', info, $div );
} );
} )
.fail( function ( code, info ) {
self.errore( 'toolbox-close-notice-error', info, $div );
} );
} )
.fail( function ( code, info ) {
self.errore( 'toolbox-close-delete-error', info, $div );
} );
} ),
'&nbsp;',
$( '<button>' )
.addClass( 'mw-ui-button mw-ui-constructive' )
.text( self.msg( 'toolbox-close-delete-no' ) )
.click( function ( event ) {
event.preventDefault();
var $div = $( this ).parent();
self.mantenuta( titoloPagina, votazione, numero, favorevoli, contrari )
.done( function () {
self.proteggiPagina( mw.config.get( 'wgPageName' ) )
.done( function () {
self.purgaPagina( mw.config.get( 'wgPageName' ) ).done( function () {
window.location.reload();
} );
} )
.fail( function ( code, info ) {
self.errore( 'toolbox-close-protect-error', info, $div );
} );
} )
.fail( function ( code, info ) {
self.errore( 'toolbox-close-kept-error', info, $div );
} );
self.progresso( 'toolbox-close-kept-wait', $div );
} ),
'&nbsp;',
$( '<button>' )
.addClass( 'mw-ui-button' )
.text( self.msg( 'toolbox-close-cancel' ) )
.click( function ( event ) {
event.preventDefault();
self.switchButtons( $sysopButtons, true );
} )
] )
.insertAfter( self.switchButtons( $sysopButtons ) );
} )
] );
] );
}
}
toolbox.prependTo( '#mw-content-text' );
$toolbox.prependTo( '#mw-content-text' );
} );
} );
} );
} );

Versione delle 20:56, 25 dic 2014

//<nowiki>
/* jshint browser:true, devel:true, smarttabs:true */
/* global mediaWiki, jQuery */
( function ( mw, $ ) {
	'use strict';
	var namespaces = mw.config.get( 'wgFormattedNamespaces' );
	window.PDC = {
		api: new mw.Api(),

		namespaces: namespaces,

		dependencies: {

			/**
			 * Moduli ResourceLoader da cui dipende lo script.
			 */
			general: [
				'mediawiki.jqueryMsg',
				'mediawiki.api.edit',
				'mediawiki.ui.button',
				'mediawiki.ui.input'
			],

			/**
			 * Moduli ResourceLoader da cui dipende la funzionalità della finestra di dialogo.
			 */
			dialog: [
				'jquery.spinner',
				'jquery.ui.autocomplete',
				'jquery.ui.dialog'
			]

		},

		/**
		 * Configurazione per Wikipedia in italiano.
		 */
		config: {
			baseSummary: '[[Utente:Ricordisamoa/PDC.js|PDC.js]]: $1',
			base: namespaces[4] + ':Pagine da cancellare',
			help: namespaces[4] + ':Regole per la cancellazione',
			baseTemplate: namespaces[10] + ':Cancellazione',
			actInNamespaces: [0],
			afdCatPrefix: 'Pagine in cancellazione - ',
			wikiprojectNamespace: 102,
			autoRfd: [
				['Se ritieni il soggetto non enciclopedico, ', 'proponi', ' la ']
			],
			minEdits: 50,
			minDaysOld: 30,
			minDeferrableDays: 7,
			newNominationTemplate: 'subst:Cancellazione/creavvisotesto',
			newNominationSummary: 'nuova richiesta di cancellazione',
			nominationNoticeTemplate: 'Cancellazione',
			nominationNoticeSummary: 'richiesta di cancellazione',
			notificationNewSectionTitle: 'Cancellazione [[$1]]',
			notificationNewSectionTemplate: 'Cancellazione',
			consensualeStartTemplate: 'subst:Consensuale',
			consensualeStartSummary: 'avvio della modalità consensuale',
			deferMinDays: 1,
			deferMaxDays: 7,
			deferDefaultDays: 7,
			deferStartTemplate: 'subst:Proroga',
			deferStartSummary: 'modalità consensuale prorogata per $1 {{PLURAL:$1|giorno|giorni}}',
			voteStartTemplate: 'subst:Votazione',
			voteStartSummary: 'avvio della votazione',
			voteSummary: 'voto',
			simpleDeletedTemplate: 'subst:User:L736E/FineCanc',
			simpleDeletedSummary: 'notifica dell\'avvenuta cancellazione in modalità semplificata',
			simpleDeletedReason: 'Come da procedura di [[WP:RPC|cancellazione semplificata]]: [[$1]]',
			consensualeDeletedTemplate: 'subst:User:L736E/FineCons|cancellata',
			consensualeDeletedSummary: 'notifica dell\'avvenuta cancellazione in modalità consensuale',
			consensualeDeletedReason: 'Come da procedura di [[WP:RPC|cancellazione consensuale]]: [[$1]]',
			deletedAfterPollRfdTemplate: 'subst:User:L736E/FineVoto|cancellata',
			keptTalkTemplate: 'Mantenuta',
			keptRfdTemplate: 'subst:User:L736E/FineVoto|mantenuta',
			keptAfterPollTalkTemplate: 'Noncancellata',
			keptSummary: 'pagina mantenuta',
			protectLevel: 'edit=sysop|move=sysop',
			protectReason: '[[WP:PDC|Procedura di cancellazione]] terminata o annullata'
		},

		/**
		 * Messaggi di interfaccia per la lingua italiana.
		 */
		i18n: {
			it: {
				'menu-link-label': 'Richiedi cancellazione',
				'menu-link-tooltip': 'Procedura guidata per richiedere la cancellazione di questa pagina',
				'dialog-title': 'Richiesta di cancellazione: procedura guidata',
				'dialog-button-cancel': 'Annulla',
				'dialog-button-proceed': 'Procedi',
				'error-msg': '$1: $2',
				'process-init': 'Benvenuto/a!<br>Sarai guidato/a nella richiesta di cancellazione per la pagina "<b>$1</b>".<br><br>Se invece desideri effettuare la procedura manualmente, consulta $2.',
				'process-loading-contributors': 'Caricamento dei contributori della pagina in corso...',
				'process-confirm': 'Stai per proporre la cancellazione della pagina "$1".',
				'option-reason': 'Perché la pagina dovrebbe essere cancellata? (La firma è inserita automaticamente)',
				'option-reason-missing': 'Inserisci una motivazione',
				'option-notify-creator': 'Notifica il creatore della pagina ($1)',
				'option-notify-biggest': 'Notifica il maggior contributore (tra gli utenti registrati) della pagina ($1)',
				'option-notify-topics': 'Eventuale/i argomento/i relativo/i: ',
				'option-notify-wikiprojects': 'Invia notifiche ai progetti di riferimento',
				'new-nomination-wait': 'Creazione della pagina di procedura in corso...',
				'new-nomination-error': 'Errore durante la creazione della pagina di procedura',
				'nominate-wait': 'Aggiunta dell\'avviso nella pagina in corso...',
				'nominate-error': 'Errore durante l\'aggiunta dell\'avviso nella pagina',
				'notify-wait': 'Notifica della proposta di cancellazione in corso...',
				'notify-error': 'Errore durante la notifica della proposta di cancellazione',
				'notify-done': 'Notifica della proposta di cancellazione inviata con successo alla pagina "$1"',
				'toolbox-title': 'Strumenti PDC per "$1"',
				'toolbox-days-ago': '$1 {{PLURAL:$1|giorno|giorni}} fa',
				'toolbox-today': 'oggi',
				'toolbox-yesterday': 'ieri',
				'toolbox-user-unknown': 'un utente sconosciuto',
				'toolbox-open-generic': 'Procedura aperta',
				'toolbox-open': 'Procedura aperta $1 da $2',
				'toolbox-closed' : 'Procedura chiusa',
				'toolbox-purge': 'Aggiorna',
				'toolbox-defer': 'Proroga',
				'toolbox-already-deferred': 'Già prorogata',
				'toolbox-not-deferrable-yet': 'Non ancora prorogabile',
				'toolbox-defer-days': 'Giorni di proroga',
				'toolbox-defer-cancel': 'Non prorogare',
				'toolbox-defer-wait': 'Annullamento della procedura in corso...',
				'toolbox-defer-error': 'Errore durante la proroga della procedura',
				'toolbox-consensuale': 'Passa alla modalità consensuale',
				'toolbox-consensuale-cancel': 'Annulla',
				'toolbox-consensuale-reason': 'Perché non vuoi che la pagina sia cancellata?',
				'toolbox-consensuale-wait': 'Passaggio alla modalità consensuale in corso...',
				'toolbox-consensuale-error': 'Errore durante il passaggio alla modalità consensuale',
				'toolbox-cancel': 'Annulla la procedura',
				'toolbox-cancel-cancel': 'Non annullare la procedura',
				'toolbox-cancel-reason': 'Perché la procedura deve essere annullata?',
				'toolbox-cancel-wait': 'Annullamento della procedura in corso...',
				'toolbox-cancel-error': 'Errore durante l\'annullamento della procedura',
				'toolbox-sysops': 'Per gli amministratori',
				'toolbox-vote-start': 'Avvia votazione',
				'toolbox-vote-start-wait': 'Avvio della votazione in corso...',
				'toolbox-vote-start-error': 'Errore durante l\'avvio della votazione',
				'toolbox-close': 'Chiudi la procedura',
				'toolbox-close-delete': 'Cancellare la pagina?',
				'toolbox-close-delete-yes': 'Sì',
				'toolbox-close-delete-no': 'No',
				'toolbox-close-cancel': 'Annulla',
				'toolbox-close-option-protect': 'Proteggi questa procedura',
				'toolbox-close-kept-wait': 'Notifica dell\'avvenuto mantenimento della pagina in corso...',
				'toolbox-close-kept-error': 'Errore durante la notifica dell\'avvenuto mantenimento',
				'toolbox-close-delete-wait': 'Cancellazione della pagina in corso...',
				'toolbox-close-delete-error': 'Errore durante la cancellazione della pagina',
				'toolbox-close-notice-wait': 'Notifica dell\'avvenuta cancellazione della pagina in corso...',
				'toolbox-close-notice-error': 'Errore durante la notifica dell\'avvenuta cancellazione',
				'toolbox-close-protect-wait': 'Protezione della pagina di procedura in corso...',
				'toolbox-close-protect-error': 'Errore durante la protezione della procedura',
				'toolbox-purge-wait': 'Purge della pagina di procedura in corso...'
			}
		},

		msg: function ( nome ) {
			var params = Array.prototype.slice.call( arguments );
			params[0] = 'PDC-' + nome;
			return mw.message.apply( this, params ).text();
		},

		l10nMsg: function ( nome ) {
			var params = Array.prototype.slice.call( arguments );
			params[0] = 'PDC-opzione-' + nome;
			if ( mw.messages.exists( params[0] ) === false ) {
				mw.messages.set( params[0], this.config[nome] );
			}
			return mw.message.apply( this, params ).text();
		},

		sysop: ( mw.config.get( 'wgUserGroups' ).indexOf( 'sysop' ) !== -1 || mw.config.get( 'wgUserName' ) === 'Ricordisamoa' ),

		/**
		 * Visualizza un messaggio come contenuto della finestra di dialogo creata dallo script.
		 * @param {string|jQuery} contenuto - Il contenuto da visualizzare
		 */
		dialogo: function ( contenuto ) {
			$( '#PDC-dialog' ).empty().append( contenuto );
		},

		/**
		 * Visualizza uno spinner con un messaggio nella finestra di dialogo.
		 * @param {string|jQuery} messaggio - Il messaggio da visualizzare
		 * @param {jQuery} [box] - L'elemento HTML con cui contenere il messaggio, in modalità toolbox
		 */
		progresso: function ( messaggio, box ) {
			messaggio = this.msg( messaggio );
			console.info( messaggio );
			var $d = $( '#PDC-dialog' );
			if ( $d.length === 1 ) {
				var $l = $d.find( '.PDC-spinner-label' );
				if ( $l.length === 1 ) {
					$l.empty().append( messaggio );
				} else {
					this.dialogo( [
						$( '<span>' )
						.addClass( 'PDC-spinner-label' )
						.append( messaggio ),
						'<br><br>',
						$.createSpinner( {
							size: 'large',
							type: 'block'
						} )
					] );
				}
			} else {
				var $tb = $( '#PDC-toolbox' );
				if ( $tb.length === 1 ) {
					if ( $tb.find( '.mw-spinner' ).size() === 0 ) {
						$.createSpinner( {
							size: 'large'
						} ).css( {
							float: 'right',
							margin: '2em'
						} ).prependTo( $tb );
					}
					box.empty().append( messaggio );
				}
			}
		},

		/**
		 * Visualizza un messaggio di errore nella finestra di dialogo.
		 * @param {string} messaggio - Il codice corrispondente al messaggio di errore da visualizzare
		 * @param {Object|string} [dati] - Eventuali dettagli sull'errore
		 * @param {jQuery} [box] - L'elemento HTML con cui contenere il messaggio, in modalità toolbox
		 */
		errore: function ( messaggio, dati, box ) {
			messaggio = this.msg( messaggio );
			if ( dati ) {
				if ( dati.error && dati.error.info ) {
					dati = dati.error.info;
				}
				messaggio = this.msg( 'error-msg', messaggio, dati );
			}
			console.error( messaggio );
			if ( $( '#PDC-dialog' ).length === 1 ) {
				this.dialogo(
					$( '<p>' )
					.addClass( 'error' )
					.append( messaggio )
				);
			} else {
				var $tb = $( '#PDC-toolbox' );
				if ( $tb.length === 1 ) {
					$tb.find( '.mw-spinner' ).remove();
					box.empty()
					.addClass( 'error' )
					.append( messaggio );
				}
			}
		},

		/**
		 * Restituisce il titolo della pagina relativa a una procedura di cancellazione.
		 * @param {string} procedura - La procedura di cancellazione
		 * @return {jQuery.Promise}
		 */
		titoloPagina: function ( procedura ) {
			var self = this;
			return self.api.get( {
				action: 'query',
				format: 'json',
				prop: 'revisions',
				titles: procedura,
				rvprop: 'content',
				rvlimit: 1
			} )
			.then( function ( data ) {
				var rev = data.query.pages[Object.keys( data.query.pages )[0]].revisions,
				m = ( rev[0]['*'] || '' ).match( /\{\{\s*[Cc]ancellazione\/proposta\s*\|\s*(1\s*\=\s*)?([^\{\|\}]+)\s*(\}\}|\|)/ );
				if ( m ) {
					return m[2];
				}
			} );
		},

		/**
		 * Verifica i requisiti di apertura delle procedure da parte di un utente.
		 * vedi [[Wikipedia:Requisiti di voto#Requisiti relativi alle votazioni sulle pagine]]
		 * @param {string} [utente] - Il nome dell'utente del quale verificare i contributi
		 * @return {jQuery.Promise}
		 */
		verificaRequisiti: function ( utente ) {
			if ( utente === undefined ) {
				utente = mw.config.get( 'wgUserName' );
			}
			if ( mw.config.get( 'wgDBname' ) === 'testwiki' ) {
				return $.Deferred().resolve( true );
			}
			var self = this;
			return self.api.get( {
				action: 'query',
				format: 'json',
				list: 'users|usercontribs',
				usprop: 'editcount',
				ususers: utente,
				ucuser: utente,
				ucprop: 'timestamp',
				ucdir: 'newer',
				uclimit: 1
			} )
			.then( function ( data ) {
				if ( !data.query || !data.query.users || data.query.users.length !== 1 ) {
					return false;
				}
				var user = data.query.users[0];
				if ( !user.name || user.name !== utente || !user.editcount || user.editcount < self.config.minEdits || !data.query.usercontribs ) {
					return false;
				}
				var uc = data.query.usercontribs;
				if ( uc.length !== 1 || !uc[0].user || !uc[0].timestamp || ( new Date() - new Date( uc[0].timestamp ) ) / 86400000 < self.config.minDaysOld ) {
					return false;
				}
				return true;
			} );
		},

		contributori: [],
		ottieniContributori: function ( titolo, callback, continua ) {
			var self = this;
			self.api.get(
				$.extend( {
					action: 'query',
					format: 'json',
					prop: 'revisions',
					titles: titolo,
					rvprop: 'user',
					rvlimit: 'max'
				},
				continua || {} )
			)
			.done( function ( data ) {
				try {
					$.each( data.query.pages[Object.keys( data.query.pages )[0]].revisions, function () {
						if ( this.user ) {
							self.contributori.push( this );
						}
					} );
				} catch ( e ) {
					console.warn( e );
				}
				if ( data['query-continue'] && data['query-continue'].revisions ) {
					self.ottieniContributori( titolo, callback, data['query-continue'].revisions );
				} else {
					callback( self.contributori );
				}
			} );
		},

		maggiorContributore: function ( contributori ) {
			var t = {};
			$.each( contributori, function ( i, rv ) {
				if ( rv.anon === undefined ) {
					if ( t[rv.user] ) {
						t[rv.user] = t[rv.user] + 1;
					} else {
						t[rv.user] = 1;
					}
				}
			} );
			var x = Object.keys( t ).sort( function ( a, b ) {
				return ( ( t[a] > t[b] ) ? -1 : ( ( t[a] < t[b] ) ? 1 : 0 ) );
			} ),
			r = x[0];
			$.each( t, function ( k, v ) {
				if ( k != x[0] && v == t[x[0]] ) {
					r = null;
					return;
				}
			} );
			return r;
		},

		/**
		 * Aggiunge il template {{Cancellazione}} all'inizio di una pagina.
		 * @param {string} titolo - Il titolo della pagina proposta per la cancellazione
		 * @param {integer} numero - Il numero della procedura di cancellazione
		 * @param {Array.<string>} argomenti - Gli eventuali argomenti al quale la pagina è relativa
		 * @return {jQuery.Promise}
		 */
		avvisoVoce: function ( titolo, numero, argomenti ) {
			argomenti = $.map( ['', '2'], function ( suf, i ) {
				if ( argomenti.length > i ) {
					return '|arg' + suf + '=' + argomenti[i];
				}
			} )
			.join( '' );
			return this.api.postWithToken( 'edit', {
				action: 'edit',
				format: 'json',
				title: titolo,
				summary: this.l10nMsg( 'baseSummary', this.config.nominationNoticeSummary ),
				prependtext: '<noinclude>{{' + this.config.nominationNoticeTemplate + argomenti + '}}</noinclude>\n',
				nocreate: 1
			} );
		},

		/**
		 * Rimuove il template {{Cancellazione}} da una pagina.
		 * @param {string} titolo - Il titolo della pagina dalla quale rimuovere l'avviso
		 * @return {jQuery.Promise}
		 */
		rimuoviAvvisoVoce: function ( titolo ) {
			this.progresso( 'remove-wait' );
			return this.api.postWithToken( 'edit', {
				action: 'edit',
				format: 'json',
				title: titolo,
				summary: this.l10nMsg( 'baseSummary', this.config.removeSummary ),
				text: newText,
				nocreate: 1
			} );
		},

		/**
		 * Aggiunge il template {{Mantenuta}} nella discussione di una pagina.
		 * @param {string} titolo - Il titolo della pagina sopravvissuta a una richiesta di cancellazione
		 * @param {boolean} votazione - Se la procedura di cancellazione si è svolta con voto
		 * @param {number} numero - Il numero della procedura di cancellazione
		 * @param {number} favorevoli - Il numero di voti favorevoli alla cancellazione
		 * @param {number} contrari - Il numero di voti contrari alla cancellazione
		 * @return {jQuery.Promise}
		 */
		mantenuta: function ( titolo, votazione, numero, favorevoli, contrari ) {
			var d = new Date(),
			tmp = '{{' + this.config['kept' + ( votazione ? 'AfterPoll' : '' ) + 'TalkTemplate'] + '|' + mw.config.get( 'wgMonthNames' )[d.getMonth() + 1] + '|' + d.getDate() + '|' + d.getFullYear() + '|' + titolo + '|' + ( numero && numero !== null ? numero : '' );
			if ( votazione ) {
				tmp += '|' + favorevoli + '|' + contrari;
			}
			tmp += '}}';
			return this.api.postWithToken( 'edit', {
				action: 'edit',
				format: 'json',
				title: titolo,
				section: 0,
				summary: this.l10nMsg( 'baseSummary', this.config['kept' + ( votazione ? 'AfterPoll' : '' ) + 'Summary'] ),
				appendtext: tmp,
				nocreate: 1
			} );
		},

		/**
		 * Aggiunge il template {{Cancellazione}} in una nuova sezione di una o più pagine di discussione.
		 * @param {string} titolo - Il titolo della pagina da proporre per la cancellazione
		 * @param {Array.<string>} discussioni - I titoli delle pagine di discussione degli utenti o dei progetti da avvisare
		 * @return {jQuery.Promise}
		 */
		notificaProcedura: function ( titolo, discussioni ) {
			var self = this,
			deferreds = [],
			sectionTitle = self.l10nMsg( 'notificationNewSectionTitle', titolo ),
			sectionContent = '{{' + self.config.notificationNewSectionTemplate + '|' + titolo + '}}--~~~~';
			$.each( discussioni, function ( i, discussione ) {
				deferreds.push(
					self.api.newSection( discussione, sectionTitle, sectionContent )
					.done( function () {
						console.info( self.msg( 'notify-done', discussione ) );
					} )
				);
			} );
			return $.when.apply( $, deferreds );
		},

		/**
		 * Crea la procedura di cancellazione.
		 * @param {string} titolo - Il titolo della pagina da proporre per la cancellazione
		 * @param {string} motivazione - La motivazione per la quale proporre la cancellazione della pagina
		 * @return {jQuery.Promise}
		 */
		creaProcedura: function ( titolo, motivazione ) {
			var numero = 1,
				procedura = this.config.base + '/' + titolo;
			return this.api.postWithToken( 'edit', {
				action: 'edit',
				format: 'json',
				title: procedura,
				summary: this.l10nMsg( 'baseSummary', this.config.newNominationSummary ),
				text: '{{' + this.config.newNominationTemplate + '}}\n\n' + motivazione + ' --~~~~',
				createonly: 1
			} );
		},

		/**
		 * Annulla una procedura di cancellazione.
		 * @param {string} titolo - Il titolo della procedura da annullare
		 * @param {string} motivazione - La motivazione per la quale la procedura va annullata
		 * @return {jQuery.Promise}
		 */
		annullaProcedura: function ( titolo, motivazione ) {
		},

		/**
		 * Passa alla modalità consensuale.
		 * @param {string} titolo - Il titolo della procedura di cancellazione (già esistente)
		 * @param {string} motivazione - La motivazione per la quale l'utente intende opporsi alla cancellazione tacita della pagina
		 * @return {jQuery.Promise}
		 */
		consensuale: function ( titolo, motivazione ) {
			return this.api.postWithToken( 'edit', {
				action: 'edit',
				format: 'json',
				title: titolo,
				summary: this.l10nMsg( 'baseSummary', this.config.consensualeStartSummary ),
				appendtext: '{{' + this.config.consensualeStartTemplate + '}}\n\n' + motivazione.trim() + ' --~~~~',
				nocreate: 1
			} );
		},

		/**
		 * Proroga una procedura di cancellazione
		 * @param {string} titolo - Il titolo della procedura di cancellazione (già esistente)
		 * @param {integer} giorni - Il numero di giorni per i quali prorogare la procedura
		 * @return {jQuery.Promise}
		 */
		prorogaProcedura: function ( titolo, giorni ) {
			var giorniArg;
			if ( giorni === this.config.deferDefaultDays ) {
				giorniArg = '';
			} else {
				giorniArg = '|' + giorni;
			}
			return this.api.postWithToken( 'edit', {
				action: 'edit',
				format: 'json',
				title: titolo,
				summary: this.l10nMsg( 'baseSummary', this.l10nMsg( 'deferStartSummary', giorni ) ),
				appendtext: '\n\n{{' + this.config.deferStartTemplate + giorniArg + '}}',
				nocreate: 1
			} );
		},

		/**
		 * Per gli amministratori: passa alla modalità votazione.
		 * @param {string} titolo - Il titolo della procedura di cancellazione (già esistente)
		 * @return {jQuery.Promise}
		 */
		avviaVotazione: function ( titolo ) {
			return this.api.postWithToken( 'edit', {
				action: 'edit',
				format: 'json',
				title: titolo,
				summary: this.l10nMsg( 'baseSummary', this.config.voteStartSummary ),
				appendtext: '\n\n{{' + this.config.voteStartTemplate + '}}',
				nocreate: 1
			} );
		},

		/**
		 * Vota a favore o contro la cancellazione di una pagina.
		 * @param {string} titolo - Il titolo della procedura di cancellazione (già esistente)
		 * @param {string} tipo - Il tipo di voto da esprimere ("Mantenere", "Cancellare", o "Astenuti")
		 * @param {string} motivazione - La motivazione (facoltativa) per il voto espresso
		 * @return {jQuery.Promise}
		 */
		vota: function ( titolo, tipo, motivazione ) {
			return this.api.postWithToken( 'edit', {
				action: 'edit',
				format: 'json',
				title: titolo,
				section: sezione,
				summary: this.l10nMsg( 'baseSummary', this.config.voteSummary ),
				appendtext: '\n# ' + motivazione.trim() + ( motivazione.trim() !== '' ? ' ' : '' ) + '--~~~~',
				nocreate: 1
			} );
		},

		/**
		 * Controlla se una pagina contiene già un avviso di cancellazione.
		 * @param {string} titolo - Il titolo della pagina da controllare
		 * @return {jQuery.Promise}
		 */
		inCancellazione: function ( titolo ) {
			return this.api.get( {
				action: 'query',
				format: 'json',
				titles: titolo,
				prop: 'templates',
				tltemplates: this.config.baseTemplate
			} )
			.then( function ( data ) {
				if ( data.query && data.query.pages ) {
					var pages = data.query.pages;
					return (
						Object.keys( pages ).length === 1 &&
						( pages[Object.keys( pages )[0]].templates || [] ).length === 1
					);
				}
				return false;
			} );
		},

		/**
		 * Controlla se esiste già una procedura di cancellazione (in corso o terminata) riguardante una pagina.
		 * @param {string} titolo - Il titolo della pagina da controllare
		 * @return {jQuery.Promise}
		 */
		proceduraEsistente: function ( titolo ) {
		},

		/**
		 * Controlla lo stato di una procedura di cancellazione.
		 * @param {string} titolo - Il titolo della procedura da controllare
		 * @return {jQuery.Promise}
		 */
		statoProcedura: function ( titolo ) {
			return this.api.get( {
				action: 'query',
				format: 'json',
				titles: titolo,
				prop: 'categories|revisions',
				rvprop: 'timestamp|user',
				cllimit: 'max',
				rvdir: 'newer',
				rvlimit: 1
			} )
			.then( function ( data ) {
				if ( data.query && data.query.pages && Object.keys( data.query.pages ).length === 1 ) {
					var stato = {},
					page = data.query.pages[Object.keys( data.query.pages )[0]];
					$.each( page.categories || [], function () {
						if ( this.title === 'Categoria:Procedure di cancellazione in corso' ) {
							stato.terminata = false;
						} else if ( this.title === 'Categoria:Procedure di cancellazione protette' ) {
							stato.terminata = true;
						}
						var inizio = this.title.match( /^Categoria\:Cancellazioni del (\d\d? .+ \d{4})$/ ),
						consensuale = this.title.match( /^Categoria\:Cancellazioni consensuali del (\d\d? .+ \d{4})$/ ),
						prorogata = this.title.match( /^Categoria\:Cancellazioni consensuali prorogate del (\d\d? .+ \d{4})$/ ),
						votazione = this.title.match( /^Categoria\:Cancellazioni con votazione del (\d\d? .+ \d{4})$/ );
						if ( inizio ) {
							stato.inizio = inizio[1];
						}
						if ( consensuale ) {
							stato.consensuale = consensuale[1];
						}
						if ( prorogata ) {
							stato.prorogata = prorogata[1];
						}
						if ( votazione ) {
							stato.votazione = votazione[1];
						}
					} );
					if ( page.revisions && page.revisions.length === 1 ) {
						stato.creazione = page.revisions[0];
					}
					return stato;
				}
			} );
		},

		/**
		 * Per gli amministratori: protegge la procedura di cancellazione, una volta terminata.
		 * @param {string} titolo - Il titolo della procedura da proteggere
		 * @return {jQuery.Promise}
		 */
		proteggiPagina: function ( titolo ) {
			return this.api.postWithToken( 'protect', {
				action: 'protect',
				format: 'json',
				title: titolo,
				protections: this.config.protectLevel,
				reason: this.config.protectReason
			} );
		},

		/**
		 * Per gli amministratori: cancella una pagina.
		 * @param {string} titolo - Il titolo della pagina da cancellare
		 * @param {string} procedura - Il titolo della procedura di cancellazione
		 * @param {string} motivazione - La motivazione per la quale la pagina va cancellata
		 * @return {jQuery.Promise}
		 */
		cancellaPagina: function ( titolo, procedura, modalità ) {
			return this.api.postWithToken( 'edit', {
				action: 'delete',
				title: titolo,
				reason: this.l10nMsg( 'baseSummary', this.l10nMsg( modalità + 'DeletedReason', procedura ) )
			} );
		},

		/**
		 * Per gli amministratori: notifica l'avvenuta cancellazione di una pagina.
		 * @param {string} titolo - Il titolo della procedura di cancellazione (terminata)
		 * @param {string} modalità - La modalità della procedura di cancellazione
		 * @return {jQuery.Promise}
		 */
		avvisoCancellata: function ( titolo, modalità ) {
			return this.api.postWithToken( 'edit', {
				action: 'edit',
				format: 'json',
				title: titolo,
				appendtext: '\n\n{{' + this.l10nMsg( modalità + 'DeletedTemplate' ) + '}}',
				summary: this.l10nMsg( 'baseSummary', this.config[modalità + 'DeletedSummary'] ),
				nocreate: 1
			} );
		},

		/**
		 * Purga la cache del server relativa a una pagina, compresa la cache dei link (utile per le categorie).
		 * @param {string} titolo - Il titolo della pagina da purgare
		 * @return {jQuery.Promise}
		 */
		purgaPagina: function ( titolo ) {
			return this.api.get( {
				action: 'purge',
				forcelinkupdate: 1,
				titles: titolo
			} );
		},

		opzione: function ( nome ) {
			var params = Array.prototype.slice.call( arguments );
			params[0] = 'option-' + nome;
			return $( '<label>' )
			.append(
				$( '<input>' )
				.attr( {
					type: 'checkbox',
					id: 'PDC-option-' + nome
				} )
			)
			.append( this.msg.apply( this, params ) );
		},

		scegliArgomento: function ( request, response ) {
			var self = this;
			self.api.get( {
				list: 'allcategories',
				acprefix: self.config.afdCatPrefix,
				acprop: '',
				acfrom: self.config.afdCatPrefix + request.term,
				aclimit: 10
			} )
			.done( function ( data ) {
				response( $.map( data.query.allcategories, function ( e ) {
					return e['*'].replace( self.config.afdCatPrefix, '' );
				} ) );
			} );
		},

		/**
		 * Avvia una finestra di dialogo per guidare l'utente durante l'avvio della procedura.
		 * @param {string} titolo - Il titolo della pagina della quale proporre la cancellazione
		 */
		proceduraGuidata: function ( titolo ) {
			var self = this;
			titolo = titolo.replace( /_/g, ' ' );
			mw.loader.using( self.dependencies.dialog )
			.done( function () {
				var cancelButton = {
					text: self.msg( 'dialog-button-cancel' ),
					specialButton: 'cancel',
					click: function () {
						$( this ).dialog( 'destroy' ).remove();
					}
				};
				$( '<div>' )
				.attr( 'id', 'PDC-dialog' )
				.append(
					self.msg( 'process-init', titolo, '<a href="' + mw.util.getUrl( self.config.help ) + '">' + self.config.help + '</a>' )
				)
				.dialog( {
					title: self.msg( 'dialog-title' ),
					modal: true,
					width: 'auto',
					close: function () {
						$( this ).dialog( 'destroy' ).remove();
					},
					buttons: [
						cancelButton,
						{
							text: self.msg( 'dialog-button-proceed' ),
							specialButton: 'proceed',
							click: function () {
								var dialog = $( this );
								self.progresso( 'process-loading-contributors' );
								self.ottieniContributori( titolo, function ( contributori ) {
									var opzioni = [
										self.msg( 'process-confirm', titolo ),
										$( '<textarea>' )
										.addClass( 'mw-ui-input' )
										.css( 'background', '#fff' )
										.attr( {
											id: 'PDC-option-reason',
											placeholder: self.msg( 'option-reason' )
										} )
									],
									creatore = contributori[contributori.length - 1],
									magg = self.maggiorContributore( contributori );
									if ( creatore.anon === undefined && creatore.user !== mw.config.get( 'wgUserName' ) ) {
										opzioni.push( self.opzione( 'notify-creator', creatore.user ) );
									}
									if ( magg !== null && magg !== creatore.user && magg !== mw.config.get( 'wgUserName' ) ) {
										opzioni.push( self.opzione( 'notify-biggest', magg ) );
									}
									for ( var i = 1; i < opzioni.length; i = i + 2 ) {
										opzioni.splice( i, 0, '<br>' );
									}
									opzioni.push( '<br>' );
									opzioni.push(
										$( '<label>' )
										.attr( 'for', 'PDC-option-topic1' )
										.append( self.msg( 'option-notify-topics' ) )
									);
									opzioni.push(
										$( '<input>' )
										.attr( 'id', 'PDC-option-topic1' )
										.autocomplete( {
											source: function ( request, response ) {
												self.scegliArgomento( request, response );
											}
										} )
									);
									opzioni.push(
										$( '<label>' )
										.attr( 'for', 'PDC-option-topic2' )
										.append( '+' )
									);
									opzioni.push(
										$( '<input>' )
										.attr( 'id', 'PDC-option-topic2' )
										.autocomplete( {
											source: function ( request, response ) {
												self.scegliArgomento( request, response );
											}
										} )
									);
									opzioni.push( '<br>' );
									opzioni.push( self.opzione( 'notify-wikiprojects' ) );
									var form = $( '<form>' )
									.append( opzioni )
									.submit( function ( event ) {
										event.preventDefault();
									} );
									self.dialogo( form );
									// ricrea i pulsanti per cambiare la funzione di "Procedi"
									dialog.dialog( 'option', 'buttons', [
										cancelButton,
										{
											text: self.msg( 'dialog-button-proceed' ),
											specialButton: 'proceed',
											click: function () {
												var $motivazione = $( '#PDC-option-reason' ),
												motivazione = $motivazione.val().trim().replace( /\s*(\-\-)?\~{4}$/, '' );
												if ( motivazione.length === 0 ) {
													$motivazione.get( 0 ).setCustomValidity( self.msg( 'option-reason-missing' ) );
													$motivazione.parents( 'form' ).submit();
												} else {
													$motivazione.get( 0 ).setCustomValidity( '' );
													var argomenti = $.map( [1, 2], function ( n ) {
														return $( '#PDC-option-topic' + n ).val().trim();
													} )
													.filter( function ( el, i, arr ) {
														return el !== '' && arr.indexOf( el ) === i;
													} );
													var daNotificare = $.map( {
														creator: creatore.user,
														biggest: magg
													}, function ( user, opt ) {
														if ( $( '#PDC-option-notify-' + opt ).prop( 'checked' ) === true ) {
															return self.namespaces[3] + ':' + user;
														}
													} );
													var pTalk = self.config.wikiprojectNamespace + 1;
													if ( $( '#PDC-option-notify-wikiprojects' ).prop( 'checked' ) === true && pTalk in self.namespaces ) {
														pTalk = self.namespaces[pTalk] + ':';
														daNotificare = daNotificare.concat( $.map( argomenti, function ( arg ) {
															return pTalk + arg;
														} ) );
													}
													self.creaProcedura( titolo, motivazione )
													.done( function ( procedura, numero ) {
														self.avvisoVoce( titolo, numero, argomenti )
														.done( function () {
															self.progresso( 'notify-wait' );
															self.notificaProcedura( titolo, daNotificare )
															.done( function () {
																window.location = mw.util.getUrl( procedura );
															} )
															.fail( function () {
																self.errore( 'notify-error' );
															} );
														} )
														.fail( function () {
															self.errore( 'nominate-error' );
														} );
														self.progresso( 'nominate-wait' );
													} )
													.fail( function () {
														self.errore( 'new-nomination-error' );
													} );
													self.progresso( 'new-nomination-wait' );
												}
											}
										}
									] );
								} );
							}
						}
					]
				} );
			} );
		},

		switchButtons: function ( $obj, show ) {
			var m = show ? 'show' : 'hide';
			if ( show ) {
				$obj.next().remove();
			}
			return $obj[m]();
		},

		/**
		 * Trasforma alcune frasi appositamente configurate
		 * in link per richiedere la cancellazione della pagina.
		 */
		autoRfd: function () {
			var self = this;
			if ( self.config.autoRfd.length === 0 ) {
				return;
			}
			$( 'div' ).each( function () {
				$( this )
				.contents()
				.filter( function () {
					// solo testo semplice
					return this.nodeType === this.TEXT_NODE;
				} )
				.each( function () {
					var htmlDiv = this;
					$.each( self.config.autoRfd, function ( replIdx, replParts ) {
						// cerca la frase intera,
						var find = htmlDiv.textContent.indexOf( replParts.join( '' ) );
						if ( find !== -1 ) {
							// ...la isola
							var node = htmlDiv.splitText( find + replParts[0].length );
							// ...e la rende cliccabile
							$( node.splitText( replParts[1].length ).previousSibling )
							.wrap( '<a>' ).parent()
							.attr( {
								href: '#',
								title: self.msg( 'menu-link-tooltip' )
							} )
							.click( function ( event ) {
								event.preventDefault();
								self.proceduraGuidata( mw.config.get( 'wgPageName' ) );
							} );
						}
					} );
				} );
			} );
		},

		/**
		 * Genera il contenitore per pulsanti che richiedono permessi di amministratore.
		 * @param {Object} stato - Lo stato della procedura di cancellazione
		 * @return {jQuery}
		 */
		buildSysopButtons: function ( stato ) {
			var self = this,
			$sysopButtons = $( '<div>' )
			.attr( 'id', 'PDC-toolbox-sysop' )
			.append( [
				// Pulsante "avvia votazione" con effetto immediato
				$( '<button>' )
				.addClass( 'mw-ui-button mw-ui-constructive' )
				.attr( !stato.votazione && stato.consensuale ? {} : { disabled: 'disabled' } )
				.text( self.msg( 'toolbox-vote-start' ) )
				.click( function ( event ) {
					event.preventDefault();
					var $cont = $( this ).prev();
					$cont.next().remove();
					$cont.after( '<p>' + self.msg( 'toolbox-vote-start-wait' ) + '</p>' );
					self.avviaVotazione( mw.config.get( 'wgPageName' ) )
					.done( function () {
						window.location.reload();
					} )
					.fail( function () {
						$cont.next().remove();
						$cont.after( self.msg( 'toolbox-vote-start-error' ) );
					} );
				} ),
				'&nbsp;',
				// Pulsante "chiudi la procedura" con conferma richiesta
				$( '<button>' )
				.addClass( 'mw-ui-button mw-ui-progressive' )
				.text( self.msg( 'toolbox-close' ) )
				.click( function ( event ) {
					event.preventDefault();
					$( '<div>' )
					.append( [
						// Cancellare la pagina?
						self.msg( 'toolbox-close-delete' ),
						'<br>',
						// Sì
						$( '<button>' )
						.addClass( 'mw-ui-button mw-ui-destructive' )
						.text( self.msg( 'toolbox-close-delete-yes' ) )
						.click( function ( event ) {
							event.preventDefault();
							var $div = $( this ).parent(),
								modalità = stato.consensuale ? 'consensuale' : 'simple';
							self.progresso( 'toolbox-close-delete-wait', $div );
							self.cancellaPagina( stato.pagina, mw.config.get( 'wgPageName' ), modalità )
							.done( function () {
								self.progresso( 'toolbox-close-notice-wait', $div );
								self.avvisoCancellata( mw.config.get( 'wgPageName' ), modalità )
								.done( function () {
									self.progresso( 'toolbox-close-protect-wait', $div );
									self.proteggiPagina( mw.config.get( 'wgPageName' ) )
									.done( function () {
										self.progresso( 'toolbox-purge-wait', $div );
										self.purgaPagina( mw.config.get( 'wgPageName' ) )
										.done( function () {
											window.location.reload();
										} );
									} )
									.fail( function ( code, info ) {
										self.errore( 'toolbox-close-protect-error', info, $div );
									} );
								} )
								.fail( function ( code, info ) {
									self.errore( 'toolbox-close-notice-error', info, $div );
								} );
							} )
							.fail( function ( code, info ) {
								self.errore( 'toolbox-close-delete-error', info, $div );
							} );
						} ),
						'&nbsp;',
						// No
						$( '<button>' )
						.addClass( 'mw-ui-button mw-ui-constructive' )
						.text( self.msg( 'toolbox-close-delete-no' ) )
						.click( function ( event ) {
							event.preventDefault();
							var $div = $( this ).parent();
							self.mantenuta( stato.pagina, votazione, numero, favorevoli, contrari )
							.done( function () {
								self.progresso( 'toolbox-close-protect-wait', $div );
								self.proteggiPagina( mw.config.get( 'wgPageName' ) )
								.done( function () {
									self.progresso( 'toolbox-purge-wait', $div );
									self.purgaPagina( mw.config.get( 'wgPageName' ) )
									.done( function () {
										window.location.reload();
									} );
								} )
								.fail( function ( code, info ) {
									self.errore( 'toolbox-close-protect-error', info, $div );
								} );
							} )
							.fail( function ( code, info ) {
								self.errore( 'toolbox-close-kept-error', info, $div );
							} );
							self.progresso( 'toolbox-close-kept-wait', $div );
						} ),
						'&nbsp;',
						// Annulla
						$( '<button>' )
						.addClass( 'mw-ui-button' )
						.text( self.msg( 'toolbox-close-cancel' ) )
						.click( function ( event ) {
							event.preventDefault();
							self.switchButtons( $sysopButtons, true );
						} )
					] )
					.insertAfter( self.switchButtons( $sysopButtons ) );
				} )
			] );
			return $sysopButtons;
		},

		/**
		 * Se lo script è utile nella pagina, carica le dipendenze e lo avvia.
		 */
		preInit: function () {
			if (
				// in modalità di visualizzazione
				mw.config.get( 'wgAction' ) === 'view' &&
				// solo utenti registrati
				mw.user.isAnon() === false &&
				// niente redirect
				mw.config.get( 'wgIsRedirect' ) === false &&
				// niente diff
				mw.util.getParamValue( 'diff' ) === null &&
				// solo ultime versioni
				mw.util.getParamValue( 'oldid' ) === null
			) {
				var self = this,
				sp = mw.config.get( 'wgPageName' ).replace( /_/g, ' ' ).split( '/' ),
				modes = {
					// visualizzare la casella "Strumenti PDC"?
					toolbox: ( sp.length > 1 && sp[0] === self.config.base ),
					// aggiungere il link per la finestra di dialogo alla sezione "Strumenti" della barra laterale?
					portlet: (
						mw.config.get( 'wgIsArticle' ) === true &&
						self.config.actInNamespaces.indexOf( mw.config.get( 'wgNamespaceNumber' ) ) !== -1
					)
				},
				values = $.map( modes, function ( val ) {
					return val;
				} );
				if ( values.indexOf( true ) !== -1 ) {
					self.modes = modes;
					mw.loader.using( self.dependencies.general )
					.done( function () {
						self.init();
					} );
				}
			}
		},

		/**
		 * Avvia lo script senza caricare le dipendenze.
		 */
		init: function () {
			var self = this;
			// Prepara i messaggi nella lingua dell'utente, e in alternativa in inglese.
			self.i18n = $.extend( true, ( self.i18n.en || {} ), ( self.i18n[mw.config.get( 'wgUserLanguage' )] || {} ) );
			$.each( self.i18n, function ( k, v ) {
				mw.messages.set( 'PDC-' + k, v );
			} );
			if ( self.modes.portlet === true ) {
				self.inCancellazione( mw.config.get( 'wgPageName' ) )
				.done( function ( val ) {
					if ( val === false ) {
						self.verificaRequisiti()
						.done( function ( accettato ) {
							if ( accettato !== true ) {
								return;
							}
							$( mw.util.addPortletLink( 'p-tb', '#', self.msg( 'menu-link-label' ), 'PDC-init', self.msg( 'menu-link-tooltip' ) ) )
							.click( function ( event ) {
								event.preventDefault();
								self.proceduraGuidata( mw.config.get( 'wgPageName' ) );
							} );
							self.autoRfd();
						} );
					}
				} );
			}
			if ( self.modes.toolbox === true ) {
				self.verificaRequisiti()
				.done( function ( accettato ) {
					if ( accettato !== true ) {
						return;
					}
					self.titoloPagina( mw.config.get( 'wgPageName' ) )
					.done( function ( titoloPagina ) {
						if ( !titoloPagina ) {
							return;
						}
						self.statoProcedura( mw.config.get( 'wgPageName' ) )
						.done( function ( stato ) {
							stato.pagina = titoloPagina;
							var prorogabile = false,
							adesso = new Date(),
							creazione,
							apertaDaGiorni;
							if ( stato && stato.creazione && stato.creazione.timestamp ) {
								creazione = new Date( stato.creazione.timestamp );
								apertaDaGiorni = ( adesso - creazione ) / 86400000;
								if ( stato.terminata === false && !stato.prorogata && apertaDaGiorni >= self.config.minDeferrableDays ) {
									prorogabile = true;
								}
							}
							var $toolbox = $( '<div>' )
							.attr( 'id', 'PDC-toolbox' )
							.addClass( 'toccolours' )
							.css( 'font-size', '100%')
							.append(
								$( '<h3>' )
								.text( self.msg( 'toolbox-title', stato.pagina ) )
							),
							statusMsg = self.msg( 'toolbox-open-generic' );
							if ( stato.terminata ) {
								statusMsg = self.msg( 'toolbox-closed' );
							} else if ( apertaDaGiorni ) {
								var days,
									user;
								if ( parseInt( apertaDaGiorni ) > 1 ) {
									days = self.msg( 'toolbox-days-ago', parseInt( apertaDaGiorni ) );
								} else if ( adesso.getDate() === creazione.getDate() ) {
									days = self.msg( 'toolbox-today' );
								} else {
									days = self.msg( 'toolbox-yesterday' );
								}
								if ( stato.creazione && stato.creazione.user ) {
									user = stato.creazione.user;
									user = '<a href="' + mw.util.getUrl( self.namespaces[2] + ':' + user ) + '">' + user + '</a>';
								} else {
									user = self.msg( 'toolbox-user-unknown' );
								}
								statusMsg = self.msg( 'toolbox-open', days, user );
							}
							$( '<p>' )
							.append( statusMsg )
							.appendTo( $toolbox );

							/**
							 * Contenitore per pulsanti che non richiedono permessi particolari.
							 */
							var $publicButtons = $( '<div>' )
							.attr( 'id', 'PDC-toolbox-public' )
							.appendTo( $toolbox );

							// Pulsante "aggiorna" con effetto immediato (innocuo)
							$( '<button>' )
							.addClass( 'mw-ui-button' )
							.text( self.msg( 'toolbox-purge' ) )
							.click( function ( event ) {
								event.preventDefault();
								var $box = $( this ).parent();
								self.progresso( 'toolbox-purge-wait', $box );
								self.purgaPagina( mw.config.get( 'wgPageName' ) )
								.done( function () {
									window.location.reload();
								} );
							} )
							.appendTo( $publicButtons );
							$publicButtons.append( '&nbsp;' );
							if ( !stato.terminata ) {
								if ( stato.consensuale ) {
									var deferButtonMsg;
									if ( prorogabile ) {
										deferButtonMsg = 'toolbox-defer';
									} else if ( stato.prorogata ) {
										deferButtonMsg = 'toolbox-already-deferred';
									} else {
										deferButtonMsg = 'toolbox-not-deferrable-yet';
									}
									// Pulsante "proroga" con conferma richiesta
									$( '<button>' )
									.addClass( 'mw-ui-button mw-ui-progressive' )
									.text( self.msg( deferButtonMsg ) )
									.attr( prorogabile ? {} : { disabled: 'disabled' } )
									.click( function ( event ) {
										event.preventDefault();
										$( '<div>' )
										.append( [
											// Di quanti giorni?
											$( '<label>' )
											.attr( 'for', 'PDC-defer-days' )
											.text( self.msg( 'toolbox-defer-days' ) ),
											$( '<input>' )
											.addClass( 'mw-ui-input' )
											.attr( {
												type: 'number',
												id: 'PDC-defer-days',
												min: self.config.deferMinDays,
												max: self.config.deferMaxDays
											} )
											.val( self.config.deferDefaultDays ),
											// Conferma
											$( '<button>' )
											.addClass( 'mw-ui-button mw-ui-constructive' )
											.text( self.msg( 'toolbox-defer' ) )
											.click( function ( event ) {
												event.preventDefault();
												var $box = $( this ).parent();
												self.progresso( 'toolbox-defer-wait', $box );
												self.prorogaProcedura( mw.config.get( 'wgPageName' ), parseInt( $( this ).prev().val() ) )
												.done( function () {
													self.progresso( 'toolbox-purge-wait', $box );
													self.purgaPagina( mw.config.get( 'wgPageName' ) )
													.done( function () {
														window.location.reload();
													} );
												} )
												.fail( function ( code, info ) {
													self.errore( 'toolbox-defer-error', info, $box );
												} );
											} ),
											'&nbsp;',
											// Annulla
											$( '<button>' )
											.addClass( 'mw-ui-button' )
											.text( self.msg( 'toolbox-defer-cancel' ) )
											.click( function ( event ) {
												event.preventDefault();
												self.switchButtons( $publicButtons, true );
											} )
										] )
										.insertAfter( self.switchButtons( $publicButtons ) );
									} )
									.appendTo( $publicButtons );
								} else {
									// Pulsante "passa alla modalità consensuale" con conferma richiesta
									$( '<button>' )
									.addClass( 'mw-ui-button mw-ui-progressive' )
									.text( self.msg( 'toolbox-consensuale' ) )
									.click( function ( event ) {
										event.preventDefault();
										$( '<div>' )
										.append( [
											// Motivazione
											$( '<textarea>' )
											.addClass( 'mw-ui-input' )
											.css( 'background', '#fff' )
											.attr( 'placeholder', self.msg( 'toolbox-consensuale-reason' ) ),
											// Conferma
											$( '<button>' )
											.addClass( 'mw-ui-button mw-ui-constructive' )
											.text( self.msg( 'toolbox-consensuale' ) )
											.click( function ( event ) {
												event.preventDefault();
												var $box = $( this ).parent();
												self.consensuale( mw.config.get( 'wgPageName' ), $( this ).prev().val() )
												.done( function () {
													window.location.reload();
												} )
												.fail( function ( code, info ) {
													self.errore( 'toolbox-consensuale-error', info, $box );
												} );
												self.progresso( 'toolbox-consensuale-wait', $box );
											} ),
											'&nbsp;',
											// Annulla
											$( '<button>' )
											.addClass( 'mw-ui-button' )
											.text( self.msg( 'toolbox-consensuale-cancel' ) )
											.click( function ( event ) {
												event.preventDefault();
												self.switchButtons( $publicButtons, true );
											} )
										] )
										.insertAfter( self.switchButtons( $publicButtons ) );
									} )
									.appendTo( $publicButtons );
								}
								$publicButtons.append( '&nbsp;' );
								// Pulsante "annulla la procedura" con conferma richiesta
								$( '<button>' )
								.addClass( 'mw-ui-button mw-ui-progressive' )
								.text( self.msg( 'toolbox-cancel' ) )
								.click( function ( event ) {
									event.preventDefault();
									$( '<div>' )
									.append( [
										// Motivazione
										$( '<textarea>' )
										.addClass( 'mw-ui-input' )
										.css( 'background', '#fff' )
										.attr( 'placeholder', self.msg( 'toolbox-cancel-reason' ) ),
										// Conferma
										$( '<button>' )
										.addClass( 'mw-ui-button mw-ui-destructive' )
										.text( self.msg( 'toolbox-cancel' ) )
										.click( function ( event ) {
											event.preventDefault();
											self.annullaProcedura( mw.config.get( 'wgPageName' ), $( this ).prev().val() )
											.done( function () {
												window.location.reload();
											} );
											self.progresso( 'toolbox-cancel-wait', $( this ).parent() );
										} ),
										'&nbsp;',
										// Annulla
										$( '<button>' )
										.addClass( 'mw-ui-button' )
										.text( self.msg( 'toolbox-cancel-cancel' ) )
										.click( function ( event ) {
											event.preventDefault();
											self.switchButtons( $publicButtons, true );
										} )
									] )
									.insertAfter( self.switchButtons( $publicButtons ) );
								} )
								.appendTo( $publicButtons );
							}
							if ( self.sysop && stato.terminata === false ) {
								// Strumenti per amministratori
								$toolbox
								.append( [
									$( '<h4>' )
									.text( self.msg( 'toolbox-sysops' ) ),
									self.buildSysopButtons( stato )
								] );
							}
							$toolbox.prependTo( '#mw-content-text' );
						} );
					} );
				} );
			}
		}
	};
	window.PDC.preInit();
}( mediaWiki, jQuery ) );