MediaWiki:Gadget-0xBlockMessage.js

Une page de Wikipédia, l'encyclopédie libre.
Note : après avoir enregistré la page, vous devrez forcer le rechargement complet du cache de votre navigateur pour voir les changements.

Mozilla / Firefox / Konqueror / Safari : maintenez la touche Majuscule (Shift) en cliquant sur le bouton Actualiser (Reload) ou pressez Maj-Ctrl-R (Cmd-R sur Apple Mac) ;

Chrome / Internet Explorer / Opera : maintenez la touche Ctrl en cliquant sur le bouton Actualiser ou pressez Ctrl-F5.
/*
 * BlockMessage
 *
 * Permet d'ajouter un modèle notifiant le blocage d'un utilisateur en un clic,
 * une fois le blocage réussi.
 *
 * Auteur : [[User:0x010C]]
 * {{Projet:JavaScript/Script|BlockMessage}}
 */

// Customisation
var templatesList = {
	finite: [
		{
			label: "Bloqué",
			data: '{ "template": "Bloqué|$1|$2" }'
		}, {
			label: "Bloqué sans avertissement",
			data: '{ "template": "Bloqué sans avertissement|$1|$2" }'
		}, {
			label: "Insultes",
			data: '{ "template": "Insultes|$1|$2" }'
		}, {
			label: "IP partagée bloquée",
			data: '{ "template": "IP partagée bloquée|$1|$2" }'
		}, {
			label: "Vandale scolaire bloqué",
			data: '{ "template": "Vandale scolaire bloqué" }',
			'autoselect-time': '15 july 2018'
		}, {
			label: "Proxy",
			data: '{ "template": "Proxy|durée=$1|timestamp={{subst:'+'CURRENTTIMESTAMP}}", "default-subst": false }',
			'autoselect-reason': '[[Wikipédia:Pas de serveurs mandataires ouverts|Proxy ouvert]]'
		}, {
			label: "IP bloquée pour 3 jours",
			data: '{ "template": "Adresse IP bloquée pour trois jours|$3|$1|$2" }'
		},
	],
	infinite: [
		{
			label: "Compte bloqué indéfiniment",
			data: '{ "template": "Compte bloqué indéfiniment|$3", "default-clean": true }'
		}, {
			label: "Vandale bloqué indéfiniment",
			data: '{ "template": "Vandale bloqué indéfiniment", "default-clean": true }'
		}, {
			label: "Vandale bloqué indéfiniment sans avertissement",
			data: '{ "template": "Vandale bloqué indéfiniment sans avertissement", "default-clean": true }'
		}, {
			label: "Bot banni",
			data: '{ "template": "Bot banni" }'
		}, {
			label: "Utilisateur rémunéré bloqué",
			data: '{ "template": "Utilisateur rémunéré bloqué", "default-clean": false }'
		},
	]
};

// I18n
var blockMessageMessages = {
	'en': {
		'blockmessage-default-header': 'Block user',
		'blockmessage-success-header': 'Block succeeded',
		'blockmessage-form-legend': 'Notify the user of the block',
		'blockmessage-username-label': 'Username',
		'blockmessage-template-label': 'Template',
		'blockmessage-expiry-label': 'Duration',
		'blockmessage-subst-label': 'Substitute the template',
		'blockmessage-clean-label': 'Clear the talk page before putting the template',
		'blockmessage-extra-label': 'Add a custom message under the template',
		'blockmessage-extraTextareaLabel': '(be careful, the signature is no longer automatically added)',
		'blockmessage-submit-label': 'Notify',
		'blockmessage-message-summary': 'Block',
		'blockmessage-message-tags': '0xBlockMessage',
		'blockmessage-section-title': 'Block',
		'blockmessage-successnotif': 'The message has been correctly added to the talk page.',
		'blockmessage-time-label': 'Duration',
		'blockmessage-unit-label': 'Unit',
		'blockmessage-hour': 'hour',
		'blockmessage-hours': 'hours',
		'blockmessage-day': 'day',
		'blockmessage-days': 'days',
		'blockmessage-week': 'week',
		'blockmessage-weeks': 'weeks',
		'blockmessage-month': 'month',
		'blockmessage-months': 'months',
		'blockmessage-year': 'year',
		'blockmessage-years': 'years',
		'blockmessage-markup-element-not-found': 'Gadget 0xBlockMessage: markup element not found',
	},
	'fr': {
		'blockmessage-default-header' : 'Bloquer l’utilisateur',
		'blockmessage-success-header' : 'Blocage réussi',
		'blockmessage-form-legend': 'Avertir du blocage',
		'blockmessage-username-label': 'Utilisateur',
		'blockmessage-template-label': 'Modèle',
		'blockmessage-expiry-label': 'Expiration',
		'blockmessage-subst-label': 'Substituer le modèle',
		'blockmessage-clean-label': 'Effacer la PdD avant de mettre le modèle',
		'blockmessage-extra-label': 'Rajouter un message sous le modèle',
		'blockmessage-extraTextareaLabel': '(attention, la signature n\'est plus apposée automatiquement)',
		'blockmessage-submit-label': 'Avertir',
		'blockmessage-message-summary': 'Blocage',
		'blockmessage-message-tags': '0xBlockMessage',
		'blockmessage-section-title': 'Blocage',
		'blockmessage-successnotif': 'La pose du message a réussi',
		'blockmessage-time-label': 'Durée',
		'blockmessage-unit-label': 'Unité',
		'blockmessage-hour': 'heure',
		'blockmessage-hours': 'heures',
		'blockmessage-day': 'jour',
		'blockmessage-days': 'jours',
		'blockmessage-week': 'semaine',
		'blockmessage-weeks': 'semaines',
		'blockmessage-month': 'mois',
		'blockmessage-months': 'mois',
		'blockmessage-year': 'année',
		'blockmessage-years': 'années',
		'blockmessage-markup-element-not-found': 'Gadget 0xBlockMessage : élément de markup non trouvé',
	}
};

