MediaWiki:Gadget-Massblock.js: differenze tra le versioni

Contenuto cancellato Contenuto aggiunto
m docfix
+opzione per bloccare la talk anche qui
 
(13 versioni intermedie di uno stesso utente non sono mostrate)
Riga 10:
* see [[:it:MediaWiki:Gadget-Massblock-it.js]]
*
* Memo: only then() can return a new promise object, done() and fail() can't.
*
* @author (i.e. blame him) [[:it:User:Daimona Eaytoy]]
* @todo This should handle the async loop more nicely, and properly use Promise
* rejections.
*/
( function( mw, $ ) {
'use strict';
 
// Default messages
// OOUI element
var submitBtn,
// Like wgBlockAllowsUTEdit
blockAllowsTalkEdit;
 
// Default messages
mw.messages.set( {
'massblock-toolbar-text': 'Massblock',
Line 28 ⟶ 23:
'massblock-page-title': 'Mass-blocking tool',
'massblock-abuse-disclaimer': 'If you abuse this tool, it\'s your fault, not mine.',
'massblock-basic-data': 'Basic data',
'massblock-blockusers': 'Users to block (one on each line, please):',
'massblock-talkmsg': 'Replace talk page with, or text to add if the expiry is not infinite (leave blank to leave no message):',
Line 58 ⟶ 52:
} );
 
// OOUI element
/**
var submitBtn,
* Main form processing routine, called on form submit
// Ideally this would use $wgBlockAllowsUTEdit, but it's not available in JS.
*/
blockAllowsTalkEdit = true,
function doMassBlock() {
mwapi = new mw.Api();
var users = $( "#wpMassBlockUsers textarea" ).val().split( "\n" );
 
users = users
// First trim everything
.map( function( s ) {
return s.trim();
} )
// Then remove blanks and duplicates
.filter( function( el, index, me ) {
return el !== '' && me.indexOf( el ) === index;
} );
 
if ( users.length === 0 ) {
// Easy
return;
}
submitBtn.setDisabled( true );
 
var wpMassBlockReasons = $( "#wpMassBlockReasons select :selected" ).val().trim(),
wpMassBlockReason = $( "#wpMassBlockReason input" ).val().trim(),
blocked = 0,
talkpageedited = 0,
userpageedited = 0,
talkpageprotected = 0,
userpageprotected = 0,
errors = {};
 
var wpMassBlockAnononly = $( "#wpMassBlockAnononly input" ).prop( 'checked' ),
wpMassBlockNocreate = $( "#wpMassBlockNocreate input" ).prop( 'checked' ),
wpMassBlockEmail = $( "#wpMassBlockEmail input" ).prop( 'checked' ),
wpMassBlockAutoblock = $( "#wpMassBlockAutoblock input" ).prop( 'checked' ),
wpMassBlockTalkpage = blockAllowsTalkEdit ? $( "#wpMassBlockTalkpage input" ).prop( 'checked' ) : false,
wpMassBlockReblock = $( "#wpMassBlockReblock input" ).prop( 'checked' ),
wpMassBlockMessage = $( "#wpMassBlockMessage textarea" ).val().trim(),
wpMassBlockTag = $( "#wpMassBlockTag textarea" ).val().trim(),
wpMassBlockExpiry = $( "#wpMassBlockExpiry input" ).val().trim(),
wpMassBlockSummaryTalk = $( "#wpMassBlockSummaryTalk input" ).val().trim(),
wpMassBlockSummaryUser = $( "#wpMassBlockSummaryUser input" ).val().trim(),
wpMassBlockProtectTalk = $( "#wpMassBlockProtectTalk input" ).prop( 'checked' ),
wpMassBlockProtectUser = $( "#wpMassBlockProtectUser input" ).prop( 'checked' );
 
var ErrorHandler = {
errors: {},
/**
* Process an error in any part of the process
Line 114 ⟶ 71:
* which has no hyphen and no page.
*/
var errorHandler =add: function( e, user, action ) {
var obj = { action: e };
if ( !this.errors[ user ] ) {
this.errors[ user ] = [ obj ];
} else {
this.errors[ user ].push( obj );
}
};,
getCodesForUser: function( user ) {
var cb = function( el ) {
var key = Object.keys( el )[ 0 ],
action = key.split( "-" )[ 0 ],
link = '//mediawiki.org/wiki/API:' + action + '#Possible_errors';
return key + ': <code style="color:red">' +
el[ key ] + '</code> (<a href="' + link + '">' +
msg( 'failure-help' ) + '</a>)';
};
return this.errors[ user ].map( cb );
}
};
 
var FormData = {
var isInfty = isInfinity( wpMassBlockExpiry );
init: function() {
// Several actions can only be executed if the block is infinite
this.dropdownReason = $( "#wpMassBlockReasons select :selected" ).val().trim();
wpMassBlockProtectTalk = wpMassBlockProtectTalk && isInfty;
this.otherReason = $( "#wpMassBlockReason input" ).val().trim();
wpMassBlockProtectUser = wpMassBlockProtectUser && isInfty;
this.anononly = $( "#wpMassBlockAnononly input" ).prop( 'checked' );
wpMassBlockTag = isInfty ? wpMassBlockTag : '';
this.nocreate = $( "#wpMassBlockNocreate input" ).prop( 'checked' );
this.noEmail = $( "#wpMassBlockEmail input" ).prop( 'checked' );
this.autoblock = $( "#wpMassBlockAutoblock input" ).prop( 'checked' );
this.talkpageBlocked = blockAllowsTalkEdit ? $( "#wpMassBlockTalkpage input" ).prop( 'checked' ) : true;
this.reblock = $( "#wpMassBlockReblock input" ).prop( 'checked' );
this.talkMessage = $( "#wpMassBlockMessage textarea" ).val().trim();
this.expiry = $( "#wpMassBlockExpiry input" ).val().trim();
this.talkSummary = $( "#wpMassBlockSummaryTalk input" ).val().trim();
this.upSummary = $( "#wpMassBlockSummaryUser input" ).val().trim();
this.protectReason = $( "#wpMassBlockProtectReason input" ).val().trim();
 
this.isInfty = isInfinity( this.expiry );
/**
// *Several Performactions acan singleonly be executed if the block viais APIinfinite
this.protectTalk = $( "#wpMassBlockProtectTalk input" ).prop( 'checked' ) && this.isInfty;
*
this.protectUser = $( "#wpMassBlockProtectUser input" ).prop( 'checked' ) && this.isInfty;
* @param {string} user The user to block
this.upMessage = this.isInfty ? $( "#wpMassBlockTag textarea" ).val().trim() : '';
* @return {Promise}
*/}
};
var doBlock = function( user ) {
return new mw.Api().postWithToken( "csrf", {
action: 'block',
allowusertalk: wpMassBlockTalkpage,
autoblock: wpMassBlockAutoblock,
nocreate: wpMassBlockNocreate,
expiry: wpMassBlockExpiry === "" ? "indefinite" : wpMassBlockExpiry,
anononly: wpMassBlockAnononly,
noemail: wpMassBlockEmail,
reblock: wpMassBlockReblock,
reason: wpMassBlockReasons === "other" ? wpMassBlockReason : wpMassBlockReasons + ( wpMassBlockReason ? ": " + wpMassBlockReason : "" ),
user: user
} );
};
 
var Main = {
/**
blocked: 0,
* The post-block handler. Performs edits and protections.
talkpageedited: 0,
*
userpageedited: 0,
* @param {Object} response The response of the block API call
talkpageprotected: 0,
* @return {Promise} A promise which is resolved after all actions are done
userpageprotected: 0,
* for all pages. This will never be rejected.
*/
var successHandler = function( response ) {
var user = response.block.user,
talkPage = 'User talk:' + user,
userPage = 'User:' + user,
// @var {Promise} These track the state for all actions (edit and protect)
// on every page. They are resolved as soon as a page is processed, with or
// without a failure. This way the final $.when will resolve after all promises
// have been processed, and not after the first rejection.
talkDone = $.Deferred(),
userDone = $.Deferred();
 
_protect: function( page, exists, counter, user ) {
blocked++;
var prType = exists ? 'edit=sysop|move=sysop' : 'create=sysop';
 
return doProtectPage( page, 'edit=sysop|move=sysop' )
if ( wpMassBlockMessage !== "" ) {
.done( function() {
doEditPage( talkPage, wpMassBlockMessage, wpMassBlockSummaryTalk, !isInfty )
.done( function() {this[counter]++;
} )
talkpageedited++;
if.fail( function( wpMassBlockProtectTalke ) {
ErrorHandler.add( e, user, "protect-talk" );
doProtectPage( talkPage, 'edit=sysop|move=sysop' )
} )
.donealways( function() {
talkpageprotected++return $.when();
} );
},
.fail( function( e ) {
errorHandler( e, user, "protect-talk" );
editTalk: function( user ) {
} )
var talkPage = getTalkTitle( user );
.always( function() {
return doEditPage( talkPage, FormData.talkMessage, FormData.talkSummary, !FormData.isInfty )
talkDone.resolve();
} );.then(
} elsefunction() {
talkDonethis.resolve()talkpageedited++;
if ( FormData.protectTalk ) {
return this._protect( talkPage, true, 'talkpageprotected', user );
}
}.bind( this ),
.fail( function( e ) {
errorHandlerErrorHandler.add( e, user, "edit-talk" );
talkDonereturn $.resolvewhen();
} );
);
} else if ( wpMassBlockProtectTalk ) {
},
new mw.Api().get( {
protectTalk: function( user ) {
action: 'query',
titles:var talkPage = getTalkTitle( user );
}mwapi.get( ){
action: 'query',
.then( function( data ) {
titles: talkPage
var exists = Object.keys( data.query.pages )[ 0 ] !== -1,
} )
prType = exists ? 'edit=sysop|move=sysop' : 'create=sysop';
.then(
doProtectPage( talkPage, prType )
.done( function( data ) {
var exists = Object.keys( data.query.pages )[ 0 ] !== -1;
talkpageprotected++;
return this._protect( talkPage, exists, 'talkpageprotected', user );
} )
}.failbind( function( ethis ) {,
errorHandlerfunction( e, user,) "protect-talk" );{
ErrorHandler.add( e, user, "query-talk" );
} )
return $.always( functionwhen() {;
}
talkDone.resolve();
} );
} ),
.fail(editUP: function( euser ) {
var userPage = getUPTitle( user );
errorHandler( e, user, "query-talk" );
doEditPage( userPage, FormData.upMessage, FormData.upSummary )
talkDone.resolve();
} );.then(
} else function() {
this.userpageedited++;
talkDone.resolve();
if ( FormData.protectUser ) {
}
return this._protect( userPage, true, 'userpageprotected', user );
 
if ( wpMassBlockTag !== "" ) {
doEditPage( userPage, wpMassBlockTag, wpMassBlockSummaryUser )
.done( function() {
userpageedited++;
if ( wpMassBlockProtectUser ) {
doProtectPage( userPage, 'edit=sysop|move=sysop' )
.done( function() {
userpageprotected++;
} )
.fail( function( e ) {
errorHandler( e, user, "protect-user" );
} )
.always( function() {
userDone.resolve();
} );
} else {
userDone.resolve();
}
}.bind( this ),
.fail( function( e ) {
errorHandlerErrorHandler.add( e, user, "edit-user" );
userDonereturn $.resolvewhen();
} );
);
} else if ( wpMassBlockProtectUser ) {
},
new mw.Api().get( {
protectUP: function( user ) {
action: 'query',
titles:var userPage = getUPTitle( user );
return mwapi.get( {
} )
action: 'query',
.then( function( data ) {
titles: userPage
var exists = Object.keys( data.query.pages )[ 0 ] !== -1,
} )
prType = exists ? 'edit=sysop|move=sysop' : 'create=sysop';
.then(
doProtectPage( userPage, prType )
.done( function( data ) {
var exists = Object.keys( data.query.pages )[ 0 ] !== -1;
userpageprotected++;
return this._protect( userPage, exists, 'userpageprotected', user );
} )
}.failbind( function( ethis ) {,
errorHandlerfunction( e, user,) "protect-user" );{
ErrorHandler.add( e, user, "query-user" );
} )
return $.always( functionwhen() {;
}
userDone.resolve();
} );
} ),
.fail( function( e ) {
getAlertText: function() {
errorHandler( e, user, "query-user" );
return msg( 'result-alert' )
userDone.resolve();
.replace( '$1', this.blocked )
} );
.replace( '$2', this.talkpageedited )
} else {
.replace( '$3', this.userpageedited )
userDone.resolve();
.replace( '$4', this.talkpageprotected )
}
.replace( '$5', this.userpageprotected );
}
};
 
function getTalkTitle( user ) {
return $.when( talkDone, userDone );
return 'User talk:' + user;
};
}
function getUPTitle( user ) {
return 'User:' + user;
}
 
/**
* The post-block handler. Performs edits and protections.
*
* @param {string} user
* @return {Promise} A promise which is resolved after all actions are done
* for all pages. This will never be rejected.
*/
function successHandler( user ) {
// @var {Promise} These track the state for all actions (edit and protect)
// on every page. They are resolved as soon as a page is processed, with or
// without a failure. This way the final $.when will resolve after all promises
// have been processed, and not after the first rejection.
var talkDone, userDone;
 
Main.blocked++;
 
if ( FormData.talkMessage !== "" ) {
talkDone = Main.editTalk( user );
} else if ( FormData.protectTalk ) {
talkDone = Main.protectTalk( user );
} else {
talkDone = $.when();
}
 
if ( FormData.upMessage !== "" ) {
userDone = Main.editUP( user );
} else if ( FormData.protectUser ) {
userDone = Main.protectUP( user );
} else {
userDone = $.when();
}
 
return $.when( talkDone, userDone );
}
 
/**
* Main form processing routine, called on form submit
*/
function doMassBlock() {
var users = $( "#wpMassBlockUsers textarea" ).val().split( "\n" );
 
users = users
// First trim everything
.map( function( s ) {
return s.trim();
} )
// Then remove blanks and duplicates
.filter( function( el, index, me ) {
return el !== '' && me.indexOf( el ) === index;
} );
 
if ( users.length === 0 ) {
// Easy
return;
}
submitBtn.setDisabled( true );
 
FormData.init();
 
// Array of Promises, one for each user. Each one is resolved after the user
Line 280 ⟶ 288:
deferreds.push(
doBlock( user )
.then(
function( data ) {
return successHandler( datauser );
},
function( e ) {
errorHandler ErrorHandler.add( e, user, "block" );
// Return so that this counts as resolved and won't leave
// other promises unresolved.
return $.when();
}
)
);
} );
 
$.when.apply( $, deferreds ).always( function()doPostBlockActions {);
doPostBlockActions( errors );
OO.ui.alert(
msg( 'result-alert' ).replace( '$1', blocked ).replace( '$2', talkpageedited ).replace( '$3', userpageedited )
.replace( '$4', talkpageprotected ).replace( '$5', userpageprotected )
);
} );
}
 
/**
* Executed after all users have been processed.
*
* @param {Object} errors The errors collected on the way. The structure of
* this object is { username: [ { action: errorcode }, ... ], ... }
*/
function doPostBlockActions( errors ) {
var errors = ErrorHandler.errors;
if ( Object.keys( errors ).length > 0 ) {
var linkedList = ""'';
 
var errorsToCodes = function( el ) {
var key = Object.keys( el )[ 0 ],
action = key.split( "-" )[ 0 ],
link = '//mediawiki.org/wiki/API:' + action + '#Possible_errors';
return key + ': <code style="color:red">' +
el[ key ] + '</code> (<a href="' + link + '">' +
msg( 'failure-help' ) + '</a>)';
};
 
for ( var user in errors ) {
var codes = errors[ user ]ErrorHandler.mapgetCodesForUser( errorsToCodesuser );
linkedList +=
"<li><a href=\"" + mw.config.get( 'wgScript' ) + "?title=Special:Contributions/" + encodeURIComponent( user ) + "\">" + user + "</a>: " +
user + "</a>: " + codes.join( "; " ) + "</li>";
}
$( "#wpMassBlockFailedContainer" ).html(
Line 331 ⟶ 323:
);
}
 
OO.ui.alert( Main.getAlertText() );
}
 
/**
* Perform a single block via API
*
* @param {string} user The user to block
* @return {Promise}
*/
function doBlock( user ) {
return mwapi.postWithToken( "csrf", {
action: 'block',
allowusertalk: !FormData.talkpageBlocked,
autoblock: FormData.autoblock,
nocreate: FormData.nocreate,
expiry: FormData.expiry === "" ? "indefinite" : FormData.expiry,
anononly: FormData.anononly,
noemail: FormData.noEmail,
reblock: FormData.reblock,
reason: FormData.dropdownReason === "other" ? FormData.otherReason : FormData.dropdownReason + ( FormData.otherReason ? ": " + FormData.otherReason : "" ),
user: user
} );
}
 
Line 355 ⟶ 370:
params.text = text;
}
return new mw.Api()mwapi.postWithEditToken( params );
}
 
