Utilisateur:Escargot bleu/Gadget-BandeauxPortails.js
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) ;
Firefox (sur GNU/Linux) / Chrome / Internet Explorer / Opera : maintenez la touche Ctrl en cliquant sur le bouton Actualiser ou pressez Ctrl-F5.//
//<syntaxhighlight lang=javascript>
// Documentation : [[Projet:Scripts et gadgets/Notices/BandeauxPortails]]
// Licence : Domaine public
// <syntaxhighlight lang=javascript>
// ==================================================================================================================== DEBUT DU CODE
// ====================================================================================================================
//<pre><nowiki>
/* eslint-env browser */
/* jshint esversion: 8 */
'use strict';
/////////////////////////////////////////////////////////////////////////////////// Variables personnalisables
const defaultOptions = {
singleEdits: true, // Affichage des anciens boutons du gadget
autoLaunch: false, // Lancement automatique du gadget
autoEdit: true, // Publication automatique
minorEdit: true, // Modification mineure
watchthis: '-1', // Ajout à la liste de suivi ( -1 = défaut préférences, 0 = jamais, 1 = toujours)
showRedirect: false, // Affichage des redirections de bandeaux
skipConfirm: false, // Confirmation de la suppression du bandeau
tailleListe: 10, // Nombre d'éléments affichés pour les anciens select
listeBas: false, // Positionnement des anciens select
};
const commonjsOptions = {};
if ( typeof window.BandeauxPortails_SingleEdits !== 'undefined' ) commonjsOptions.singleEdits = window.BandeauxPortails_SingleEdits;
if ( typeof window.BandeauxPortails_AutoLaunch !== 'undefined' ) commonjsOptions.autoLaunch = window.BandeauxPortails_AutoLaunch;
if ( typeof window.BandeauxPortails_AutoEdit !== 'undefined' ) commonjsOptions.autoEdit = window.BandeauxPortails_AutoEdit;
if ( typeof window.BandeauxPortails_MinorEdit !== 'undefined' ) commonjsOptions.minorEdit = window.BandeauxPortails_MinorEdit;
if ( typeof window.BandeauxPortails_Watchthis !== 'undefined' ) commonjsOptions.watchthis = window.BandeauxPortails_Watchthis;
if ( typeof window.BandeauxPortails_ShowRedirect !== 'undefined' ) commonjsOptions.showRedirect = window.BandeauxPortails_ShowRedirect;
if ( typeof window.BandeauxPortails_SkipConfirm !== 'undefined' ) commonjsOptions.skipConfirm = window.BandeauxPortails_SkipConfirm;
if ( typeof window.BandeauxPortails_TailleListe !== 'undefined' ) commonjsOptions.tailleListe = window.BandeauxPortails_TailleListe;
if ( typeof window.BandeauxPortails_ListeBas !== 'undefined' ) commonjsOptions.listeBas = window.BandeauxPortails_ListeBas;
const savedOptions = JSON.parse( mw.user.options.get( 'userjs-bandeauxPortails-settings' ) ) || {};
let userOptions = Object.assign( {}, defaultOptions, savedOptions, commonjsOptions );
// Groupe nécessaire pour appliquer une balise
const BandeauxPortails_TagGroup = 'user';
// Balise à appliquer aux modifs
const BandeauxPortails_Tag = mw.config.get( 'wgServer' ) === '//fr.wikipedia.org' && mw.config.get( 'wgUserGroups' ).includes( BandeauxPortails_TagGroup ) ? 'BandeauxPortails' : '';
if ( mw.config.get( 'wgAction' ) === 'view' && ( mw.config.get( 'wgNamespaceNumber' ) === 0 ) ) {
mw.loader.using( [ 'mediawiki.api', 'oojs-ui' ], function () {
$( function ( $ ) {
// Objet mw.Api
const api = new mw.Api({ userAgent: 'BandeauxPortails/1.0' });
let formOpen = false;
mw.util.addCSS(`
.redirection-portail { font-style: italic }
.bandeau-portail-edit {
float: right;
margin-top: 1ex;
}
.skin-minerva .bandeau-portail-edit {
margin-top: 0;
}
.bandeauxportails-formulaire {
max-width: none;
margin-top: 1em;
}
.bandeauxportails-formulaire .bandeau-portail-element a,
.bandeauxportails-formulaire .oo-ui-tagItemWidget a.new {
pointer-events: none;
}
.bouton-settings-bandeauportail {
margin-top: .2em;
}
.bouton-submit-bandeauportail {
float: right;
margin-top: .2em;
}
.bandeau-portail-vide {
font-style: italic;
color: var(--color-placeholder, #72777d);
}
.bandeauxportail-hidden-option {
display:none;
}
`);
// Enregistrement systématique de l'option singleEdits: true
// Temporaire, pour pouvoir ensuite changer la valeur par défaut sans affecter les anciens utilisateurs
if ( mw.user.options.get( 'userjs-bandeauxPortails-settings' ) === null ) {
api.saveOption( 'userjs-bandeauxPortails-settings', JSON.stringify( { singleEdits: true } ) );
}
/////////////////////////////////////////////////////////////////////////////////// Utilitaire
const getPageContent = async function () {
const data = await api.get({
action: 'query',
titles: mw.config.get( 'wgPageName' ),
prop: 'revisions',
rvprop: 'content',
rvslots: 'main',
formatversion: 2
});
return data.query.pages[ 0 ].revisions[ 0 ].slots.main.content;
}
const parse = async function ( wikitext ) {
const data = await api.get({
action: 'parse',
title: mw.config.get( 'wgPageName' ),
text: wikitext,
prop: 'text',
disablelimitreport: true,
wrapoutputclass: '',
formatversion: 2,
utf8: true
})
return data.parse.text;
}
/////////////////////////////////////////////////////////////////////////////////// Édition
const BandeauxPortails_Edit = async function ( anciensPortails, nouveauxPortails ) {
// Vérification de l'absence de conflit d'édition
let ancienTexte = await getPageContent();
const regexParamsPortail = /\{\{\s*[Pp]ortail(.*?)\}\}/;
const matchPortail = ancienTexte.match( regexParamsPortail );
let portailsActuels = [];
if ( matchPortail ) {
portailsActuels = matchPortail[ 1 ]
.split( '|' )
.map( param => param.trim() )
.filter( param => param !== '' );
}
if ( JSON.stringify( portailsActuels ) !== JSON.stringify( anciensPortails ) ) {
mw.notify( 'Les portails ont changé pendant votre modification. Impossible d\'appliquer les changements.', { type: 'error' } );
return;
}
let nouveauModele = '';
if ( nouveauxPortails.length === 0 ) {
if ( !userOptions.skipConfirm && ! await OO.ui.confirm( 'Supprimer le modèle {{Portail}} ?' ) ) {
return;
}
} else {
nouveauModele = '{{Portail|' + nouveauxPortails.join( '|' ) + '}}';
}
// Construction du sommaire
let sommaire;
const added = nouveauxPortails.filter( portail => !anciensPortails.includes( portail ));
const removed = anciensPortails.filter( portail => !nouveauxPortails.includes( portail ));
if ( added.length !== 0 && removed.length !== 0 ) {
sommaire = 'Changement rapide de {{Portail}} : - ' + removed.join( ' , - ' ) + ' , + ' + added.join( ' , + ' );
} else if ( removed.length !== 0 ) {
sommaire = 'Retrait rapide de {{Portail}} : - ' + removed.join( ' , - ' );
} else if ( added.length !== 0 ) {
sommaire = 'Ajout rapide de {{Portail}} : + ' + added.join( ' , + ' );
} else {
sommaire = 'Changement rapide de {{Portail}}';
}
// Mise à jour du Portail
let nouveauTexte = ancienTexte;
if ( matchPortail ) {
const regexPortail = /\{\{\s*[Pp]ortail.*?\}\}/;
nouveauTexte = nouveauTexte.replace( regexPortail, nouveauModele );
} else {
const regexCategories = /(\{\{DEFAULTSORT:|\{\{CLEDETRI:|\{\{CLEFDETRI:|\[\[[Cc]at[ée]gor(ie|y):)/;
const matchCategories = ancienTexte.match( regexCategories );
if ( matchCategories ) {
nouveauTexte = nouveauTexte.replace( regexCategories, nouveauModele + '\n\n$1' );
} else {
const interWiki = /^\s*\[\[([a-z][a-z].?(x?-[^]]+)?|simple|tokipona):([^\]]*)\]\]\s*$/;
const blank = /^\s*$/;
const lines = ancienTexte.split( '\n' );
let DebutModele = '';
let SuiteModele = '';
for ( let lineId = lines.length - 1; lineId >= 0; --lineId) {
if ( !interWiki.test( lines[ lineId ] ) && !blank.test( lines[ lineId ] ) ) {
DebutModele = lines.slice( 0, lineId + 1 ).join( '\n' ) + '\n\n';
SuiteModele = lines.slice( lineId + 1 ).join( '\n' );
break;
}
}
if ( DebutModele === '' ) {
// edge case: source has nothing else than interwikis
SuiteModele = ancienTexte;
}
while ( SuiteModele.indexOf( '\n\n' ) !== -1 ) {
SuiteModele = SuiteModele.split( '\n\n' ).join( '\n' );
}
SuiteModele = SuiteModele.replace( /^\n/, '' );
}
}
// Publication directe ou ouverture de l'éditeur
if ( userOptions.autoEdit === false ) {
mw.loader.using( 'mediawiki.storage', function () {
mw.storage.set( 'bandeaux-portails-newtext', nouveauTexte, 3600 );
mw.storage.set( 'bandeaux-portails-summary', sommaire, 3600 );
location.href = mw.config.get( 'wgScript' ) + '?action=edit&title=' + mw.config.get( 'wgPageName' );
});
} else {
const watchthisparam = {
'-1': 'nochange',
0: 'unwatch',
1: 'watch'
};
const datas = {
action : 'edit',
title : mw.config.get( 'wgPageName' ),
text : nouveauTexte,
minor : userOptions.minorEdit,
watchlist : watchthisparam[ userOptions.watchthis ]
};
if ( BandeauxPortails_Tag !== '' ) {
datas.summary = sommaire;
datas.tags = BandeauxPortails_Tag;
} else {
datas.summary = sommaire + ' ; avec [[Projet:Scripts et gadgets/Notices/BandeauxPortails|BandeauxPortails]]';
}
try {
await api.postWithEditToken( datas );
location.hash = '#bandeau-portail';
location.reload();
} catch ( e ) {
mw.notify( `La publication a échoué : ${ e }`, { type: 'error' } );
}
}
};
/////////////////////////////////////////////////////////////////////////////////// Formulaire
let BandeauxPortails_tagMultiselectWidget, BandeauxPortails_layout;
const PortalInputWidget = function () {
OO.ui.TextInputWidget.call( this, {
placeholder: 'Entrez un portail à ajouter...',
autocomplete: false,
validate: input => !/[{}|<>\[\]]/.test( input ) // eslint-disable-line no-useless-escape
});
OO.ui.mixin.LookupElement.call( this, { api } );
};
OO.inheritClass( PortalInputWidget, OO.ui.TextInputWidget );
OO.mixinClass( PortalInputWidget, OO.ui.mixin.LookupElement );
PortalInputWidget.prototype.getLookupRequest = function () {
const inputValue = this.getValue();
const params = {
action: 'query',
list: 'categorymembers',
cmtitle: 'Catégorie:Modèle lien vers portail/Liste complète',
cmstartsortkeyprefix: inputValue,
cmtype: 'page',
cmlimit: 200,
formatversion: 2
};
return api.get( params );
};
PortalInputWidget.prototype.getLookupCacheDataFromResponse = function ( response ) {
return response.query.categorymembers
.map( page => page.title.replace( /Modèle:Portail /, '' ) );
};
PortalInputWidget.prototype.getLookupMenuOptionsFromData = async function ( data ) {
let allPages = [];
let portailRedirects = [];
const inputValue = this.getValue();
if ( userOptions.showRedirect ) {
const params = {
action: 'query',
list: 'categorymembers',
cmtitle: 'Catégorie:Redirection de modèle - portail',
cmstartsortkeyprefix: inputValue,
cmtype: 'page',
cmlimit: 200,
formatversion: 2
};
const dataRedirects = await api.get( params );
portailRedirects = dataRedirects.query.categorymembers.map( page => page.title.replace( /Modèle:Portail /, '' ) );
allPages = data
.concat( portailRedirects );
} else {
allPages = data;
}
BandeauxPortails_tagMultiselectWidget.allowedValues = [ ...new Set( [ ...BandeauxPortails_tagMultiselectWidget.allowedValues, ...allPages ] ) ];
const collator = new Intl.Collator( 'fr', { sensitivity: 'base' });
const suggestedPages = allPages
.filter( portail => {
const portailSlice = portail.slice( 0, inputValue.length );
return collator.compare( portailSlice, inputValue ) === 0;
})
.sort( ( a, b ) => a.localeCompare( b, 'fr', { sensitivity: 'base' } ) );
return suggestedPages.map( portail => new OO.ui.MenuOptionWidget({
data: portail,
label: portail,
classes: portailRedirects.includes( portail ) ? [ 'redirection-portail' ] : []
}));
};
PortalInputWidget.prototype.onLookupMenuChoose = function ( item ) {
BandeauxPortails_tagMultiselectWidget.addTag( item.getData() );
this.setValue( '' );
};
const BandeauxPortails_TagMultiselectWidget = function ( selected ) {
OO.ui.TagMultiselectWidget.call( this, {
inputWidget: new PortalInputWidget(),
inputPosition: 'outline',
selected: selected,
allowedValues: selected,
tagLimit: 20, // 20 portails max, cf la documentation et le code de [[Modèle:Portail]]
classes: [ 'bandeauxportails-formulaire' ]
});
};
OO.inheritClass( BandeauxPortails_TagMultiselectWidget, OO.ui.TagMultiselectWidget );
BandeauxPortails_TagMultiselectWidget.prototype.createTagItemWidget = function ( data, label ) {
// mise en forme des TagItemWidget en remplaçant le nom brut du portail
// par le HTML parsé du modèle de portail concerné
const tagWidget = new OO.ui.TagItemWidget( { data: data, label: label || data } );
parse( '{{Portail ' + data + '|parent=bandeau}}' )
.then( ( parsedContent ) => {
const parsedContentStripped = parsedContent.replace(/<li>|<\/li>|<p>|<\/p>/g, '');
tagWidget.$element.find( '.oo-ui-labelElement-label' ).html( parsedContentStripped );
});
return tagWidget;
};
const BandeauxPortails_showForm = async function () {
if ( formOpen ) return;
formOpen = true;
// Solution temporaire en attendant la résolution de [[phab:T414331]]
$( '.vector-sticky-header-container' ).appendTo( '#bodyContent' );
// Lecture des paramètres du modèle {{Portail}}
let anciensPortails = [];
const data = await api.get({
action: 'query',
titles: mw.config.get( 'wgPageName' ),
prop: 'revisions',
rvprop: 'content',
rvslots: 'main',
formatversion: 2
});
let ancienTexte = data.query.pages[ 0 ].revisions[ 0 ].slots.main.content;
const regexParamsPortail = /\{\{\s*[Pp]ortail(.*?)\}\}/;
const matchPortail = ancienTexte.match( regexParamsPortail );
if ( matchPortail ) {
anciensPortails = matchPortail[ 1 ]
.split( '|' )
.map( param => param.trim() )
.filter( param => param !== '' );
}
// Création du formulaire
BandeauxPortails_tagMultiselectWidget = new BandeauxPortails_TagMultiselectWidget( anciensPortails );
BandeauxPortails_layout = new OO.ui.FieldLayout( BandeauxPortails_tagMultiselectWidget ); // Le FieldLayout sert à afficher des avertissements.
const bandeau = $( '#bandeau-portail' );
bandeau.hide();
bandeau.after( BandeauxPortails_layout.$element );
const paramButton = new OO.ui.ButtonWidget( {
label: 'Paramètres',
icon: 'settings',
classes: [ 'bouton-settings-bandeauportail' ]
} );
paramButton.on( 'click', () => openOptionsDialog() );
const submitButton = document.createElement( 'input' );
submitButton.type = 'button';
submitButton.value = 'Enregistrer';
submitButton.disabled = true;
submitButton.className = 'cdx-button cdx-button--action-progressive cdx-button--weight-primary bouton-submit-bandeauportail';
submitButton.addEventListener( 'click', () => {
const nouveauxPortails = BandeauxPortails_tagMultiselectWidget.getValue();
BandeauxPortails_Edit( anciensPortails, nouveauxPortails );
});
const cancelButton = document.createElement( 'input' );
cancelButton.type = 'button';
cancelButton.value = 'Annuler';
cancelButton.className = 'cdx-button cdx-button--action-destructive cdx-button--weight-quiet bouton-submit-bandeauportail';
cancelButton.addEventListener( 'click', () => {
bandeau.show();
BandeauxPortails_layout.$element.remove();
paramButton.$element.remove();
submitButton.remove();
cancelButton.remove();
formOpen = false;
} );
BandeauxPortails_layout.$element.after( submitButton, cancelButton, paramButton.$element );
BandeauxPortails_tagMultiselectWidget.on( 'change', function () {
const nouveauxPortails = BandeauxPortails_tagMultiselectWidget.getValue();
const warnings = !BandeauxPortails_tagMultiselectWidget.isUnderLimit() ? [ 'Le nombre maximal de portails a été atteint.' ] : [];
BandeauxPortails_layout.setWarnings( warnings );
submitButton.disabled = JSON.stringify( nouveauxPortails ) === JSON.stringify( anciensPortails );
});
};
/////////////////////////////////////////////////////////////////////////////////// Gestion des préférences
// Utilisation d'un Process Dialog, voir [[mw:OOUI/Windows/Process Dialogs]]
const BandeauxPortailsOptionsDialog = function ( config ) {
BandeauxPortailsOptionsDialog.super.call( this, config );
};
OO.inheritClass( BandeauxPortailsOptionsDialog, OO.ui.ProcessDialog );
BandeauxPortailsOptionsDialog.static.name = 'BandeauxPortailsOptionsDialog';
BandeauxPortailsOptionsDialog.static.title = 'Préférences de BandeauxPortails';
BandeauxPortailsOptionsDialog.static.actions = [{
action: 'save',
label: 'Valider',
flags: [ 'primary', 'progressive' ]
}, {
label: 'Annuler',
flags: 'safe'
}];
BandeauxPortailsOptionsDialog.prototype.initialize = function () {
BandeauxPortailsOptionsDialog.super.prototype.initialize.apply( this );
this.content = new OO.ui.PanelLayout({
padded: true,
expanded: false
});
const BandeauxPortailsSettings = new OO.ui.FieldsetLayout({
label: 'Préférences'
});
const singleEditsCheckbox = new OO.ui.CheckboxInputWidget({
disabled: typeof commonjsOptions.singleEdits !== 'undefined',
selected: userOptions.singleEdits
})
this.singleEditsInput = new OO.ui.FieldLayout( singleEditsCheckbox, {
align: 'inline',
label: 'Afficher les boutons de modification individuels',
help: 'En cochant cette option, les boutons de suppression, de changement et d\'ajout de portail à côté de chaque portail s\'afficheront.'
});
this.tailleListeInput = new OO.ui.FieldLayout( new OO.ui.NumberInputWidget( {
disabled: typeof commonjsOptions.tailleListe !== 'undefined',
input: { value: userOptions.tailleListe },
min: 0,
max: 500,
}), {
align: 'inline',
label: 'Nombre de suggestions à afficher',
help: 'Pour les boutons de modification individuels uniquement : nombre de suggestions à afficher dans les champs de saisie.',
classes: !userOptions.singleEdits ? [ 'bandeauxportail-hidden-option' ] : []
});
this.listeBasInput = new OO.ui.FieldLayout( new OO.ui.CheckboxInputWidget({
disabled: typeof commonjsOptions.listeBas !== 'undefined',
selected: userOptions.listeBas
}), {
align: 'inline',
label: 'Positionner les suggestions en dessous de la saisie',
help: 'Pour les boutons de modification individuels uniquement : positionner les suggestions au dessus ou au dessous des champs de saisie.',
classes: !userOptions.singleEdits ? [ 'bandeauxportail-hidden-option' ] : []
});
singleEditsCheckbox.on( 'change', ( selected ) => {
if ( !selected ) {
this.tailleListeInput.$element.addClass( 'bandeauxportail-hidden-option' );
this.listeBasInput.$element.addClass( 'bandeauxportail-hidden-option' );
} else {
this.tailleListeInput.$element.removeClass( 'bandeauxportail-hidden-option' );
this.listeBasInput.$element.removeClass( 'bandeauxportail-hidden-option' );
}
});
this.autoLaunchInput = new OO.ui.FieldLayout( new OO.ui.CheckboxInputWidget({
disabled: typeof commonjsOptions.autoLaunch !== 'undefined',
selected: userOptions.autoLaunch
}), {
align: 'inline',
label: 'Charger automatiquement le formulaire de modifications multiples',
help: 'En cochant cette option, le formulaire de modification du modèle Portail sera automatiquement chargé dans les articles, sans avoir à cliquer sur le bouton « modifier ».'
});
this.autoEditInput = new OO.ui.FieldLayout( new OO.ui.CheckboxInputWidget({
disabled: typeof commonjsOptions.autoEdit !== 'undefined',
selected: userOptions.autoEdit
}), {
align: 'inline',
label: 'Publication automatique',
help: 'En décochant cette option, la modification des portails ne sera pas effectuée automatiquement en cliquant sur « Enregistrer ». À la place, l\'éditeur s\'ouvrira automatiquement avec le remplacement des portails déjà effectué (l\'édition manuelle des portails est incompatible avec l\'éditeur visuel).'
});
this.minorEditInput = new OO.ui.FieldLayout( new OO.ui.CheckboxInputWidget({
disabled: typeof commonjsOptions.minorEdit !== 'undefined',
selected: userOptions.minorEdit
}), {
align: 'inline',
label: 'Marquer les modifications comme mineures',
help: 'En cochant cette option, les modifications effectuées à l\'aide du gadget seront automatiquement marquées comme mineures.'
});
this.watchThisInput = new OO.ui.FieldLayout( new OO.ui.ButtonSelectWidget( {
disabled: typeof commonjsOptions.watchthis !== 'undefined',
items: [
new OO.ui.ButtonOptionWidget( {
selected: userOptions.watchthis === '-1',
data: '-1',
label: 'défaut préférences'
} ),
new OO.ui.ButtonOptionWidget( {
selected: userOptions.watchthis === 0,
data: 0,
label: 'jamais'
} ),
new OO.ui.ButtonOptionWidget( {
selected: userOptions.watchthis === 1,
data: 1,
label: 'toujours'
} )
]
} ), {
align: 'inline',
label: 'Ajout à la liste de suivi',
help: 'Sélection des modalités d\'ajout automatique des pages modifiées avec le gadget à la liste de suivi.'
});
this.showRedirectInput = new OO.ui.FieldLayout( new OO.ui.CheckboxInputWidget({
disabled: typeof commonjsOptions.showRedirect !== 'undefined',
selected: userOptions.showRedirect
}), {
align: 'inline',
label: 'Affichage des redirections dans les suggestions',
help: 'En cochant cette option, les alias de noms de portails seront affichés en italique dans les suggestions de saisie.'
});
this.skipConfirmInput = new OO.ui.FieldLayout( new OO.ui.CheckboxInputWidget({
disabled: typeof commonjsOptions.skipConfirm !== 'undefined',
selected: userOptions.skipConfirm
}), {
align: 'inline',
label: 'Ne pas confirmer la suppression du bandeau',
help: 'En cochant cette option, la boîte de dialogue demandant la confirmation de suppression ne s\'affichera plus.',
});
BandeauxPortailsSettings.addItems( [
this.singleEditsInput,
this.tailleListeInput,
this.listeBasInput,
this.autoLaunchInput,
this.autoEditInput,
this.minorEditInput,
this.watchThisInput,
this.showRedirectInput,
this.skipConfirmInput,
] );
this.content.$element.append( BandeauxPortailsSettings.$element, '<hr><p>Si des paramètres ont été définis depuis votre <a href="https://fr.m.vvikipidea.org/wiki/Spécial:Ma page/common.js" title="Spécial:Ma page/common.js" target="_blank">common.js</a>, ils ne peuvent pas être modifiés ici. Pour plus d\'informations sur ce gadget, voir <a href="https://fr.m.vvikipidea.org/wiki/Projet:Scripts_et_gadgets/Notices/BandeauxPortails" title="Projet:Scripts et gadgets/Notices/BandeauxPortails" target="_blank">Projet:Scripts et gadgets/Notices/BandeauxPortails</a>.</p>' );
this.$body.append( this.content.$element );
};
BandeauxPortailsOptionsDialog.prototype.getActionProcess = function ( action ) {
const dialog = this;
if ( action === 'save' ) {
return new OO.ui.Process( function () {
const changedOptions = {};
if ( dialog.singleEditsInput.getField().selected !== defaultOptions.singleEdits ) { changedOptions.singleEdits = dialog.singleEditsInput.getField().selected }
if ( dialog.tailleListeInput.getField().getNumericValue() !== defaultOptions.tailleListe ) { changedOptions.tailleListe = dialog.tailleListeInput.getField().getNumericValue() }
if ( dialog.listeBasInput.getField().selected !== defaultOptions.listeBas ) { changedOptions.listeBas = dialog.listeBas.getField().selected }
if ( dialog.autoLaunchInput.getField().selected !== defaultOptions.autoLaunch ) { changedOptions.autoLaunch = dialog.autoLaunchInput.getField().selected }
if ( dialog.autoEditInput.getField().selected !== defaultOptions.autoEdit ) { changedOptions.autoEdit = dialog.autoEditInput.getField().selected }
if ( dialog.minorEditInput.getField().selected !== defaultOptions.minorEdit ) { changedOptions.minorEdit = dialog.minorEditInput.getField().selected }
if ( dialog.watchThisInput.getField().findFirstSelectedItem().data !== defaultOptions.watchthis ) { changedOptions.watchthis = dialog.watchThisInput.getField().findFirstSelectedItem().data }
if ( dialog.showRedirectInput.getField().selected !== defaultOptions.showRedirect ) { changedOptions.showRedirect = dialog.showRedirectInput.getField().selected }
if ( dialog.skipConfirmInput.getField().selected !== defaultOptions.skipConfirm ) { changedOptions.skipConfirm = dialog.SkipConfirmInput.getField().selected }
userOptions = Object.assign( {}, defaultOptions, changedOptions, commonjsOptions );
changedOptions.singleEdits = userOptions.singleEdits;
api.saveOption( 'userjs-bandeauxPortails-settings', JSON.stringify( changedOptions ) );
dialog.close({
action: action
});
});
}
return BandeauxPortailsOptionsDialog.super.prototype.getActionProcess.call( this, action );
};
const openOptionsDialog = function () {
const windowManager = new OO.ui.WindowManager();
$( document.body ).append( windowManager.$element );
const bandeauxPortailsOptionsDialog = new BandeauxPortailsOptionsDialog();
windowManager.addWindows( [ bandeauxPortailsOptionsDialog ] );
windowManager.openWindow( bandeauxPortailsOptionsDialog );
};
/////////////////////////////////////////////////////////////////////////////////// Formulaires
const BandeauxPortails_Cancel = function( id ) {
const Span = document.getElementById( id );
Span.style.display = 'inline';
const Parent = Span.parentNode;
const Form = Parent.getElementsByTagName( 'form' )[ 0 ];
Form.remove();
};
const BandeauxPortails_SupprOne = async function( anciensPortails, portailSuppr ) {
if ( userOptions.skipConfirm || await OO.ui.confirm( `Voulez-vous vraiment supprimer le portail « ${ portailSuppr } » ?` ) ) {
const nouveauxPortails = anciensPortails.filter( portail => portail !== portailSuppr );
BandeauxPortails_Edit( anciensPortails, nouveauxPortails );
}
};
const BandeauxPortails_ModifyThatOne = function( anciensPortails, id ) {
const input = document.getElementById( 'input-modify_' + id );
if ( input.value !== '' && input.value !== anciensPortails[ id ] ) {
const portailsAjoutes = input.value.split( '|' );
const nouveauxPortails = [ ...anciensPortails.slice( 0, id ), ...portailsAjoutes, ...anciensPortails.slice( parseInt( id ) + 1 ) ];
BandeauxPortails_Edit( anciensPortails, nouveauxPortails );
} else {
BandeauxPortails_Cancel( 'lien-portail_' + id );
}
};
const BandeauxPortails_ModifyOne = function( anciensPortails, id ) {
const span = document.getElementById( 'lien-portail_' + id );
span.style.display = 'none';
const form = document.createElement( 'form' );
form.addEventListener( 'submit', ( event ) => {
event.preventDefault();
BandeauxPortails_ModifyThatOne( anciensPortails, id );
});
form.style.display = 'inline';
const select = document.createElement( 'select' );
select.id = 'select-modify_' + id;
select.style.display = 'none';
select.title = 'Suggestions de bandeaux';
const textInput = document.createElement( 'input' );
textInput.id = 'input-modify_' + id;
textInput.type = 'text';
textInput.value = anciensPortails[ id ];
textInput.onkeyup = () => BandeauxPortails_TextChanged( 'select-modify_' + id );
const okButton = document.createElement( 'input' );
okButton.type = 'button';
okButton.className = 'cdx-button cdx-button--action-progressive cdx-button--weight-primary cdx-button--size-small';
okButton.addEventListener( 'click', () => BandeauxPortails_ModifyThatOne( anciensPortails, id ) );
okButton.addEventListener( 'select', () => BandeauxPortails_ModifyThatOne( anciensPortails, id ) );
okButton.value = 'OK';
const cancelButton = document.createElement( 'input' );
cancelButton.type = 'button';
cancelButton.className = 'cdx-button cdx-button--action-destructive cdx-button--weight-quiet cdx-button--size-small';
cancelButton.addEventListener( 'click', () => BandeauxPortails_Cancel( 'lien-portail_' + id ) );
cancelButton.addEventListener( 'select', () => BandeauxPortails_Cancel( 'lien-portail_' + id ) );
cancelButton.value = 'Annuler';
form.append( select, textInput, okButton, cancelButton );
span.before( form );
document.getElementById( 'input-modify_' + id ).focus() ;
};
const BandeauxPortails_AddThatOne = function( anciensPortails ) {
const input = document.getElementById( 'input-add' );
if ( input.value !== '' ) {
const portailsAjoutes = input.value.split( '|' );
BandeauxPortails_Edit( anciensPortails, [ ...anciensPortails, ...portailsAjoutes ] );
} else {
BandeauxPortails_Cancel( 'BandeauxPortails_Add' );
}
};
const BandeauxPortails_AddOne = function ( anciensPortails ) {
const span = document.getElementById( 'BandeauxPortails_Add' );
span.style.display = 'none';
const form = document.createElement( 'form' );
form.style.display = 'inline';
form.addEventListener( 'submit', ( event ) => {
event.preventDefault();
BandeauxPortails_AddThatOne( anciensPortails );
});
const selectElement = document.createElement( 'select' );
selectElement.id = 'select-add';
selectElement.style.display = 'none';
selectElement.title = 'Suggestions de bandeaux';
const inputTextElement = document.createElement( 'input' );
inputTextElement.id = 'input-add';
inputTextElement.type = 'text';
inputTextElement.value = '';
inputTextElement.onkeyup = () => BandeauxPortails_TextChanged( 'select-add' );
const buttonOkElement = document.createElement( 'input' );
buttonOkElement.type = 'button';
buttonOkElement.className = 'cdx-button cdx-button--action-progressive cdx-button--weight-primary cdx-button--size-small';
buttonOkElement.addEventListener( 'click', () => BandeauxPortails_AddThatOne( anciensPortails ) );
buttonOkElement.addEventListener( 'select', () => BandeauxPortails_AddThatOne( anciensPortails ) );
buttonOkElement.value = 'OK';
const buttonCancelElement = document.createElement( 'input' );
buttonCancelElement.type = 'button';
buttonCancelElement.className = 'cdx-button cdx-button--action-destructive cdx-button--weight-quiet cdx-button--size-small';
buttonCancelElement.addEventListener( 'click', () => BandeauxPortails_Cancel( 'BandeauxPortails_Add' ) );
buttonCancelElement.addEventListener( 'select', () => BandeauxPortails_Cancel( 'BandeauxPortails_Add' ) );
buttonCancelElement.value = 'Annuler';
form.append( selectElement, inputTextElement, buttonOkElement, buttonCancelElement );
span.before( form );
document.getElementById( 'input-add' ).focus() ;
};
/////////////////////////////////////////////////////////////////////////////////// Suggestions des saisies individuelles
const BandeauxPortails_TextChanged = async function ( id ) {
if ( userOptions.tailleListe === 0 ) return;
const select = document.getElementById( id ) ;
const idInput = id.replace( 'select', 'input' );
const input = document.getElementById( idInput ) ;
if ( !input || !select ) return;
const value = input.value;
if ( value === '' ) return;
const allParams = value.split( '|' );
// Récupération de la liste des suggestions
const params = {
action: 'query',
list: 'categorymembers',
cmtitle: 'Catégorie:Modèle lien vers portail/Liste complète',
cmstartsortkeyprefix: allParams[ allParams.length - 1 ],
cmtype: 'page',
cmlimit: userOptions.tailleListe,
formatversion: 2
};
const data = await api.get( params );
const allPages = data.query.categorymembers.map( page => page.title.replace( /Modèle:Portail /, '' ) );
let portailRedirects = [];
if ( userOptions.showRedirect ) {
params.cmtitle = 'Catégorie:Redirection de modèle - portail';
const dataRedirects = await api.get( params );
portailRedirects = dataRedirects.query.categorymembers.map( page => page.title.replace( /Modèle:Portail /, '' ) );
allPages.push( ...portailRedirects );
}
const resultArray = allPages
.sort( ( a, b ) => a.localeCompare( b, 'fr', { sensitivity: 'base' } ) )
.slice( 0, userOptions.tailleListe );
// Affichage des suggestions
select.innerHTML = '';
for ( const titrePage of resultArray ) {
const option = document.createElement( 'option' );
option.value = titrePage;
option.innerHTML = titrePage;
if ( portailRedirects.includes( titrePage ) ) option.style.fontStyle = 'italic';
select.append( option );
}
if ( select.length > 0 ) {
select.addEventListener( 'change', function () {
const titrePage = this.value;
const allParams = value.split( '|' );
allParams[ allParams.length - 1 ] = titrePage
input.value = allParams.join( '|' );
input.focus() ;
});
select.size = select.length;
select.style.display = 'inline';
select.style.zIndex = 5 ;
select.style.position = 'absolute' ;
select.style.width = input.offsetWidth + 'px' ;
if ( userOptions.listeBas ) {
select.style.top = ( parseInt( input.offsetTop ) + parseInt( input.offsetHeight ) ) + 'px';
} else {
select.style.top = ( parseInt( input.offsetTop ) - select.offsetHeight ) + 'px';
}
select.style.left = ( parseInt( input.parentNode.offsetLeft ) - 1 ) + 'px';
} else {
select.style.display = 'none';
select.innerHTML = '';
}
};
/////////////////////////////////////////////////////////////////////////////////// Fonction active au chargement de la page (saisie individuelle)
const BandeauxPortails_ModifyUl = async function () {
const bandeauUl = document.getElementById( 'bandeau-portail' );
if ( !bandeauUl ) return;
// Ajout des boutons (-) et (±) pour chaque portail
const contenu = await getPageContent();
let anciensPortails = [];
const regexParamsPortail = /\{\{\s*[Pp]ortail(.*?)\}\}/;
const match = contenu.match( regexParamsPortail );
if ( match ) {
anciensPortails = match[ 1 ]
.split( '|' )
.map( param => param.trim() )
.filter( param => param !== '' );
const portailItems = bandeauUl.querySelectorAll( ':scope > li, :scope > a.new' );
for ( const [ i, param ] of Object.entries( anciensPortails ) ) {
// Les éléments du bandeau du DOM correspondent aux portails du wikicode
// y compris en cas de paramètre vide et de portail incorrect (lien rouge)
const portailItem = portailItems[ i ];
const lien = portailItem.querySelector( '.bandeau-portail-texte a' );
let titre = '';
let spanLien;
if ( lien ) {
titre = lien.title.replace( 'Portail:', '' );
spanLien = lien.parentNode;
} else {
const lienRouge = portailItem;
titre = lienRouge.innerHTML.replace( 'Modèle:Portail', '' );
spanLien = document.createElement( 'span' );
}
spanLien.id = 'lien-portail_' + i;
const deleteLink = document.createElement( 'a' );
deleteLink.href = '#';
deleteLink.textContent = '(-)';
deleteLink.title = 'Supprimer le bandeau de portail ' + titre;
deleteLink.addEventListener( 'click', function ( e ) {
e.preventDefault();
BandeauxPortails_SupprOne( anciensPortails, param );
});
const modifyLink = document.createElement( 'a' );
modifyLink.href = '#';
modifyLink.textContent = '(±)';
modifyLink.title = 'Modifier le bandeau de portail ' + titre;
modifyLink.addEventListener( 'click', function ( e ) {
e.preventDefault();
BandeauxPortails_ModifyOne( anciensPortails, i );
});
spanLien.append( ' • ', deleteLink, ' • ', modifyLink );
if ( !lien ) {
const lienRouge = portailItem;
const newLi = document.createElement( 'li' );
lienRouge.replaceWith( newLi );
newLi.append( lienRouge, spanLien );
}
}
}
// Ajout du bouton (+)
const addLi = document.createElement( 'li' );
addLi.id = 'lien-portail_add';
const span = document.createElement( 'span' );
span.className = 'bandeau-portail-element';
const spanTexte = document.createElement( 'span' );
spanTexte.className = 'bandeau-portail-texte';
spanTexte.id = 'BandeauxPortails_Add';
const linkElement = document.createElement( 'a' );
linkElement.textContent = '(+)';
linkElement.title = 'Ajouter un bandeau de portail';
linkElement.addEventListener( 'click', () => BandeauxPortails_AddOne( anciensPortails ) );
spanTexte.append( linkElement );
span.append( spanTexte );
addLi.append( span );
bandeauUl.appendChild( addLi );
};
/////////////////////////////////////////////////////////////////////////////////// Initialisation au chargement de la page
const homonymie = document.getElementById( 'homonymie' );
let bandeauUl = document.getElementById( 'bandeau-portail' );
if ( homonymie && !bandeauUl ) return;
if ( !bandeauUl ) {
const catLinks = document.getElementById( 'catlinks' );
if ( !catLinks ) return;
bandeauUl = document.createElement( 'ul' );
bandeauUl.id = 'bandeau-portail';
bandeauUl.className = 'bandeau-portail';
bandeauUl.innerHTML = '<span class="bandeau-portail-vide">Aucun portail.</span>';
catLinks.before( bandeauUl );
}
if ( userOptions.singleEdits ) {
BandeauxPortails_ModifyUl();
}
if ( userOptions.autoLaunch ) {
BandeauxPortails_showForm();
}
// Le bouton « modifier » est ajouté même pour le chargement automatique pour le cas où l'utilisateur clique sur « annuler »
const editA = document.createElement( 'a' );
editA.title = 'Modifier le bandeau portails';
editA.setAttribute( 'role', 'button' );
editA.addEventListener( 'click', () => BandeauxPortails_showForm() );
const editSpan = document.createElement( 'span' );
editSpan.className = 'bandeau-portail-edit mw-editsection-like';
if ( mw.config.get( 'skin' ) === 'minerva' ) {
editA.className = 'cdx-button cdx-button--size-small cdx-button--fake-button cdx-button--fake-button--enabled cdx-button--icon-only cdx-button--weight-quiet mw-editsection-visualeditor';
const spanIcon = document.createElement( 'span' );
spanIcon.className = 'minerva-icon minerva-icon--edit';
const spanModifier = document.createElement( 'span' );
spanModifier.innerHTML = 'modifier';
editA.append( spanIcon, spanModifier );
editSpan.append( editA );
} else {
editA.innerHTML = 'modifier';
const editLeftBracket = document.createElement( 'span' );
editLeftBracket.className = 'mw-editsection-bracket';
editLeftBracket.innerHTML = '[';
const editRightBracket = document.createElement( 'span' );
editRightBracket.className = 'mw-editsection-bracket';
editRightBracket.innerHTML = ']';
editSpan.append( editLeftBracket, editA, editRightBracket );
}
bandeauUl.prepend( editSpan );
});
} );
}
/////////////////////////////////////////////////////////////////////////////////// Édition manuelle de la page lorsque userOptions.autoEdit === false
const BandeauxPortails_manualEdit = function () {
const newText = mw.storage.get( 'bandeaux-portails-newtext' );
if ( newText === null ) return;
const summary = mw.storage.get( 'bandeaux-portails-summary' ) || '';
mw.storage.remove( 'bandeaux-portails-newtext' );
mw.storage.remove( 'bandeaux-portails-summary' );
$( '#wpTextbox1' ).textSelection( 'setContents', newText ); // éditeurs de wikicode bureau
$( '#wikitext-editor' ).textSelection( 'setContents', newText ); // éditeur de wikicode mobile
/*if ( usesVe ) {
// éditeur visuel
// globals ve
const surface = ve.init.target.getSurface();
if ( surface.getMode() === 'visual' ) {
const surfaceModel = ve.init.target.getSurface().getModel();
const rangeToRemove = surfaceModel.getDocument().getDocumentRange();
const fragment = surfaceModel.getLinearFragment( rangeToRemove );
fragment.insertContent( newText );
}
}*/
$( '#wpSummary' ).textSelection( 'setContents', summary );
$( '#wpMinoredit' ).prop( { 'checked': userOptions.minorEdit } );
if ( userOptions.watchthis === 1 ) $( '#wpWatchthis' ).prop( { 'checked': true } );
if ( userOptions.watchthis === 0 ) $( '#wpWatchthis' ).prop( { 'checked': false } );
};
if ( ( mw.config.get( 'wgAction' ) === 'edit' && userOptions.autoEdit === false && mw.config.get( 'wgNamespaceNumber' ) === 0 ) ) {
mw.loader.using( [ 'jquery.textSelection', 'mediawiki.storage' ], function () {
mw.hook( 'wikipage.editform' ).add( () => BandeauxPortails_manualEdit() );
mw.hook( 've.activationComplete' ).add( () => BandeauxPortails_manualEdit() );
// Le hook mobile est marqué comme interne et est susceptible de changer sans préavis.
mw.hook( 'mobileFrontend.editorOpened' ).add( () => BandeauxPortails_manualEdit() );
});
}
//</nowiki></pre>
// ====================================================================================================================
// ==================================================================================================================== FIN DU CODE
//</syntaxhighlight>