« MediaWiki:Gadget-CatRename.js » : différence entre les versions
Contenu supprimé Contenu ajouté
m petit réarrangement de l'ordre de certaines méthodes, pour clarifier un peu le code |
Récupération, traitement (merci Od1n !) et validation des inputs de l'utilisateur une fois pour toute en début de process |
||
Ligne 121 : | Ligne 121 : | ||
CatRename.prototype.getActionProcess = function ( action ) { |
CatRename.prototype.getActionProcess = function ( action ) { |
||
if ( action === 'rename' ) { |
if ( action === 'rename' ) { |
||
return new OO.ui.Process( this. |
return new OO.ui.Process() |
||
.next( this.prepare, this ) |
|||
.next( this.checkCategory, this ) |
|||
.next( this.getMembers, this ) |
.next( this.getMembers, this ) |
||
.next( this.lockMultitabs, this ) |
.next( this.lockMultitabs, this ) |
||
Ligne 132 : | Ligne 134 : | ||
} |
} |
||
else if ( action === 'rbot' ) { |
else if ( action === 'rbot' ) { |
||
return new OO.ui.Process( this. |
return new OO.ui.Process() |
||
.next( this.prepare, this ) |
|||
.next( this.checkCategory, this ) |
|||
.next( this.getMembers, this ) |
.next( this.getMembers, this ) |
||
.next( this.postRBot, this ) |
.next( this.postRBot, this ) |
||
.next( this.renameCategory, this ) |
.next( this.renameCategory, this ) |
||
.next( this.unlockMultitabs, this ) |
|||
.next( this.success, this ) |
|||
.next( this.close, this ); |
.next( this.close, this ); |
||
} |
} |
||
else if ( action === 'cancel' ) { |
else if ( action === 'cancel' ) { |
||
return new OO.ui.Process( this.unlockMultitabs, this ) |
return new OO.ui.Process() |
||
.next( this.unlockMultitabs, this ) |
|||
.next( this.close, this ); |
.next( this.close, this ); |
||
} |
} |
||
Ligne 158 : | Ligne 165 : | ||
/* Process step methods */ |
/* Process step methods */ |
||
/** |
|||
* Fetch and validate user's input to make it easily accessible later. |
|||
* |
|||
* @return {undefined|OO.ui.Error} Error message for the ProcessDialog |
|||
* to display, if any. |
|||
*/ |
|||
CatRename.prototype.prepare = function() { |
|||
⚫ | |||
this.newTitle = this.newNameInput.getValue().trim().replace(/^([Cc]atégorie|[Cc]ategory):/, ''); |
|||
this.oldPageName = mw.config.get('wgFormattedNamespaces')[ 14 ] + ':' + this.oldTitle; |
|||
this.newPageName = mw.config.get('wgFormattedNamespaces')[ 14 ] + ':' + this.newdTitle; |
|||
⚫ | |||
⚫ | |||
⚫ | |||
⚫ | |||
⚫ | |||
if ( this.reason === '' ) { |
|||
return new OO.ui.Error( 'Veuillez indiquer une explication pour ce renommage.' ); |
|||
} |
|||
return; |
|||
}; |
|||
/** |
/** |
||
Ligne 182 : | Ligne 212 : | ||
return this.deferred; |
return this.deferred; |
||
} |
} |
||
⚫ | |||
⚫ | |||
⚫ | |||
return this.deferred; |
|||
} |
} |
||
Ligne 194 : | Ligne 219 : | ||
'formatversion': 2, |
'formatversion': 2, |
||
'prop': 'categoryinfo', |
'prop': 'categoryinfo', |
||
'titles': |
'titles': this.newPageName |
||
} ).then( function( data ) { |
} ).then( function( data ) { |
||
console.log( data ); |
console.log( data ); |
||
Ligne 397 : | Ligne 422 : | ||
*/ |
*/ |
||
CatRename.prototype.editMembers = function() { |
CatRename.prototype.editMembers = function() { |
||
var dialog = this |
var dialog = this, |
||
⚫ | |||
⚫ | |||
⚫ | |||
⚫ | |||
⚫ | |||
⚫ | |||
⚫ | |||
⚫ | |||
⚫ | |||
⚫ | |||
⚫ | |||
}; |
|||
this.deferred = $.Deferred(); |
this.deferred = $.Deferred(); |
||
⚫ | |||
console.log( '---> Édition des membres de la catégorie' ); |
console.log( '---> Édition des membres de la catégorie' ); |
||
⚫ | |||
⚫ | |||
newCatName = this.newNameInput.getValue(), |
|||
⚫ | |||
⚫ | |||
⚫ | |||
⚫ | |||
⚫ | |||
⚫ | |||
⚫ | |||
⚫ | |||
⚫ | |||
⚫ | |||
⚫ | |||
if ( this.userInGroup( 'bot' ) ) { |
if ( this.userInGroup( 'bot' ) ) { |
||
Ligne 445 : | Ligne 466 : | ||
content = content.replace( |
content = content.replace( |
||
oldCatRegex, |
oldCatRegex, |
||
'$1[[' + |
'$1[[' + this.newPageName + '$6]]' |
||
); |
); |
||
} |
} |
||
Ligne 459 : | Ligne 480 : | ||
setTimeout( doEdit, dialog.noSpammingDelay ); |
setTimeout( doEdit, dialog.noSpammingDelay ); |
||
} ) |
} ) |
||
.fail( function ( |
.fail( function ( code, data ) { |
||
console.log( |
console.log( code ); |
||
console.log( data ); |
console.log( data ); |
||
if ( |
if ( code === 'protectedpage' ) { |
||
dialog.logFailedPages( member, 'La page est protégée en écriture.' ); |
dialog.logFailedPages( member, 'La page est protégée en écriture.' ); |
||
doEdit(); |
doEdit(); |
||
} |
} |
||
else { |
else { |
||
dialog.errorHandler( |
dialog.errorHandler( code ); |
||
} |
} |
||
} ); |
} ); |
||
Ligne 493 : | Ligne 514 : | ||
'format': 'json', |
'format': 'json', |
||
'from': mw.config.get( 'wgPageName' ), |
'from': mw.config.get( 'wgPageName' ), |
||
'to': |
'to': this.newPageName, |
||
'reason': this. |
'reason': this.reason, |
||
'tags': TAG, |
'tags': TAG, |
||
'formatversion': '2' |
'formatversion': '2' |
||
Ligne 518 : | Ligne 539 : | ||
} ).fail( function( error ) { |
} ).fail( function( error ) { |
||
if ( error === 'articleexists' ) { |
if ( error === 'articleexists' ) { |
||
dialog.errorHandler( 'Impossible de déplacer la catégorie, la page de destination « $1 » existe déjà.'.replace( '$1', dialog. |
dialog.errorHandler( 'Impossible de déplacer la catégorie, la page de destination « $1 » existe déjà.'.replace( '$1', dialog.newPageName ) ); |
||
} |
} |
||
else { |
else { |
||
Ligne 543 : | Ligne 564 : | ||
var content = '\n{{Déplacement catégorie' |
var content = '\n{{Déplacement catégorie' |
||
+ '|ancienne=' + mw.config.get( 'wgPageName' ) |
+ '|ancienne=' + mw.config.get( 'wgPageName' ) |
||
+ '|nouvelle= |
+ '|nouvelle=' + this.newPageName |
||
+ '|raison=' + this. |
+ '|raison=' + this.reason |
||
+ '}}'; |
+ '}}'; |
||
Ligne 599 : | Ligne 620 : | ||
setTimeout( function() { |
setTimeout( function() { |
||
window.location = mw.util.getUrl( |
window.location = mw.util.getUrl( dialog.newPageName ); |
||
}, 1000 ); |
}, 1000 ); |
||
}; |
}; |
||
Ligne 656 : | Ligne 677 : | ||
*/ |
*/ |
||
CatRename.prototype.errorHandler = function ( error, recoverable, warning ) { |
CatRename.prototype.errorHandler = function ( error, recoverable, warning ) { |
||
var errorMessage = new OO.ui.Error( error, { recoverable: recoverable || true, warning: warning || false } ); |
|||
warning = warning || false; |
|||
this.unlockMultitabs(); |
this.unlockMultitabs(); |
||
Ligne 663 : | Ligne 683 : | ||
this.$body.append( this.configContent.$element ); |
this.$body.append( this.configContent.$element ); |
||
this.deferred.reject( |
this.deferred.reject( errorMessage ); |
||
}; |
}; |
||
Version du 22 mars 2018 à 20:59
//TODO: Use i18n messages
//TODO: document attributes
//TODO: remove useless console.log
mw.loader.using( [ 'oojs-ui', 'mediawiki.util', 'mediawiki.api', 'mediawiki.api.edit', 'mediawiki.api.category' ], function() {
( function ( mw, $, OO ) {
const TAG = 'RenommageCategorie';
const DAILY_LIMIT = 250;
const RBOT_PAGE = 'Wikipédia:Bot/Requêtes/Catégories';
/**
* Main class of the gadget CatRename, which is displayed as a ProcessDialog
*
* @class
* @extends OO.ui.ProcessDialog
*
* @constructor
*/
var CatRename = function() {
var config = {
size: 'medium'
};
CatRename.parent.call( this, config );
this.api = new mw.Api( {
timeout: 7000
} );
this.configContent = new OO.ui.PanelLayout( { padded: true, expanded: false } );
this.statusContent = new OO.ui.PanelLayout( { padded: true, expanded: false } );
};
/* Setup */
OO.inheritClass( CatRename, OO.ui.ProcessDialog );
/* Static Properties */
CatRename.static.name = 'catrename';
CatRename.static.title = 'Renommer une catégorie';
CatRename.static.actions = [
{ action: 'rename', label: 'Renommer', flags: [ 'primary', 'progressive' ] },
{ action: 'cancel', label: 'Annuler', flags: [ 'safe', 'back' ] },
{ action: 'rbot', label: '... ou faire faire la tâche à un bot', flags: 'other' }
];
/* ProcessDialog-related Methods */
/**
* Build the interface displayed inside the ProcessDialog box
*/
CatRename.prototype.initialize = function () {
CatRename.parent.prototype.initialize.apply( this, arguments );
this.newNameInput = new OO.ui.TextInputWidget();
this.reasonInput = new OO.ui.TextInputWidget( {
maxLength: 1000
} );
this.optionCheckboxes = new OO.ui.CheckboxMultiselectInputWidget( {
value: [ 'movetalk', 'leave-redirect' ],
options: [
{ data: 'movetalk', label: 'Renommer aussi la page de discussion associée' },
{ data: 'leave-redirect', label: 'Laisser une redirection vers le nouveau titre', disabled: ! this.userInGroup( 'sysop' ) },
{ data: 'watch', label: 'Suivre les catégories originale et nouvelle' },
{ data: 'watch-members', label: 'Suivre les pages modifiées' }
]
} );
this.layout = new OO.ui.Widget( {
content: [
new OO.ui.FieldLayout(
this.newNameInput, {
align: 'top',
label: 'Nouveau titre :',
help: 'Nom de la catégorie après renommage, sans le préfixe "Catégorie:".'
}
),
new OO.ui.FieldLayout(
this.reasonInput, {
align: 'top',
label: 'Motif :',
}
),
new OO.ui.FieldLayout(
this.optionCheckboxes, {}
)
],
} );
this.configContent.$element.append( this.layout.$element );
this.$body.append( this.configContent.$element );
this.statusIndicator = $( '<h3>' )
.css( 'text-align', 'center' )
.css( 'margin-top', '1em' )
.css( 'margin-bottom', '2em' );
this.pagesInError = $( '<ul>' );
this.statusContent.$element.append( this.statusIndicator ).append( this.pagesInError );
this.setSize( this.size );
this.updateSize();
};
/**
* Get a process for taking action.
*
* This method is called within the ProcessDialog when the user clicks
* on an action button (the one defined in CatRename.static.actions).
* Here is defined in which order each method of the category moving
* process is called.
* @param {string} action Name of the action button clicked
* @return {OO.ui.Process} Action process
*/
CatRename.prototype.getActionProcess = function ( action ) {
if ( action === 'rename' ) {
return new OO.ui.Process()
.next( this.prepare, this )
.next( this.checkCategory, this )
.next( this.getMembers, this )
.next( this.lockMultitabs, this )
.next( this.checkLimits, this )
.next( this.editMembers, this )
.next( this.renameCategory, this )
.next( this.unlockMultitabs, this )
.next( this.success, this )
.next( this.close, this );
}
else if ( action === 'rbot' ) {
return new OO.ui.Process()
.next( this.prepare, this )
.next( this.checkCategory, this )
.next( this.getMembers, this )
.next( this.postRBot, this )
.next( this.renameCategory, this )
.next( this.unlockMultitabs, this )
.next( this.success, this )
.next( this.close, this );
}
else if ( action === 'cancel' ) {
return new OO.ui.Process()
.next( this.unlockMultitabs, this )
.next( this.close, this );
}
return CatRename.parent.prototype.getActionProcess.call( this, action );
};
/**
* Get the height of the window body.
* Used by the ProcessDialog to set an accurate height to the dialog.
*
* @return {number} Height in px the dialog should be.
*/
CatRename.prototype.getBodyHeight = function () {
return this.configContent.$element.outerHeight( true );
};
/* Process step methods */
/**
* Fetch and validate user's input to make it easily accessible later.
*
* @return {undefined|OO.ui.Error} Error message for the ProcessDialog
* to display, if any.
*/
CatRename.prototype.prepare = function() {
this.oldTitle = mw.config.get( 'wgTitle' );
this.newTitle = this.newNameInput.getValue().trim().replace(/^([Cc]atégorie|[Cc]ategory):/, '');
this.oldPageName = mw.config.get('wgFormattedNamespaces')[ 14 ] + ':' + this.oldTitle;
this.newPageName = mw.config.get('wgFormattedNamespaces')[ 14 ] + ':' + this.newdTitle;
this.reason = this.reasonInput.getValue().trim();
if ( mw.Title.makeTitle( 14, this.newName ) === null ) {
return new OO.ui.Error( 'Le titre de la catégorie demandée est non valide, vide, ou mal formé.' );
}
if ( this.reason === '' ) {
return new OO.ui.Error( 'Veuillez indiquer une explication pour ce renommage.' );
}
return;
};
/**
* Check if it is technically possible to move the category.
*
* Two main checks are performed:
* * Has the user the right to move the category according to the
* protection level?
* * Is the target title free?
* @return {JQuery.Deferred} Promise telling to continue the process if
* successfull or stopping the process if rejected
*/
CatRename.prototype.checkCategory = function() {
var dialog = this;
this.deferred = $.Deferred();
this.showStatus( 'Vérification de la catégorie cible' );
console.log( '---> Vérification de la catégorie' );
var restrictionMove = mw.config.get( 'wgRestrictionMove' );
for ( var i=0; i < restrictionMove.length; i++ ) {
if ( ! this.userInGroup( restrictionMove[ i ] ) ) {
this.errorHandler( 'Cette catégorie est protégée, vous n\'êtes pas autorisé à la renommer.' );
return this.deferred;
}
}
this.api.get( {
'action': 'query',
'format': 'json',
'formatversion': 2,
'prop': 'categoryinfo',
'titles': this.newPageName
} ).then( function( data ) {
console.log( data );
if ( data.query.pages[ 0 ].missing !== true ) {
//TODO: Allow user to move pages without renaming the cat
dialog.errorHandler( 'Il existe déjà une catégorie avec ce nom...' );
return;
}
dialog.deferred.resolve();
} ).fail( function( error ) {
dialog.errorHandler( error );
} );
return this.deferred;
};
/**
* Get all pages, files and sub-categories in the source category.
*
* This method populates the attribute 'members'.
* @return {JQuery.Deferred} Promise telling to continue the process if
* successfull or stopping the process if rejected
*/
CatRename.prototype.getMembers = function() {
var dialog = this;
this.deferred = $.Deferred();
this.members = [];
this.showStatus( 'Récupération des pages membres de la catégorie' );
console.log( '---> Récupération des pages de la catégorie actuelle' );
function doGetMembers( cmcontinue ) {
cmcontinue = cmcontinue || '';
dialog.api.get( {
'action': 'query',
'format': 'json',
'list': 'categorymembers',
'formatversion': '2',
'cmtitle': mw.config.get( 'wgPageName' ),
'cmprop': 'title',
'cmlimit': 'max',
'cmcontinue': cmcontinue,
} ).then( function( data ) {
console.log( data );
var categoryMembers = data.query.categorymembers;
for ( var i=0; i < categoryMembers.length; i++ ) {
dialog.members.push( categoryMembers[ i ].title );
}
if ( data.continue !== undefined ) {
doGetMembers( data.continue.cmcontinue );
}
else {
dialog.deferred.resolve();
}
} ).fail( function( error ) {
dialog.errorHandler( error );
} );
}
doGetMembers();
return this.deferred;
};
/**
* Lock the process while other instances of CatRename are running.
*
* This method acts a bit like the POSIX sem_wait
* @return {JQuery.Deferred} Promise telling to continue the process
* when it is its turn to execute.
*/
CatRename.prototype.lockMultitabs = function() {
var dialog = this;
this.deferred = $.Deferred();
if ( this.userInGroup( 'bot' ) ) {
return;
}
this.lockID = 'catrename-' + Math.random().toString(36).substring(7);
this.nextTab = null;
this.showStatus( 'En attente de la fin de renommage dans d\'autres onglets' );
console.log( '---> En attente de la fin de renommage d\'autres onglets' );
//TODO: check lock timestamp
if ( localStorage.getItem( 'catrename-lock' ) === null ) {
console.log( 'lock-initial' );
console.log( this.lockID );
localStorage.setItem( 'catrename-lock', this.lockID );
this.deferred.resolve();
}
else {
$( window ).on( 'storage.catrename.catrename-waiting', function( event ) {
console.log( 'storage event 1' );
console.log(event);
if ( event.originalEvent.key === 'catrename-lock' && event.originalEvent.newValue === dialog.lockID ) {
console.log( 'got the lock' );
$( window ).off( 'storage.catrename-waiting' );
dialog.deferred.resolve();
}
} );
localStorage.setItem( 'catrename-addtab', this.lockID );
}
$( window ).on( 'storage.catrename', function( event ) {
console.log( 'storage event 2' );
console.log(event.originalEvent);
// if this tab has no successor and a new one appears, add it as our successor
if ( dialog.nextTab === null && event.originalEvent.key === 'catrename-addtab' && event.originalEvent.newValue !== null ) {
console.log( 'addtab' );
dialog.nextTab = event.originalEvent.newValue;
localStorage.setItem( dialog.lockID, dialog.nextTab );
}
// if our successor decides to leave, remove it and take its successor
else if ( dialog.nextTab !== null && event.originalEvent.key === 'catrename-removetab' && event.originalEvent.newValue === dialog.nextTab ) {
console.log( 'removetab' );
dialog.nextTab = localStorage.getItem( dialog.nextTab );
if ( dialog.nextTab !== null ) {
localStorage.setItem( dialog.lockID, dialog.nextTab );
}
else {
localStorage.removeItem( dialog.lockID );
}
}
} );
window.addEventListener( 'unload', function (e) {
dialog.unlockMultitabs();
} );
return this.deferred;
};
/**
* Check if the daily limit of edits using this script would be reached
* if the move is performed.
*
* In fact, we are not looking realy on a daily basis, but a 24h rolling
* period.
* @return {JQuery.Deferred} Promise telling to continue the process
* when it is its turn to execute.
*/
CatRename.prototype.checkLimits = function() {
var dialog = this;
this.deferred = $.Deferred();
var yesterday = new Date();
yesterday.setDate( yesterday.getDate() - 1 );
if ( this.userInGroup( 'bot' ) ) {
this.noSpammingDelay = 0;
return;
}
this.noSpammingDelay = 5000;
if ( this.members.length > 50 ) {
this.noSpammingDelay = 20000;
}
else if ( this.members.length > 10 ) {
this.noSpammingDelay = 10000;
}
this.showStatus( 'Vérification de la limite journalière' );
console.log( '---> Checking daily limit' );
this.api.get( {
'action': 'query',
'format': 'json',
'list': 'usercontribs',
'formatversion': '2',
'uclimit': 'max', // only query DAILY_LIMIT results ?
'ucend': yesterday.toISOString(),
'ucuser': mw.config.get( 'wgUserName' ),
'ucprop': 'timestamp',
'uctag': TAG
} ).then( function( data ) {
console.log( data );
if ( data.query.usercontribs.length + dialog.members.length >= DAILY_LIMIT ) {
dialog.errorHandler( 'Le renommage de cette catégorie vous ferait faire plus de $1 modifications avec ce script en moins de 24h. Vous pouvez cependant faire une requête aux bots via le bouton en bas à gauche.'.replace( '$1', DAILY_LIMIT ), false );
}
else {
dialog.deferred.resolve();
}
} ).fail( function( error ) {
dialog.errorHandler( error );
} );
return this.deferred;
};
/**
* Try to move all the pages inside the 'members' attribute from the old
* to the new category name by fetching and editing their wikicode.
*
* @return {JQuery.Deferred} Promise telling to continue the process
* when it is its turn to execute.
*/
CatRename.prototype.editMembers = function() {
var dialog = this,
totalPages = this.members.length,
oldCatRegex = this.buildRegex( this.oldTitle ),
newCatRegex = buildRegex( this.newTitle ),
summary = 'Remplacement de la catégorie [[Catégorie:$1]] par [[Catégorie:$2]] : $3'
.replace( '$1', this.oldTitle )
.replace( '$2', this.newTitle )
.replace( '$3', this.reason ),
commonPayload = {
summary: summary,
minor: true,
tags: TAG
};
this.deferred = $.Deferred();
console.log( '---> Édition des membres de la catégorie' );
if ( this.userInGroup( 'bot' ) ) {
commonPayload[ 'bot' ] = 1;
}
if ( this.optionCheckboxes.getValue().indexOf( 'watch-members' ) > -1 ) {
commonPayload[ 'watchlist' ] = 'watch';
}
function doEdit() {
var member = dialog.members.pop();
if ( member === undefined ) {
dialog.deferred.resolve();
return;
}
//TODO: a progress-bar ?
dialog.showStatus( 'Édition de la page $1 sur $2'.replace( '$1', totalPages - dialog.members.length ).replace( '$2', totalPages ) );
dialog.api.edit( member, function ( revision ) {
var content = revision.content,
newCatInPageList = content.match( newCatRegex );
if ( newCatInPageList !== null ) {
dialog.logFailedPages( member, 'La page contient déjà la nouvelle catégorie.' );
}
else {
content = content.replace(
oldCatRegex,
'$1[[' + this.newPageName + '$6]]'
);
}
return $.extend( { text: content }, commonPayload );
} )
.then( function ( result ) {
console.log( result );
if ( result.nochange === true ) {
dialog.logFailedPages( member, 'La catégorie n\'a pas été trouvée dans le code de la page, peut-être est-elle incluse via un modèle ?' );
}
setTimeout( doEdit, dialog.noSpammingDelay );
} )
.fail( function ( code, data ) {
console.log( code );
console.log( data );
if ( code === 'protectedpage' ) {
dialog.logFailedPages( member, 'La page est protégée en écriture.' );
doEdit();
}
else {
dialog.errorHandler( code );
}
} );
}
doEdit();
return this.deferred;
};
/**
* Move the category itself.
*
* @return {JQuery.Deferred} Promise telling to continue the process
* when it is its turn to execute.
*/
CatRename.prototype.renameCategory = function() {
var dialog = this;
this.deferred = $.Deferred();
this.showStatus( 'Renommage de la catégorie' );
console.log( '---> Déplacement de la catégorie' );
var payload = {
'action': 'move',
'format': 'json',
'from': mw.config.get( 'wgPageName' ),
'to': this.newPageName,
'reason': this.reason,
'tags': TAG,
'formatversion': '2'
};
var options = this.optionCheckboxes.getValue();
if ( options.indexOf( 'movetalk' ) > -1 ) {
payload[ 'movetalk' ] = 1;
}
if ( options.indexOf( 'leave-redirect' ) === -1 ) {
payload[ 'noredirect' ] = 1;
}
if ( options.indexOf( 'watch' ) > -1 ) {
payload[ 'watchlist' ] = 'watch';
}
this.api.postWithToken( 'csrf', payload ).then( function( data ) {
console.log( data );
dialog.deferred.resolve();
} ).then( function( data ) {
console.log( data );
dialog.deferred.resolve();
} ).fail( function( error ) {
if ( error === 'articleexists' ) {
dialog.errorHandler( 'Impossible de déplacer la catégorie, la page de destination « $1 » existe déjà.'.replace( '$1', dialog.newPageName ) );
}
else {
dialog.errorHandler( error );
}
} );
return this.deferred;
};
/**
* Post a move request for the bots.
*
* @return {JQuery.Deferred} Promise telling to continue the process
* when it is its turn to execute.
*/
CatRename.prototype.postRBot = function() {
var dialog = this;
this.deferred = $.Deferred();
this.showStatus( 'Dépôt de la requête aux bots' );
console.log( '---> Dépot d\'un message sur RBOT' );
var content = '\n{{Déplacement catégorie'
+ '|ancienne=' + mw.config.get( 'wgPageName' )
+ '|nouvelle=' + this.newPageName
+ '|raison=' + this.reason
+ '}}';
this.api.postWithToken( 'csrf', {
'action': 'edit',
'format': 'json',
'title': RBOT_PAGE,
'summary': 'RBOT: Demande de renommage de catégorie',
'tags': TAG,
'nocreate': 1,
'appendtext': content,
'formatversion': '2'
} ).then( function( data ) {
console.log( data );
dialog.deferred.resolve();
} ).fail( function( error ) {
dialog.errorHandler( error );
} );
return this.deferred;
};
/**
* Release the lock to allow other instances of CatRename to execute.
*
* This method acts a bit like the POSIX sem_post.
*/
CatRename.prototype.unlockMultitabs = function() {
if ( this.lockID !== undefined ) {
$( window ).off( 'storage.catrename' );
localStorage.setItem( 'catrename-removetab', this.lockID ); //Inform other tabs that we're closing
localStorage.removeItem( this.lockID ); //Clean up our mess from the localStorage
// wake up the next tab, or reset if there is none
if ( localStorage.getItem( 'catrename-lock' ) === this.lockID ) {
if ( this.nextTab !== null ) {
localStorage.setItem( 'catrename-lock', this.nextTab );
}
else {
localStorage.removeItem( 'catrename-lock' );
}
}
delete this.lockID;
}
};
/**
* Method called when all has gone well (yeah !).
*/
CatRename.prototype.success = function() {
var dialog = this;
setTimeout( function() {
window.location = mw.util.getUrl( dialog.newPageName );
}, 1000 );
};
/* Instanciate CatRename and add it to MediaWiki's UI */
$( function() {
if ( mw.config.get( 'wgNamespaceNumber' ) === 14 ) {
var windowManager = new OO.ui.WindowManager();
$( 'body' ).append( windowManager.$element );
var catRename = new CatRename();
windowManager.addWindows( [ catRename ] );
var portlet = mw.util.addPortletLink( 'p-cactions', '#', 'CatRename' );
$( portlet ).on( 'click', function ( e ) {
windowManager.openWindow( catRename );
e.preventDefault();
} );
window.catRename = catRename;
}
} );
/* Helper Methods */
/**
* Get information about the current user's groups
*
* @param {string} groupName Name of the group to check
* @return {boolean} Whether the current user is in the given group
*/
CatRename.prototype.userInGroup = function( groupName ) {
return ( mw.config.get( 'wgUserGroups' ).indexOf( groupName ) > -1 );
};
/**
* Display a status message inside the main content of the dialog.
*
* @return {string} Status message to display.
*/
CatRename.prototype.showStatus = function ( status ) {
this.statusIndicator.text( status );
this.$body.children().detach();
this.$body.append( this.statusContent.$element );
};
/**
* Raise an error using OO.ui.Error, and reset all what should be.
*
* @param {string} error Error message to display to the user.
* @param {boolean} recoverable Is the error recoverable (default to true).
* @param {boolean} warning Should we raise a warning instead an error (default to false).
*/
CatRename.prototype.errorHandler = function ( error, recoverable, warning ) {
var errorMessage = new OO.ui.Error( error, { recoverable: recoverable || true, warning: warning || false } );
this.unlockMultitabs();
this.$body.children().detach();
this.$body.append( this.configContent.$element );
this.deferred.reject( errorMessage );
};
/**
* Add a page to the error log
*
* @param {string} pageName Name (including namespace) of the page.
* @param {string} reason Explaination of the error.
*/
CatRename.prototype.logFailedPages = function ( pageName, reason ) {
var li = $( '<li>' ).text( ' - ' + reason ),
a = $( '<a>' ).attr( 'href', mw.util.getUrl( pageName ) ).text( pageName );
this.pagesInError.append( li.prepend( a ) );
};
/**
* Build a regex to extract the link to a given category from wikicode.
*
* @param {string} category Name (without namespace) of the category.
* @return {RegExp} Regex object to extract the given category.
*/
CatRename.prototype.buildRegex = function( category ) {
var formattedNamespace = mw.config.get( 'wgFormattedNamespaces' )[ 14 ],
isFirstLetterCaseSensitive = ( mw.config.get( 'wgCaseSensitiveNamespaces' ).indexOf( 14 ) > -1 ),
namespace = '(?:[' + formattedNamespace.charAt( 0 ) + formattedNamespace.charAt( 0 ).toLowerCase() + ']' + formattedNamespace.slice( 1 ) + '|[Cc]ategory)';
category = category.replace( /([\\\^\$\*\+\?\.\|\{\}\[\]\(\)])/g, '\\$1' );
if ( ! isFirstLetterCaseSensitive ) {
var firstLetter = category.charAt(0);
if ( firstLetter.toUpperCase() !== firstLetter.toLowerCase() ) {
category = '[' + firstLetter.toUpperCase() + firstLetter.toLowerCase() + ']'
+ category.slice(1);
}
}
return new RegExp('(\\s*)\\[\\[( |_)*' + namespace + '( |_)*:( |_)*' + category + '( |_)*(\\|[^\\]]*)?\\]\\]', 'g');
}
}( mediaWiki, jQuery, OO ) );
} );