Line 366 ⟶ 381:
*/
function doProtectPage( title, protections ) {
return new mw.Api()mwapi.postWithToken( 'csrf', {
action: 'protect',
title: title,
protections: protections,
reason: $( "#wpMassBlockProtectReason input" )FormData.val().trim()protectReason,
watchlist: 'nochange'
} );
Line 393 ⟶ 408:
talkTextField, userTextField, talkProtectCb, talkSummaryField,
userSummaryField, userProtectCb, protectReasonField;
 
// Ideally this would use $wgBlockAllowsUTEdit, but it's not available.
blockAllowsTalkEdit = window.___location.href.indexOf( 'it.wikipedia' ) === -1;
 
$( "h1" ).first().html( msg( 'page-title' ) );
Line 412 ⟶ 424:
} );
 
var basicFieldsetmainField = new OO.ui.FieldsetLayout( {
label: msg( 'basic-datablockusers' ),
items: [
new OO.ui.FieldLayoutMultilineTextInputWidget( {
rows: 10,
new OO.ui.MultilineTextInputWidget( {
rowsid: 10'wpMassBlockUsers'
} ), {
label: msg( 'blockusers' ),
align: 'top',
id: 'wpMassBlockUsers'
}
),
new OO.ui.FieldLayout(
talkTextField, {
label: msg( 'talkmsg' ),
align: 'top',
id: 'wpMassBlockMessage'
}
),
new OO.ui.FieldLayout( userTextField, {
label: msg( 'upmsg' ),
align: 'top',
id: 'wpMassBlockTag'
} )
]
Line 574 ⟶ 569:
} );
 
userTextField.on(var 'change',toggleUserTextField = function() {
userSummaryField.setDisabled(var disabled = userTextField.getValue().trim() === '' );||
!isInfinity( $( '#wpMassBlockExpiry input' ).val().trim() );
} );
userSummaryField.setDisabled( disabled );
};
 