mw.messages.set( blockMessageMessages[ 'en' ] );
var lang = mw.config.get( 'wgUserLanguage' );
if ( lang !== 'en' && lang in blockMessageMessages ) {
	mw.messages.set( blockMessageMessages[ lang ] );
}

var blockMessageUnits = [
	{ en: 'hour', data: mw.msg( 'blockmessage-hour' ), label: mw.msg( 'blockmessage-hour' ) },
	{ en: 'hours', data: mw.msg( 'blockmessage-hours' ), label: mw.msg( 'blockmessage-hours' ) },
	{ en: 'day', data: mw.msg( 'blockmessage-day' ), label: mw.msg( 'blockmessage-day' ) },
	{ en: 'days', data: mw.msg( 'blockmessage-days' ), label: mw.msg( 'blockmessage-days' ) },
	{ en: 'week', data: mw.msg( 'blockmessage-week' ), label: mw.msg( 'blockmessage-week' ) },
	{ en: 'weeks', data: mw.msg( 'blockmessage-weeks' ), label: mw.msg( 'blockmessage-weeks' ) },
	{ en: 'month', data: mw.msg( 'blockmessage-month' ), label: mw.msg( 'blockmessage-month' ) },
	{ en: 'months', data: mw.msg( 'blockmessage-months' ), label: mw.msg( 'blockmessage-months' ) },
	{ en: 'year', data: mw.msg( 'blockmessage-year' ), label: mw.msg( 'blockmessage-year' ) },
	{ en: 'years', data: mw.msg( 'blockmessage-years' ), label: mw.msg( 'blockmessage-years' ) }
];



// Load the script only on the Block special page
if ( mw.config.get( 'wgCanonicalNamespace' ) === 'Special' && mw.config.get( 'wgCanonicalSpecialPageName' ) === 'Block' ) {

	mw.loader.using( [ 'mediawiki.cookie', 'mediawiki.util', 'oojs-ui', 'mediawiki.widgets.SelectWithInputWidget' ], function () {
		$( function ( $ ) {

			// On the Block page
			if ( $( '#firstHeading' ).html() === mw.msg( 'blockmessage-default-header' ) ) {
				var $expirySelect = $( '#mw-input-wpExpiry' ).find( 'select' );
				var $expiryOther = $( 'input[name="wpExpiry-other"]' );
				var $reasonSelect = $( '#mw-input-wpReason' ).find( 'select' );
				var $reasonOther = $( 'input[name="wpReason-other"]' );

				if (!$expirySelect.length || !$expiryOther.length || !$reasonSelect.length || !$reasonOther.length) {
					mw.notify( mw.msg( 'blockmessage-markup-element-not-found' ), { type: 'error', autoHide: false } );
					return;
				}

				$( 'form.mw-htmlform' ).submit( function ( event ) {
					if ( $expirySelect.val() === 'other' ) {
						mw.cookie.set( 'blockmessage-expiry', $expiryOther.val() );
					}
					else {
						mw.cookie.set( 'blockmessage-expiry', $expirySelect.val() );
					}

					if ( $reasonSelect.val() === 'other' ) {
						mw.cookie.set( 'blockmessage-reason', $reasonOther.val() );
					}
					else if ( $( 'input[name="wpReason-other"]' ).val() !== '' ) {
						mw.cookie.set( 'blockmessage-reason', $reasonSelect.val() + ' : ' + $reasonOther.val() );
					}
					else {
						mw.cookie.set( 'blockmessage-reason', $reasonSelect.val() );
					}
				} );
			}

			// When the user has successfully blocked someone.
			// wgRelevantUserName may be null for IP ranges.
			else if ( $( '#firstHeading' ).html() === mw.msg( 'blockmessage-success-header' ) &&
			          mw.cookie.get( 'blockmessage-expiry' ) !== null &&
			          mw.config.get( 'wgRelevantUserName' ) !== null ) {
				window.blockMessage = new BlockMessage( mw.config.get( 'wgRelevantUserName' ), mw.cookie.get( 'blockmessage-reason' ), mw.cookie.get( 'blockmessage-expiry' ) );
			}

		} );
	} );
}

