Utilisateur:DreZhsh/LiveAbuseLog.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.
/* jshint esversion: 6 */
/**
 * @name LiveAbuseLog
 *
 * Affiche le journal des filtrages en temps réel sur Special:BlankPage/LiveAbuseLog
 * avec EventStreams <https://stream.wikimedia.org/v2/ui/#/>
 *
 * @param {Object} window.LiveAbuseLogCustomizedMessages - Un objet contenant les messages
 * à utiliser
 *
 * {{Catégorisation JS}}
 */
mw.loader.using( 'mediawiki.util', () => {

	mw.util.addPortletLink(
		'p-tb',
		'/wiki/Special:BlankPage/LiveAbuseLog',
		'LiveAbuseLog',
		't-liveabuselog'
	);

	// Initialisation
	if ( mw.config.get( 'wgCanonicalSpecialPageName' ) === 'Blankpage' && ( /LiveAbuseLog/ ).test( mw.config.get( 'wgPageName' ) ) ) {
	/*
 	* Liste des dépendances :
	*
 	* mediawiki.api : requêtes à l'API locale
 	* mediawiki.ForeignApi : requêtes à l'API de meta.wikimedia.org
 	* mediawiki.storage : enregistrement des filtres sélectionnés
 	* mediawiki.base : mw.html.element et mw.message
 	* oojs-ui-widgets : bouton "pause"
 	* oojs-ui-windows : panneau de sélection des filtres
	* oojs-ui.styles.icon-* : icônes
 	*/

		mw.loader.using( [
			'mediawiki.api', 'mediawiki.ForeignApi',
			'mediawiki.storage', 'mediawiki.base',
			'oojs-ui-widgets', 'oojs-ui-windows',
			'oojs-ui.styles.icons-media', 'oojs-ui.styles.icons-wikimedia',
			'oojs-ui.styles.icons-editing-core', 'oojs-ui.styles.icons-user',
			'oojs-ui.styles.icons-moderation', 'oojs-ui.styles.icons-alerts',
			'oojs-ui.styles.icons-interactions', 'oojs-ui.styles.icons-content'
		], () => {
			if ( window.LiveAbuseLogCustomizedMessages === undefined ) {
				mw.messages.set( {
					log: 'Journal',
					diff: 'Diff',
					reset: 'Réinitialiser',
					'title-page': 'Journal des filtrages en temps réel',
					'header-username': 'Nom d\'utilisateur',
					'header-title': 'Titre',
					'header-filter-action': 'Actions entreprises',
					'header-filter': 'Filtre déclenché',
					'header-hour': 'Heure',
					'header-delete': 'Supprimer la ligne',
					'config-pause': 'Arrêter temporairement le flux du journal des filtrages',
					'config-max-line': 'Maximum de lignes',
					'config-max-line-default': 'par défaut : 50',
					'config-filter': 'Filtres',
					'config-title': 'Paramètres',
					'config-filter-only': 'Afficher uniquement les filtres sélectionnés',
					'config-filter-except': 'Exclure les filtres sélectionnés',
					'config-filter-global': 'Filtres globaux',
					'config-filter-global-help': 'Les saisies ne peuvent contenir que le n° du filtre, sans le préfixe global-.',
					'config-filter-title': 'Paramètres de LiveAbuseLog',
					'config-settings': 'Paramètres',
					'config-settings-link': 'Afficher les liens vers les filtres',
					'config-settings-style': 'Appliquer des feuilles de style en cascade personelles à l\'interface',
					'panel-action-save': 'Sauvegarder',
					'panel-action-close': 'Fermer la fenêtre',
					'panel-action-unselect': 'Désélectionner',
					'abusefilter-action-log': 'Journaliser'
				} );
			} else {
				mw.messages.set( window.LiveAbuseLogCustomizedMessages );
			}
			new mw.Api().loadMessagesIfMissing( [
				'abusefilter-action-block',
				'abusefilter-action-blockautopromote',
				'abusefilter-action-degroup',
				'abusefilter-action-disallow',
				'abusefilter-action-rangeblock',
				'abusefilter-action-tag',
				'abusefilter-action-throttle',
				'abusefilter-action-warn'
			] ).then( () => {
				let recentChangeStream, LiveAbuseLogLimit, LiveAbuseLogNumberLine,
					LiveAbuseLogOptionsWidget, dialogLiveAbuseLog;
				const storageName = `${mw.config.get( 'wgDBname' )}-LocalFilters`,
					storageGlobal = 'wikimedia-GlobalFilters';
				LiveAbuseLogLimit = 50;
				LiveAbuseLogNumberLine = 0;
				// Stockage des filtres
				new mw.Api().get( {
					action: 'query',
					format: 'json',
					list: 'abusefilters',
					formatversion: 2,
					abflimit: '500',
					abfprop: 'id|description',
					abfshow: 'enabled'
				} ).then( ( data ) => {
					const arrayFilter = data.query.abusefilters;
					if ( data.continue !== undefined ) {
						abusefiltersContinue( data.continue.abfstartid, arrayFilter );
					} else {
						mw.storage.session.set( storageName, JSON.stringify( arrayFilter ) );
					}
				}
				);
				new mw.ForeignApi(
					'https://meta.wikimedia.org/w/api.php'
				).get( {
					action: 'query',
					format: 'json',
					list: 'abusefilters',
					formatversion: 2,
					abflimit: '500',
					abfprop: 'id|description',
					abfshow: 'enabled'
				} ).then( ( data ) => {
					const arrayFilter = data.query.abusefilters;
					if ( data.continue !== undefined ) {
						abusefiltersGlobalContinue( data.continue.abfstartid, arrayFilter );
					} else {
						mw.storage.session.set( storageGlobal, JSON.stringify( arrayFilter ) );
					}
				} );
				function abusefiltersContinue( continueQuery, data ) {
					new mw.Api().get( {
						action: 'query',
						format: 'json',
						list: 'abusefilters',
						formatversion: 2,
						abfstartid: continueQuery,
						abflimit: '500',
						abfprop: 'id|description',
						abfshow: 'enabled'
					} ).then( ( query ) => {
						const array = data.concat( query.query.abusefilters );
						if ( query.continue !== undefined ) {
							abusefiltersContinue( query.continue.abfstartid, array );
						} else {
							mw.storage.session.set( storageName, JSON.stringify( array ) );
						}
					} );
				}
				function abusefiltersGlobalContinue( continueQuery, data ) {
					new mw.ForeignApi(
						'https://meta.wikimedia.org/w/api.php'
					).get( {
						action: 'query',
						format: 'json',
						list: 'abusefilters',
						formatversion: 2,
						abfstartid: continueQuery,
						abflimit: '500',
						abfprop: 'id|description',
						abfshow: 'enabled'
					} ).then( ( query ) => {
						const array = data.concat( query.query.abusefilters );
						if ( query.continue !== undefined ) {
							abusefiltersGlobalContinue( query.continue.abfstartid, array );
						} else {
							mw.storage.session.set( storageGlobal, JSON.stringify( array ) );
						}
					} );
				}
				// Initialisation du tableau
				const userTable = mw.html.element( 'th', {
						style: 'width: 23%',
						scope: 'col'
					}, mw.msg( 'header-username' ) ),
					titleTable = mw.html.element( 'th', {
						style: 'width: 22%',
						scope: 'col'
					}, mw.msg( 'header-title' ) ),
					logTable = mw.html.element( 'th', {
						style: 'width: 10%',
						scope: 'col'
					}, mw.msg( 'log' ) ),
					filterActionTable = mw.html.element( 'th', {
						style: 'width: 15%',
						scope: 'col'
					}, mw.msg( 'header-filter-action' ) ),
					filterTable = mw.html.element( 'th', {
						style: 'width: 25%',
						scope: 'col'
					}, mw.msg( 'header-filter' ) ),
					hourTable = mw.html.element( 'th', {
						style: 'width: 5%',
						scope: 'col'
					}, mw.msg( 'header-hour' ) ),
					$trashIcon = new OO.ui.IconWidget( {
						icon: 'trash',
						title: mw.msg( 'header-delete' )
					} ).$element,
					$deleteTable = $( '<th>' )
						.attr( {
							style: 'width: 3%'
						} )
						.append( $trashIcon ),
					concatHtml = userTable + filterTable + titleTable +
					filterActionTable + logTable + hourTable,
					$tableLine = $( '<tr>' )
						.attr( {
							id: 'liveAbuseLogHeader',
							class: 'abuseLogHeader'
						} )
						.append( $.parseHTML( concatHtml ) )
						.append( $deleteTable );
				// Initialisation options
				const toggleSwitch = new OO.ui.ToggleSwitchWidget( {
						title: mw.msg( 'config-pause' ),
						id: 'liveAbuseLogPauseWidget'
					} ),
					iconWidget = new OO.ui.IconWidget( {
						icon: 'pause',
						title: mw.msg( 'config-pause' )
					} ),
					textInput = new OO.ui.TextInputWidget( {
						placeholder: mw.msg( 'config-max-line' ),
						type: 'number',
						label: mw.msg( 'config-max-line-default' ),
						validate: /^[0-9]*$/
					} ),
					button = new OO.ui.ButtonWidget( {
						label: mw.msg( 'reset' ),
						flags: [
							'destructive'
						]
					} ),
					settingsButton = new OO.ui.ButtonWidget( {
						label: mw.msg( 'config-title' ),
						flags: [
							'progressive'
						],
						icon: 'settings',
						title: mw.msg( 'config-filter-title' )
					} ),
					fieldset = new OO.ui.FieldLayout(
						new OO.ui.Widget( {
							content: [ new OO.ui.HorizontalLayout( {
								items: [
									toggleSwitch,
									iconWidget,
									button,
									textInput,
									settingsButton
								]
							} ) ]
						} )
					);
				const layout = new OO.ui.HorizontalLayout( {
					items: [
						new OO.ui.LabelWidget( {
							label: new OO.ui.HtmlSnippet(
								`Powered by <a href="https://www.mediawiki.org">MediaWiki</a> and 
							<a href="https://stream.wikimedia.org/v2/ui/#/">Wikimedia Event Streams</a>`
							)
						} ),
						new OO.ui.IconWidget( { icon: 'logoWikimedia' } )
					]
				} );
				// URL de requête
				const url = 'https://stream.wikimedia.org/v2/stream/recentchange';
				recentChangeStream = new EventSource( url );
				// Nom du serveur
				const serverName = mw.config.get( 'wgServer' ).replace( '//', '' );

				/**
				 * defineLogActionIcon
				 *
				 * Définit les icônes à afficher dans la nouvelle
				 * ligne du tableau en convertissant la chaîne passée
				 * en argument en un élément HTML.
				 *
				 * @param {string} type - L'action effectuée par le filtre (disallow, tag, warn)
				 * @return {HTMLImageElement} Les icônes à afficher
				 */
				function defineLogActionIcon( type ) {
					const $iconArea = $( '<span>' );
					$iconArea.append( new OO.ui.IconWidget( {
						icon: 'bookmark',
						title: mw.msg( 'abusefilter-action-log' )
					} ).$element );
					if ( type === 'disallow' ) {
						$iconArea.append( new OO.ui.IconWidget( {
							icon: 'editLock',
							title: mw.msg( 'abusefilter-action-disallow' )
						} ).$element );
					} else if ( type === 'warn' ) {
						$iconArea.append( new OO.ui.IconWidget( {
							icon: 'alert',
							title: mw.msg( 'abusefilter-action-warn' )
						} ).$element );
					} else if ( type === 'tag' ) {
						$iconArea.append( new OO.ui.IconWidget( {
							icon: 'tag',
							title: mw.msg( 'abusefilter-action-tag' )
						} ).$element );
					} else if ( type === 'block' ) {
						$iconArea.append( new OO.ui.IconWidget( {
							icon: 'block',
							title: mw.msg( 'abusefilter-action-block' )
						} ).$element );
					} else if ( type === 'throttle' ) {
						$iconArea.append( new OO.ui.IconWidget( {
							icon: 'fullScreen',
							title: mw.msg( 'abusefilter-action-throttle' )
						} ).$element );
					} else if ( type === 'degroup' ) {
						$iconArea.append( new OO.ui.IconWidget( {
							icon: 'userGroup',
							title: mw.msg( 'abusefilter-action-degroup' )
						} ).$element );
					} else if ( type === 'rangeblock' ) {
						$iconArea.append( new OO.ui.IconWidget( {
							icon: 'block',
							title: mw.msg( 'abusefilter-action-rangeblock' )
						} ).$element );
						$iconArea.append( new OO.ui.IconWidget( {
							icon: 'userAnonymous',
							title: mw.msg( 'abusefilter-action-rangeblock' )
						} ).$element );
					} else if ( type === 'blockautopromote' ) {
						$iconArea.append( new OO.ui.IconWidget( {
							icon: 'hand',
							title: mw.msg( 'abusefilter-action-blockautopromote' )
						} ).$element );
					}
					return $iconArea;
				}

				/**
				 * linkInTable
				 *
				 * Crée un élément HTML <a> à partir des
				 * données passées en argument
				 *
				 * @param {string} type - Le type de lien (Utilisateur, journal, Page)
				 * @param {string} value - La cible du lien (Nom d'utilisateur, article, entrée de journal)
				 * @param {Array} arrayIds - Un tableau contenant l'ID du journal et l'ID de la révision
				 * @param {string} label - Le label du filtre
				 * @return {HTMLLinkElement} Le lien à afficher
				 */
				function linkInTable( type, value, arrayIds, label ) {
					if ( type === 'user' ) {
						return mw.html.element( 'a', { href: `/wiki/Special:Contributions/${value}`, target: '_blank' }, value );
					} else if ( type === 'log' ) {
						return mw.html.element( 'a', { href: `/wiki/Special:Abuselog/${value}`, target: '_blank' }, mw.msg( 'log' ) );
					} else if ( type === 'page' ) {
						return mw.html.element( 'a', { href: `/wiki/${value}`, target: '_blank' }, value );
					} else if ( type === 'diff' ) {
						const firstLink = mw.html.element(
								'a',
								{
									href: `/wiki/Special:Abuselog/${arrayIds[ 0 ]}`,
									target: '_blank'
								},
								mw.msg( 'log' ) ),
							lastLink = mw.html.element(
								'a',
								{
									href: `/wiki/Special:Diff/${arrayIds[ 1 ]}`,
									target: '_blank'
								},
								mw.msg( 'diff' ) );
						return `${firstLink} (${lastLink})`;
					} else if ( type === 'filter' ) {
						if ( JSON.parse( mw.user.options.get( 'userjs-LiveAbuseLog-Links' ) ) === true &&
							( /global-/ ).test( value ) === false ) {
							return new mw.html.Raw( mw.html.element( 'a', {
								href: `/wiki/Special:Abusefilter/${value}`
							}, `${value}${label}` ) );
						} else {
							return `${value}${label}`;
						}
					}
				}
				/**
				 * convertJsonToHtml
				 *
				 * Convertit des données JSON en HTML
				 * à afficher sur la page Web
				 *
				 * @param {string} user - Le nom d'utilisateur qui a déclenché le filtre
				 * @param {number} logId - Le numéro de journal du filtrage
				 * @param {string} logAction - L'action effectuée par le filtre
				 * @param {string} title - Le titre de la page où le filtre a été déclenché
				 * @param {string} filter - Le numéro du filtre déclenché
				 * @param {number} timestamp - L'hortodatage à utiliser pour obtenir le diff
				 */
				function convertJsonToHtml( user, logId, logAction, title, filter, timestamp ) {
					let filterLabel, logLink;

					/**
					 * insertHtml
					 *
					 * Insère le code HTML sur la page avec les
					 * informations obtenues précédemment
					 */
					function insertHtml() {
						const thisNumber = ++LiveAbuseLogNumberLine;
						const deleteLineButton = mw.html.element( 'a', {
							href: '#',
							id: `abuselogDelete-${thisNumber}`
						}, '—' );
						const hour = new Date( timestamp ).toLocaleTimeString(),
							displayHour = hour.slice( '0', '5' );
						const userCel = mw.html.element( 'td', {
								style: 'width: 500px',
								class: 'liveAbuseLogCel'
							}, new mw.html.Raw( linkInTable( 'user', user ) ) ),
							titeCel = mw.html.element( 'td', {
								style: 'width: 22%',
								class: 'liveAbuseLogCel'
							}, new mw.html.Raw( linkInTable( 'page', title ) ) ),
							logCel = mw.html.element( 'td', {
								style: 'width: 10%',
								class: 'liveAbuseLogCel'
							}, new mw.html.Raw( logLink ) ),
							$filterActionCel = $( '<td>' )
								.attr( {
									style: 'width: 15%',
									class: 'liveAbuseLogCel'
								} )
								.append( defineLogActionIcon( logAction ) ),
							filterCel = mw.html.element( 'td', {
								style: 'width: 25%',
								class: 'liveAbuseLogCel'
							}, linkInTable( 'filter', filter, null, filterLabel ) ),
							hourCel = mw.html.element( 'td', {
								style: 'width: 5%',
								class: 'liveAbuseLogCel'
							}, displayHour ),
							deleteLine = mw.html.element( 'td', {
								style: 'width: 3%',
								class: 'liveAbuseLogCel'
							}, new mw.html.Raw( `(${deleteLineButton})` ) ),
							concatHtmlNew = userCel + filterCel + titeCel,
							concatHtmlNew2 = logCel + hourCel + deleteLine,
							$tableLineNew = $( '<tr>' )
								.attr( {
									class: 'liveAbuseLogTableLine',
									id: `liveAbuseLogDelete-${thisNumber}`
								} )
								.append( $.parseHTML( concatHtmlNew ) )
								.append( $filterActionCel )
								.append( $.parseHTML( concatHtmlNew2 ) );

						// Insertion du HTML
						$( document.getElementById( 'liveAbuseLogHeader' ) ).after( $tableLineNew );

						// Suppression de lignes après un certain seuil
						while ( $( document.getElementById( 'liveAbuseLogTable' ) ).children().length > LiveAbuseLogLimit + 1 ) {
							$( document.getElementById( 'liveAbuseLogTable' ) ).children().last().remove();
						}

						$( `#abuselogDelete-${thisNumber}` ).on( 'click', ( e ) => {
							e.preventDefault();
							$( `#liveAbuseLogDelete-${thisNumber}` ).remove();
						} );
					}
					/**
					 * displayDiffIfExist
					 *
					 * Affiche un lien "(Diff)" à côté du lien "Journal"
					 * si possible
					 */
					function displayDiffIfExist() {
						new mw.Api().get( {
							action: 'query',
							format: 'json',
							list: 'abuselog',
							formatversion: 2,
							afllogid: logId,
							aflprop: 'revid'
						} ).then( ( data ) => {
							const diff = data.query.abuselog;
							if ( diff.length > 0 ) {
								const revid = diff[ 0 ].revid;

								logLink = linkInTable( 'diff', undefined, [ logId, revid ] );
							} else {
								logLink = linkInTable( 'log', logId );
							}
						} ).then( () => {
							insertHtml();
						} );
					}

					// Définition de la description du filtre
					if ( ( /global-/ ).test( filter ) === true ) {
						const filterIdNumber = filter.replace( 'global-', '' ), // Suppression du préfixe global-
							array = JSON.parse( mw.storage.session.get( storageGlobal ) );
						for ( const filterhit of array ) {
							if ( String( filterhit.id ) === filterIdNumber ) {
								filterLabel = filterhit.description;
								if ( logAction !== 'warn' && logAction !== 'disallow' ) {
									displayDiffIfExist();
								} else {
									logLink = linkInTable( 'log', logId );
									insertHtml();
								}
							}
						}
					} else {
						const array = JSON.parse( mw.storage.session.get( storageName ) );
						for ( const filterhit of array ) {
							if ( String( filterhit.id ) === filter ) {
								filterLabel = filterhit.description;
								if ( logAction !== 'warn' && logAction !== 'disallow' ) {
									displayDiffIfExist();
								} else {
									logLink = linkInTable( 'log', logId );
									insertHtml();
								}
							}
						}
					}
				}

				/**
				 * createSettingsDialog
				 *
				 * Création du panneau de sélection des filtres
				 */
				function createSettingsDialog() {
					new mw.Api().get( {
						action: 'query',
						format: 'json',
						list: 'abusefilters',
						abfshow: 'enabled',
						formatversion: 2,
						abflimit: '500',
						abfprop: 'id|description'
					} ).then( ( data ) => {
						LiveAbuseLogOptionsWidget = [];
						const arrayFilters = data.query.abusefilters;
						for ( const filterdesc of arrayFilters ) {
							const filterId = filterdesc.id;
							const filterDescription = filterdesc.description;
							const LiveAbuseLogOptions = new OO.ui.CheckboxMultioptionWidget( {
								data: filterId,
								selected: true,
								label: `${filterId}${filterDescription}`
							} );
							LiveAbuseLogOptionsWidget.push( LiveAbuseLogOptions );
						}
					} ).then( () => {
						const windowManager = new OO.ui.WindowManager(),
							optionsWidget = new OO.ui.CheckboxMultiselectWidget( {
								items: LiveAbuseLogOptionsWidget
							} ),
							input1 = new OO.ui.TagMultiselectWidget( {
								allowArbitrary: true
							} ),
							input2 = new OO.ui.TagMultiselectWidget( {
								allowArbitrary: true
							} ),
							toggleLink = new OO.ui.ToggleSwitchWidget(),
							toggleStyle = new OO.ui.ToggleSwitchWidget(),
							LiveAbuseLogSelectItemByData = optionsWidget.findSelectedItemsData();

						/**
						 * checkTagMultiselect
						 *
						 * @param {OO.ui.TagMultiselectWidget} input - La saisie à vérifier
						 */
						function checkTagMultiselect( input ) {
							const array = input.getValue();
							let inputValidity;
							for ( const i in array ) {
								if ( ( /^[0-9]*$/ ).test( array[ i ] ) !== true ) {
									inputValidity = false;
								}
							}
							if ( inputValidity === false ) {
								input.toggleValid( false );
							} else {
								input.toggleValid( true );
							}
						}
						/**
						 * LongProcessDialog
						 *
						 * @class
						 * @extends OO.ui.ProcessDialog
						 * @param {Object} [config] - Un objet contenant les paramètres de la boîte de dialogue
						 */
						function LongProcessDialog( config ) {
							LongProcessDialog.super.call( this, config );
						}
						OO.inheritClass( LongProcessDialog, OO.ui.ProcessDialog );
						LongProcessDialog.static.name = 'longProcess';
						LongProcessDialog.static.title = mw.msg( 'config-title' );
						LongProcessDialog.static.actions = [
							{ action: 'save', label: mw.msg( 'panel-action-save' ), icon: 'check', flags: [ 'primary', 'progressive' ] },
							{ action: 'close', label: mw.msg( 'panel-action-close' ), flags: [ 'safe', 'close' ] },
							{ action: 'other', label: mw.msg( 'reset' ), flags: [ 'primary', 'destructive' ] },
							{ action: 'other2', label: mw.msg( 'panel-action-unselect' ), icon: 'cancel', flags: [ 'destructive' ] }
						];
						LongProcessDialog.prototype.initialize = function () {
							LongProcessDialog.super.prototype.initialize.apply( this, arguments );

							this.booklet = new OO.ui.BookletLayout( {
								outlined: true
							} );

							/**
							 * PageOneLayout
							 *
							 * Génère la première page du BookletLayout,
							 * contenant la sélection des filtres
							 *
							 * @class
							 * @extends OO.ui.PageLayout
							 * @param {string} name - Le nom du Layout
							 * @param {Object} [config] - Un objet contenant les paramètres du Layout
							 */
							function PageOneLayout( name, config ) {
								PageOneLayout.super.call( this, name, config );
								this.$element.append( optionsWidget.$element );
							}
							OO.inheritClass( PageOneLayout, OO.ui.PageLayout );
							PageOneLayout.prototype.setupOutlineItem = function () {
								this.outlineItem.setLabel( mw.msg( 'config-filter' ) );
							};

							/**
							 * PageTwoLayout
							 *
							 * Génère la deuxième page du BookletLayout,
							 * contenant des saisies liées aux filtres globaux
							 *
							 * @class
							 * @extends OO.ui.PageLayout
							 * @param {string} name - Le nom du Layout
							 * @param {Object} [config] - Un objet contenant les paramètres du Layout
							 */
							function PageTwoLayout( name, config ) {
								PageTwoLayout.super.call( this, name, config );
								const fieldsetDialog = new OO.ui.FieldsetLayout( {
									helpInline: true,
									help: mw.msg( 'config-filter-global-help' ),
									label: mw.msg( 'config-filter-global' )
								} );

								fieldsetDialog.addItems( [
									new OO.ui.FieldLayout( input1, {
										label: mw.msg( 'config-filter-except' ),
										align: 'top'
									} ),
									new OO.ui.FieldLayout( input2, {
										label: mw.msg( 'config-filter-only' ),
										align: 'top'
									} )
								] );

								input1.on( 'change', () => {
									checkTagMultiselect( input1 );
								} );
								input2.on( 'change', () => {
									checkTagMultiselect( input2 );
								} );

								this.$element.append( fieldsetDialog.$element );
							}
							OO.inheritClass( PageTwoLayout, OO.ui.PageLayout );
							PageTwoLayout.prototype.setupOutlineItem = function () {
								this.outlineItem.setLabel( mw.msg( 'config-filter-global' ) );
							};
							/**
							 * PageThreeLayout
							 *
							 * Génère la troisième page du BookletLayout,
							 * contenant les paramètres généraux du script
							 *
							 * @class
							 * @extends OO.ui.PageLayout
							 * @param {string} name - Le nom du Layout
							 * @param {Object} [config] - Un objet contenant les paramètres du Layout
							 */
							function PageThreeLayout( name, config ) {
								PageOneLayout.super.call( this, name, config );
								const fieldsetDialog = new OO.ui.FieldsetLayout( {
									label: mw.msg( 'config-settings' )
								} );
								fieldsetDialog.addItems( [
									new OO.ui.FieldLayout( toggleLink, {
										label: mw.msg( 'config-settings-link' ),
										align: 'top'
									} ),
									new OO.ui.FieldLayout( toggleStyle, {
										label: mw.msg( 'config-settings-style' ),
										align: 'top'
									} )
								] );
								this.$element.append( fieldsetDialog.$element );
							}
							OO.inheritClass( PageThreeLayout, OO.ui.PageLayout );
							PageThreeLayout.prototype.setupOutlineItem = function () {
								this.outlineItem.setLabel( mw.msg( 'config-settings' ) );
							};

							this.pages = [
								new PageOneLayout( 'one' ),
								new PageTwoLayout( 'two' ),
								new PageThreeLayout( 'three' )
							];

							this.booklet.addPages( this.pages );
							this.booklet.connect( this );
							this.booklet.setPage( 'one' );
							this.$body.append( this.booklet.$element );
						};

						LongProcessDialog.prototype.getActionProcess = function ( action ) {
							const dialogAction = this;
							if ( action === 'close' ) {
								dialogAction.close( { action: action } );
								windowManager.destroy();
							} else if ( action === 'other' ) {
								switch ( this.booklet.getCurrentPage().name ) {
									case 'one':
										// Checkbox
										mw.user.options.set( 'userjs-LiveAbuseLogFilters', null );
										new mw.Api().saveOption( 'userjs-LiveAbuseLogFilters', null );
										optionsWidget.selectItemsByData(
											LiveAbuseLogSelectItemByData
										);
										break;
									case 'two':
										// input1
										mw.user.options.set( 'userjs-LiveAbuseLog-Exclude', null );
										new mw.Api().saveOption( 'userjs-LiveAbuseLog-Exclude', null );
										input1.setValue( [] );
										// input2
										mw.user.options.set( 'userjs-LiveAbuseLog-Only', null );
										new mw.Api().saveOption( 'userjs-LiveAbuseLog-Only', null );
										input2.setValue( [] );
										break;
									case 'three':
										// Settings
										mw.user.options.set( 'userjs-LiveAbuseLog-Links', false );
										new mw.Api().saveOption( 'userjs-LiveAbuseLog-Links', false );
										mw.user.options.set( 'userjs-LiveAbuseLog-Styles', false );
										new mw.Api().saveOption( 'userjs-LiveAbuseLog-Styles', false );
										toggleLink.setValue( false );
										toggleStyle.setValue( false );
										break;
								}

							} else if ( action === 'save' ) {
								mw.user.options.set( 'userjs-LiveAbuseLogFilters', optionsWidget.findSelectedItemsData().join( ',' ) );
								new mw.Api().saveOption( 'userjs-LiveAbuseLogFilters', optionsWidget.findSelectedItemsData() );
								const selectedFilters = mw.user.options.get( 'userjs-LiveAbuseLogFilters' ),
									array = JSON.parse( '[' + selectedFilters + ']' );
								for ( const item of optionsWidget.items ) {
									if ( array.indexOf( item.data ) === -1 ) {
										item.selected = false;
									}
								}
								checkTagMultiselect( input1 );
								checkTagMultiselect( input2 );
								if ( input1.isValid() === true ) {
									// Quand l'utilisateur reste sur la page :
									mw.user.options.set( 'userjs-LiveAbuseLog-Exclude', input1.getValue().join( ',' ) );
									new mw.Api().saveOption( 'userjs-LiveAbuseLog-Exclude', input1.getValue() );
								}
								if ( input2.isValid() === true ) {
									// Quand l'utilisateur reste sur la page :
									mw.user.options.set( 'userjs-LiveAbuseLog-Only', input2.getValue().join( ',' ) );
									new mw.Api().saveOption( 'userjs-LiveAbuseLog-Only', input2.getValue() );
								}
								mw.user.options.set( 'userjs-LiveAbuseLog-Links', toggleLink.getValue() );
								new mw.Api().saveOption( 'userjs-LiveAbuseLog-Links', toggleLink.getValue() );
								mw.user.options.set( 'userjs-LiveAbuseLog-Styles', toggleStyle.getValue() );
								new mw.Api().saveOption( 'userjs-LiveAbuseLog-Styles', toggleStyle.getValue() );
							} else if ( action === 'other2' ) {
								mw.user.options.set( 'userjs-LiveAbuseLogFilters', '' );
								new mw.Api().saveOption( 'userjs-LiveAbuseLogFilters', '' );
								optionsWidget.selectItemsByData( [] );
							}
							return LongProcessDialog.super.prototype
								.getActionProcess.call( this, action );
						};

						LongProcessDialog.prototype.getSetupProcess = function ( data ) {
							if (
								mw.user.options.get( 'userjs-LiveAbuseLog-Exclude' ) !== null &&
								mw.user.options.get( 'userjs-LiveAbuseLog-Exclude' ) !== ''
							) {
								input1.setValue( mw.user.options.get( 'userjs-LiveAbuseLog-Exclude' ).split( ',' ) );
							}
							if (
								mw.user.options.get( 'userjs-LiveAbuseLog-Only' ) !== null &&
								mw.user.options.get( 'userjs-LiveAbuseLog-Only' ) !== ''
							) {
								input2.setValue( mw.user.options.get( 'userjs-LiveAbuseLog-Only' ).split( ',' ) );
							}
							if ( mw.user.options.get( 'userjs-LiveAbuseLogFilters' ) !== null ) {
								const selectedFilters = mw.user.options.get( 'userjs-LiveAbuseLogFilters' ),
									array = JSON.parse( '[' + selectedFilters + ']' );
								optionsWidget.selectItemsByData( array );
							}
							if ( JSON.parse( mw.user.options.get( 'userjs-LiveAbuseLog-Links' ) ) === true ) {
								toggleLink.setValue( true );
							}
							if ( JSON.parse( mw.user.options.get( 'userjs-LiveAbuseLog-Styles' ) ) === true ) {
								toggleStyle.setValue( true );
							}
							return LongProcessDialog.super.prototype
								.getSetupProcess.call( this, data );
						};

						LongProcessDialog.prototype.getBodyHeight = function () {
							return 600;
						};

						$( document.body ).append( windowManager.$element );

						dialogLiveAbuseLog = new LongProcessDialog( {
							size: 'large'
						} );
						windowManager.addWindows( [ dialogLiveAbuseLog ] );
						windowManager.openWindow( dialogLiveAbuseLog );
					} );
				}
				/**
				 * core
				 *
				 * Noyau du script :
				 * vérifie si l'évènement est éligible
				 * (abuselog, sur le site actuel)
				 *
				 * @param {JSON} message - L'évènement envoyé a analyser
				 */
				function core( message ) {
					const data = JSON.parse( message.data );

					if (
						// Vérification du site
						data.server_name === serverName &&
						// Vérification du type
						data.type === 'log' &&
						data.log_type === 'abusefilter' &&
						data.log_action === 'hit'
					) {
						const selectedFilters = mw.user.options.get( 'userjs-LiveAbuseLogFilters' ),
							array = String( selectedFilters ).split( ',' ),
							arrayExclude = String( mw.user.options.get( 'userjs-LiveAbuseLog-Exclude' ) ).split( ',' ),
							arrayOnly = String( mw.user.options.get( 'userjs-LiveAbuseLog-Only' ) ).split( ',' );
						if (
							( /global-/ ).test( data.log_params.filter ) === false &&
							( mw.user.options.get( 'userjs-LiveAbuseLogFilters' ) === null ||
							array.indexOf( data.log_params.filter ) !== -1 )

						) {
							convertJsonToHtml(
								data.user,
								data.log_params.log,
								data.log_params.actions,
								data.title,
								data.log_params.filter,
								data.meta.dt
							);
						} else if (
							/*
							Si pas de configuration pour les filtres globaux,
							Afficher tous les déclenchements
							*/
							( String( mw.user.options.get( 'userjs-LiveAbuseLog-Exclude' ) ) === 'null' ||
							mw.user.options.get( 'userjs-LiveAbuseLog-Exclude' ) === '' ) &&
							( String( mw.user.options.get( 'userjs-LiveAbuseLog-Only' ) ) === 'null' ||
							mw.user.options.get( 'userjs-LiveAbuseLog-Only' ) === '' ) &&
							( /global-/ ).test( data.log_params.filter )
						) {
							convertJsonToHtml(
								data.user,
								data.log_params.log,
								data.log_params.actions,
								data.title,
								data.log_params.filter,
								data.meta.dt
							);
						} else if (
							String( mw.user.options.get( 'userjs-LiveAbuseLog-Only' ) ) !== 'null' &&
							mw.user.options.get( 'userjs-LiveAbuseLog-Only' ) !== '' &&
								arrayOnly
									.indexOf(
										String( data.log_params.filter ).replace( /global-/, '' )
									) !== -1
						) {
							convertJsonToHtml(
								data.user,
								data.log_params.log,
								data.log_params.actions,
								data.title,
								data.log_params.filter,
								data.meta.dt
							);
						} else if ( // Si en dehors de arrayOnly
							String( mw.user.options.get( 'userjs-LiveAbuseLog-Only' ) ) !== 'null' &&
							mw.user.options.get( 'userjs-LiveAbuseLog-Only' ) !== '' &&
								arrayOnly
									.indexOf(
										String( data.log_params.filter ).replace( /global-/, '' )
									) === -1
						) {
							return;
						} else if (
							String( mw.user.options.get( 'userjs-LiveAbuseLog-Exclude' ) ) !== 'null' &&
							mw.user.options.get( 'userjs-LiveAbuseLog-Exclude' ) !== '' &&
								arrayExclude
									.indexOf(
										String( data.log_params.filter ).replace( /global-/, '' )
									) === -1
						) {
							convertJsonToHtml(
								data.user,
								data.log_params.log,
								data.log_params.actions,
								data.title,
								data.log_params.filter,
								data.meta.dt
							);
						} else if ( // Si dans arrayExclude
							String( mw.user.options.get( 'userjs-LiveAbuseLog-Exclude' ) ) !== 'null' &&
							mw.user.options.get( 'userjs-LiveAbuseLog-Exclude' ) !== '' &&
								arrayExclude
									.indexOf(
										String( data.log_params.filter ).replace( /global-/, '' )
									) !== -1
						) {
							return;
						}
					}
				}

				// Création CSS
				if ( JSON.parse( mw.user.options.get( 'userjs-LiveAbuseLog-Styles' ) ) !== true ) {
					mw.loader.addStyleTag( `
.abuseLogHeader {
	background-color: #00af89;
}
.liveAbuseLogCel {
	background-color: #fef6e7;
}
table, th, td {
    padding: 10px;
    border: 1px solid #a2a9b1;
    border-collapse: collapse;
}
#liveAbuseLogTable {
	text-align: center;
}
				` );
				}
				// Nettoyage de la page
				$( document.getElementById( 'mw-content-text' ) ).empty();
				$( document.getElementById( 'firstHeading' ) ).text( mw.msg( 'title-page' ) );
				$( document.getElementsByTagName( 'title' ) ).text( 'LiveAbuseLog' );
				$( document.getElementById( 'footer-icons' ) ).remove();
				$( document.getElementById( 'footer' ) ).after( layout.$element );
				$( layout.$element ).css( 'text-align', 'right' );
				// Insertion du tableau
				$( document.getElementById( 'mw-content-text' ) ).append( mw.html.element( 'table', { id: 'liveAbuseLogTable' }, '' ) );
				$( document.getElementById( 'liveAbuseLogTable' ) ).append( $tableLine );
				// Insertion options
				$( document.getElementById( 'liveAbuseLogTable' ) ).before( fieldset.$element );
				// Bouton réinitialisation
				button.on( 'click', () => {
					$( document.getElementsByClassName( 'liveAbuseLogTableLine' ) ).remove();
					LiveAbuseLogNumberLine = 0;
					textInput.setValue( '' );
					LiveAbuseLogLimit = 50;
				} );
				// Bouton options
				settingsButton.on( 'click', () => {
					createSettingsDialog();
				} );
				// Changement de valeur lors de l'actuaisation de la saisie
				textInput.on( 'change', () => {
					LiveAbuseLogLimit = parseInt( textInput.getValue() );
				} );
				// Bouton pause
				toggleSwitch.on( 'change', () => {
					if ( toggleSwitch.getValue() === true ) {
						recentChangeStream.close();
						mw.log( `Connection to ${url} broken` );
					} else {
						recentChangeStream = new EventSource( url );
						// Gestion des RC
						recentChangeStream.onopen = () => {
							mw.log( `Connected to ${url}` );
						};
						recentChangeStream.onmessage = ( message ) => {
							core( message );
						};
					}
				} );
				// Gestion des RC
				recentChangeStream.onopen = () => {
					mw.log( `Connected to ${url}` );
				};
				recentChangeStream.onmessage = ( message ) => {
					core( message );
				};
			} );
		} );
	}
}
);