userTextField.on( 'change', toggleUserTextField );
 
talkProtectCb =
new OO.ui.CheckboxInputWidget( {
id: 'wpMassBlockProtectTalk',
selected: true
} );
 
userProtectCb =
new OO.ui.CheckboxInputWidget( {
id: 'wpMassBlockProtectUser',
selected: true
} );
 
Line 594 ⟶ 591:
maxLength: 255,
id: 'wpMassBlockProtectReason',
value: msg( 'protect-reason-default' ),
disabled: true
} );
 
Line 601 ⟶ 599:
*/
var toggleProtectionFields = function() {
if (
if ( !talkProtectCb.isSelected() && !userProtectCb.isSelected() ) {
!( talkProtectCb.isSelected() || userProtectCb.isSelected() ) ||
!isInfinity( $( '#wpMassBlockExpiry input' ).val().trim() )
) {
protectReasonField.setDisabled( true );
} else {
Line 614 ⟶ 615:
label: msg( 'further-options-label' ),
items: [
new OO.ui.HorizontalLayout( {
items: [
new OO.ui.FieldLayout(
talkTextField,
{
label: msg( 'talkmsg' ),
align: 'top',
id: 'wpMassBlockMessage',
classes: [ 'massblock-horiz-element' ]
}
),
new OO.ui.FieldLayout(
userTextField,
{
label: msg( 'upmsg' ),
align: 'top',
id: 'wpMassBlockTag',
classes: [ 'massblock-horiz-element' ]
}
)
]
} ),
new OO.ui.FieldLayout( talkSummaryField, {
label: msg( 'talksummary' )
Line 639 ⟶ 662:
userTextField,
talkProtectCb,
userSummaryField,userProtectCb
userProtectCb,
protectReasonField
];
 
Line 647 ⟶ 668:
disableEls[ el ].setDisabled( !enable );
}
 
toggleProtectionFields();
toggleUserTextField();
} );
 
Line 660 ⟶ 684:
.on( 'click', doMassBlock );
 
form.addItems( [ basicFieldsetmainField, blockOpts, furtherOpts, new OO.ui.FieldLayout( submitBtn ) ] );
 
 
Line 683 ⟶ 707:
( /sysop/ ).test( mw.config.get( "wgUserGroups" ) )
) {
var style ='.massblock-horiz-element{ width: 40%; }';
mw.loader.using( [ 'mediawiki.api', 'mediawiki.jqueryMsg', 'oojs-ui-core', 'oojs-ui-widgets', 'oojs-ui-windows' ], $.ready )
mw.util.addCSS( style );
mw.loader.using( [ 'mediawiki.jqueryMsg', 'oojs-ui-core', 'oojs-ui-widgets', 'oojs-ui-windows' ], $.ready )
.done( function loadMsg() {
new mw.Api()mwapi.loadMessagesIfMissing( [ 'Ipbreason-dropdown' ] )
.done( massblockform )
.fail( function ( e ) {
Line 695 ⟶ 721:
} );
} else {
mw.util.addPortletLink( 'p-tb', mw.configutil.getgetUrl( 'wgScript' ) + '?title=Special:Massblock' ), msg( 'toolbar-text' ) );
}
} );