/**
 * @class BlockMessage
 * @constructor
 * @private
 * @param {String} targetUser
 * @param {String} reason
 * @param {String} duration
 */
var BlockMessage = function (targetUser, reason, duration) {
	this.targetUser = targetUser;
	this.reason = reason;
	this.duration = duration;

	this.usernameInput;
	this.templateDropdownInput;
	this.expiryInput;
	this.substCheckboxInput;
	this.cleanCheckboxInput;
	this.extraCheckboxInput;
	this.extraTextarea;
	this.submitInput;

	this.expiryField;
	this.extraTextareaField;
	this.form;


	// Initialize the form
	this.createWidgets();
	this.addEventHandlers();
	this.initializeWidgets();

	// Add the form to the page once all is ready
	$( '#mw-content-text' ).append( this.form.$element );
};

/**
 * Create all the OOjs-ui widgets and organise them into a field layout
 */
BlockMessage.prototype.createWidgets = function () {
	this.usernameInput = new OO.ui.TextInputWidget( {
		name: 'username',
		disabled: 'disabled'
	} );
	this.templateDropdownInput = new OO.ui.DropdownInputWidget();
	this.expiryInput = new mw.widgets.SelectWithInputWidget( {
		or: false,
		dropdowninput: {
			label: mw.msg( 'blockmessage-unit-label' ),
			options: blockMessageUnits,
		},
		textinput: {
			placeholder: mw.msg( 'blockmessage-time-label' )
		}
	} );
	this.substCheckboxInput = new OO.ui.CheckboxInputWidget( {
		name: '',
		selected: true
	} );
	this.cleanCheckboxInput = new OO.ui.CheckboxInputWidget( {
		name: '',
		selected: false
	} );
	this.extraCheckboxInput = new OO.ui.CheckboxInputWidget( {
		name: '',
		selected: false
	} );
	this.extraTextarea = new OO.ui.MultilineTextInputWidget( {
		rows: 10,
		autosize: true,
	} );
	this.submitInput = new OO.ui.ButtonInputWidget( {
		type: 'submit',
		label: mw.msg( 'blockmessage-submit-label' ),
		flags: [ 'primary', 'destructive' ],
	} );

	this.expiryField = new OO.ui.FieldLayout( this.expiryInput, {
		align: 'top',
		label: mw.msg( 'blockmessage-expiry-label' )
	} );
	this.extraTextareaField = new OO.ui.FieldLayout( this.extraTextarea, {
		align: 'top',
		label: $( '<small>' ).text( mw.msg( 'blockmessage-extraTextareaLabel' ) )
	} );

	this.form = new OO.ui.FieldsetLayout( {
		id: 'demo-section-formLayout',
		label: mw.msg( 'blockmessage-form-legend' ),
		items: [
			new OO.ui.FieldLayout( this.usernameInput, {
				align: 'top',
				label: mw.msg( 'blockmessage-username-label' )
			} ),
			new OO.ui.FieldLayout( this.templateDropdownInput, {
				align: 'top',
				label: mw.msg( 'blockmessage-template-label' )
			} ),
			this.expiryField,
			new OO.ui.FieldLayout( this.substCheckboxInput, {
				align: 'inline',
				label: mw.msg( 'blockmessage-subst-label' )
			} ),
			new OO.ui.FieldLayout( this.cleanCheckboxInput, {
				align: 'inline',
				label: mw.msg( 'blockmessage-clean-label' )
			} ),
			new OO.ui.FieldLayout( this.extraCheckboxInput, {
				align: 'inline',
				label: mw.msg( 'blockmessage-extra-label' )
			} ),
			this.extraTextareaField,
			new OO.ui.FieldLayout( this.submitInput )
		]
	} );
};

/**
 * Add some handlers to the widgets to manage the post-submit stage
 * and to enhance the user experience
 */
BlockMessage.prototype.addEventHandlers = function () {
	var self = this;

	// Launch the postMessage method when the user submit the form
	this.submitInput.on( 'click', function () {
		self.submitInput.setDisabled(true);
		self.postMessage();
	} );

	// Auto (un)check the checkboxes when the user change the selected template
	this.templateDropdownInput.on( 'change', function (value) {
		value = JSON.parse(value);
		if ( value.hasOwnProperty( 'default-subst' ) ) {
			self.substCheckboxInput.setSelected( value[ 'default-subst' ] );
		}
		if ( value.hasOwnProperty( 'default-clean' ) ) {
			self.cleanCheckboxInput.setSelected( value[ 'default-clean' ] );
		}
	} );

	// Display or hide the extra textarea when the user (un)check the extra checkbox
	this.extraCheckboxInput.on( 'change', function ( checked ) {
		self.extraTextareaField.toggle( checked );
	} );
};

/**
 * Populate and adapt parameters from the widgets
 */
BlockMessage.prototype.initializeWidgets = function () {
	var templates;
	if ( this.duration === 'infinite' ) {
		// Hide the expiry field when the duration is infinite (it's irrelevant)
		this.expiryField.toggle( false );
		templates = templatesList.infinite;
	}
	else {
		templates = templatesList.finite;

		// Parse the expiry parameter and populate the expiration fields
		if ( this.duration !== null ) {
			var splitedDuration = this.duration.split( ' ' );
			if ( splitedDuration.length === 2 && !isNaN( splitedDuration[ 0 ] ) ) {
				for ( var i=0; i<blockMessageUnits.length; i++) {
					if ( splitedDuration[ 1 ] === blockMessageUnits[ i ].en ) {
						this.expiryInput.dropdowninput.setValue( blockMessageUnits[ i ].data );
						this.expiryInput.textinput.setValue( splitedDuration[ 0 ] );
						this.expiryField.toggle( false );
						break;
					}
				}
			}
		}
	}

	// Populate the template dropdown with the appropriate templates names
	this.templateDropdownInput.setOptions( templates );

	// Autoselect a template depending of the reasons or the duration
	for ( var i=0; i<templates.length; i++ ) {
		if ( 'autoselect-reason' in templates[ i ] ) {
			if ( templates[ i ][ 'autoselect-reason' ] === this.reason ) {
				this.templateDropdownInput.setValue( templates[ i ].data );
				break;
			}
		}
		if ( 'autoselect-duration' in templates[ i ] ) {
			if ( templates[ i ][ 'autoselect-duration' ] === this.duration ) {
				this.templateDropdownInput.setValue( templates[ i ].data );
				break;
			}
		}
	}

	// Fill the username field with the username of the blocked user
	this.usernameInput.setValue( this.targetUser );

	// By default, hide the extra textarea
	this.extraTextareaField.toggle( false );
};

/**
 * Use the datas set in the form to prepare and post a blocking notification
 * to the target user's talk page.
 * Called when the user click on the submit button.
 */
BlockMessage.prototype.postMessage = function () {
	var subst = '';
	if ( this.substCheckboxInput.isSelected() ) {
		subst = 'subst:';
	}
	var extra = ' ~~' + '~~';
	if ( this.extraCheckboxInput.isSelected() ) {
		extra = '\n\n' + this.extraTextarea.getValue();
	}

	// Prepare the template
	var template = JSON.parse( this.templateDropdownInput.getValue() ).template;
	template = template.replace( '$1', this.expiryInput.textinput.getValue() );
	template = template.replace( '$2', this.expiryInput.dropdowninput.getValue() );
	template = template.replace( '$3', this.reason );

	// Prepare the payload which will be send to the API
	var data = {
		action: 'edit',
		title: 'User talk:' + this.targetUser,
		text: '{{' + subst + template + '}}' + extra,
		summary: mw.msg( 'blockmessage-message-summary' ),
		tags: mw.msg( 'blockmessage-message-tags' ),
	};
	if ( ! this.cleanCheckboxInput.isSelected() ) {
		data.section = "new";
		data.sectiontitle = mw.msg( 'blockmessage-section-title' );
	}

	// Send the payload
	new mw.Api().postWithToken( 'csrf', data ).then( this.onMessagePosted.bind( this ) );
};

BlockMessage.prototype.onMessagePosted = function ( data ) {
	// Display a visual information to the admin to confirm that the talk page has been edited
	mw.notify( mw.msg( 'blockmessage-successnotif' ) );

	// Clean the cookies
	mw.cookie.set( 'blockmessage-expiry', null );
	mw.cookie.set( 'blockmessage-reason', null );

	// Redirect the admin to the target's talk page after a short delay
	var self = this;
	setTimeout( function () {
		document.location.href = mw.util.getUrl( 'User talk:' + self.targetUser + '#footer' );
	}, 750 );
};