MediaWiki:Gadget-twinklebatchdelete.js: Difference between revisions
m (1 revision imported) |
(Localise) |
||
(4 intermediate revisions by 2 users not shown) | |||
Line 10: | Line 10: | ||
**************************************** | **************************************** | ||
* Mode of invocation: Tab ("D-batch") | * Mode of invocation: Tab ("D-batch") | ||
* Active on: Existing | * Active on: Existing non-articles, and Special:PrefixIndex | ||
* Config directives in: TwinkleConfig | * Config directives in: TwinkleConfig | ||
*/ | */ | ||
Twinkle.batchdelete = function twinklebatchdelete() { | Twinkle.batchdelete = function twinklebatchdelete() { | ||
if( Morebits.userIsInGroup( 'sysop' ) && (mw.config.get( 'wgNamespaceNumber' ) > 0 || mw.config.get( 'wgCanonicalSpecialPageName' ) === 'Prefixindex') ) { | if( | ||
Morebits.userIsInGroup( 'sysop' ) && ( | |||
( mw.config.get( 'wgCurRevisionId' ) && mw.config.get( 'wgNamespaceNumber' ) > 0 ) || | |||
mw.config.get( 'wgCanonicalSpecialPageName' ) === 'Prefixindex' | |||
) | |||
) { | |||
Twinkle.addPortletLink( Twinkle.batchdelete.callback, "D-batch", "tw-batch", "Delete pages found in this category/on this page" ); | Twinkle.addPortletLink( Twinkle.batchdelete.callback, "D-batch", "tw-batch", "Delete pages found in this category/on this page" ); | ||
} | } | ||
Line 26: | Line 30: | ||
Window.setTitle( "Batch deletion" ); | Window.setTitle( "Batch deletion" ); | ||
Window.setScriptName( "Twinkle" ); | Window.setScriptName( "Twinkle" ); | ||
Window.addFooterLink( "Twinkle help", " | Window.addFooterLink( "Twinkle help", "SV:TW/DOC#batchdelete" ); | ||
var form = new Morebits.quickForm( Twinkle.batchdelete.callback.evaluate ); | var form = new Morebits.quickForm( Twinkle.batchdelete.callback.evaluate ); | ||
Line 36: | Line 40: | ||
name: 'delete_page', | name: 'delete_page', | ||
value: 'delete', | value: 'delete', | ||
checked: true | checked: true, | ||
subgroup: { | |||
type: 'checkbox', | |||
list: [ | |||
{ | |||
label: 'Delete associated talk pages (except user talk pages)', | |||
name: 'delete_talk', | |||
value: 'delete_talk', | |||
checked: true | |||
}, | |||
{ | |||
label: 'Delete redirects to deleted pages', | |||
name: 'delete_redirects', | |||
value: 'delete_redirects', | |||
checked: true | |||
} | |||
] | |||
} | |||
}, | }, | ||
{ | { | ||
label: ' | label: 'Unlink backlinks to each page (in Main and Portal namespaces only)', | ||
name: 'unlink_page', | name: 'unlink_page', | ||
value: 'unlink', | value: 'unlink', | ||
checked: | checked: false | ||
}, | }, | ||
{ | { | ||
label: ' | label: 'Remove usages of each file (in all namespaces)', | ||
name: ' | name: 'unlink_file', | ||
value: ' | value: 'unlink_file', | ||
checked: true | checked: true | ||
} | } | ||
Line 59: | Line 80: | ||
} ); | } ); | ||
var query; | var query = { | ||
'action': 'query', | |||
'prop': 'revisions|info|imageinfo', | |||
'inprop': 'protection', | |||
'rvprop': 'size|user' | |||
}; | |||
if( mw.config.get( 'wgNamespaceNumber' ) === 14 ) { // Category: | if( mw.config.get( 'wgNamespaceNumber' ) === 14 ) { // Category: | ||
query.generator = 'categorymembers'; | |||
query = | query.gcmtitle = mw.config.get('wgPageName'); | ||
query.gcmlimit = Twinkle.getPref('batchMax'); // the max for sysops | |||
} else if( mw.config.get( 'wgCanonicalSpecialPageName' ) === 'Prefixindex' ) { | } else if( mw.config.get( 'wgCanonicalSpecialPageName' ) === 'Prefixindex' ) { | ||
query.generator = 'allpages'; | |||
query.gaplimit = Twinkle.getPref('batchMax'); // the max for sysops | |||
if(Morebits.queryString.exists( 'prefix' ) ) | if(Morebits.queryString.exists( 'prefix' ) ) | ||
{ | { | ||
gapnamespace = Morebits.queryString.get( 'namespace' ); | query.gapnamespace = Morebits.queryString.get( 'namespace' ); | ||
gapprefix = Morebits.string.toUpperCaseFirstChar( Morebits.queryString.get( 'prefix' ) ); | query.gapprefix = Morebits.string.toUpperCaseFirstChar( Morebits.queryString.get( 'prefix' ) ); | ||
} | } | ||
else | else | ||
Line 85: | Line 106: | ||
} | } | ||
var titleSplit = pathSplit[3].split(':'); | var titleSplit = pathSplit[3].split(':'); | ||
gapnamespace = mw.config.get("wgNamespaceIds")[titleSplit[0].toLowerCase()]; | query.gapnamespace = mw.config.get("wgNamespaceIds")[titleSplit[0].toLowerCase()]; | ||
if ( titleSplit.length < 2 || typeof gapnamespace === 'undefined' ) | if ( titleSplit.length < 2 || typeof query.gapnamespace === 'undefined' ) | ||
{ | { | ||
gapnamespace = 0; // article namespace | query.gapnamespace = 0; // article namespace | ||
gapprefix = pathSplit.splice(3).join('/'); | query.gapprefix = pathSplit.splice(3).join('/'); | ||
} | } | ||
else | else | ||
Line 95: | Line 116: | ||
pathSplit = pathSplit.splice(4); | pathSplit = pathSplit.splice(4); | ||
pathSplit.splice(0,0,titleSplit.splice(1).join(':')); | pathSplit.splice(0,0,titleSplit.splice(1).join(':')); | ||
gapprefix = pathSplit.join('/'); | query.gapprefix = pathSplit.join('/'); | ||
} | } | ||
} | } | ||
} else { | } else { | ||
query = | query.generator = 'links'; | ||
query.titles = mw.config.get('wgPageName'); | |||
query.gpllimit = Twinkle.getPref('batchMax'); // the max for sysops | |||
} | } | ||
Line 130: | Line 134: | ||
var wikipedia_api = new Morebits.wiki.api( 'loading...', query, function( apiobj ) { | var wikipedia_api = new Morebits.wiki.api( 'loading...', query, function( apiobj ) { | ||
var xml = apiobj.responseXML; | var xml = apiobj.responseXML; | ||
var $pages = $(xml).find('page').filter(':not([missing])'); | var $pages = $(xml).find('page').filter(':not([missing])'); // :not([imagerepository="shared"]) | ||
var list = []; | var list = []; | ||
$pages.each(function(index, page) { | $pages.each(function(index, page) { | ||
var $page = $(page); | var $page = $(page); | ||
var ns = $page.attr('ns'); | |||
var title = $page.attr('title'); | var title = $page.attr('title'); | ||
var isRedir = $page.attr('redirect') === ""; | var isRedir = $page.attr('redirect') === ""; | ||
var $editprot = $page.find('pr[type="edit"][level="sysop"]'); | var $editprot = $page.find('pr[type="edit"][level="sysop"]'); | ||
var | var isProtected = $editprot.length > 0; | ||
var size = $page.find('rev').attr('size'); | var size = $page.find('rev').attr('size'); | ||
Line 144: | Line 149: | ||
metadata.push("redirect"); | metadata.push("redirect"); | ||
} | } | ||
if ( | if (isProtected) { | ||
metadata.push("fully protected" + | metadata.push("fully protected" + | ||
($editprot.attr('expiry') === 'infinity' ? ' indefinitely' : (', expires ' + $editprot.attr('expiry')))); | ($editprot.attr('expiry') === 'infinity' ? ' indefinitely' : (', expires ' + $editprot.attr('expiry')))); | ||
} | } | ||
metadata.push(size + " bytes"); | if (ns === "6") { // mimic what delimages used to show for files | ||
metadata.push("uploader: " + $page.find('ii').attr('user')); | |||
metadata.push("last edit from: " + $page.find('rev').attr('user')); | |||
} else { | |||
metadata.push(size + " bytes"); | |||
} | |||
list.push({ | list.push({ | ||
label: title + (metadata.length ? (' (' + metadata.join('; ') + ')') : ''), | label: title + (metadata.length ? (' (' + metadata.join('; ') + ')') : ''), | ||
value: title, | value: title, | ||
checked: true, | checked: true, | ||
style: ( | style: (isProtected ? 'color:red' : '') | ||
}); | }); | ||
}); | }); | ||
Line 189: | Line 199: | ||
}; | }; | ||
Twinkle.batchdelete.callback.evaluate = function twinklebatchdeleteCallbackEvaluate(event) { | Twinkle.batchdelete.callback.evaluate = function twinklebatchdeleteCallbackEvaluate(event) { | ||
Morebits.wiki.actionCompleted.notice = 'Status'; | Morebits.wiki.actionCompleted.notice = 'Status'; | ||
Line 206: | Line 213: | ||
var reason = event.target.reason.value; | var reason = event.target.reason.value; | ||
var delete_page = event.target.delete_page.checked; | var delete_page = event.target.delete_page.checked; | ||
var delete_talk = event.target.delete_talk && event.target.delete_talk.checked; | |||
var delete_redirects = event.target.delete_redirects && event.target.delete_redirects.checked; | |||
var unlink_page = event.target.unlink_page.checked; | var unlink_page = event.target.unlink_page.checked; | ||
var | var unlink_file = event.target.unlink_file.checked; | ||
if( ! reason ) { | if( ! reason ) { | ||
alert("You need to give a reason, you cabal crony!"); | alert("You need to give a reason, you cabal crony!"); | ||
Line 219: | Line 228: | ||
} | } | ||
var pageDeleter = new Morebits.batchOperation(delete_page ? "Deleting pages" : "Initiating requested tasks"); | |||
pageDeleter.setOption("chunkSize", Twinkle.getPref('batchdeleteChunks')); | |||
// we only need the initial status lines if we're deleting the pages in the pages array | |||
pageDeleter.setOption("preserveIndividualStatusLines", delete_page); | |||
pageDeleter.setPageList(pages); | |||
pageDeleter.run(function(pageName) { | |||
var params = { | |||
page: pageName, | |||
delete_page: delete_page, | |||
delete_talk: delete_talk, | |||
delete_redirects: delete_redirects, | |||
unlink_page: unlink_page, | |||
unlink_file: unlink_file && /^(File|Image)\:/i.test(pageName), | |||
reason: reason, | |||
pageDeleter: pageDeleter | |||
}; | |||
var wikipedia_page = new Morebits.wiki.page( pageName, 'Deleting page ' + pageName ); | |||
wikipedia_page.setCallbackParameters(params); | |||
if( delete_page ) { | |||
wikipedia_page.setEditSummary(reason + Twinkle.getPref('deletionSummaryAd')); | |||
wikipedia_page.suppressProtectWarning(); | |||
wikipedia_page.deletePage(Twinkle.batchdelete.callbacks.doExtras, pageDeleter.workerFailure); | |||
} else { | |||
Twinkle.batchdelete.callbacks.doExtras(wikipedia_page); | |||
} | } | ||
} | }); | ||
}; | }; | ||
Twinkle.batchdelete.callbacks = { | Twinkle.batchdelete.callbacks = { | ||
// this stupid parameter name is a temporary thing until I implement an overhaul | |||
var | // of Morebits.wiki.* callback parameters | ||
doExtras: function( thingWithParameters ) { | |||
var params = thingWithParameters.parent ? thingWithParameters.parent.getCallbackParameters() : | |||
thingWithParameters.getCallbackParameters(); | |||
// the initial batch operation's job is to delete the page, and that has | |||
// succeeded by now | |||
params.pageDeleter.workerSuccess(thingWithParameters); | |||
var | var query, wikipedia_api; | ||
if( | if( params.unlink_page ) { | ||
Twinkle.batchdelete.unlinkCache = {}; | |||
query = { | |||
'action': 'query', | |||
'list': 'backlinks', | |||
'blfilterredir': 'nonredirects', | |||
'blnamespace': [0, 100], // main space and portal space only | |||
'bltitle': params.page, | |||
'bllimit': 5000 // 500 is max for normal users, 5000 for bots and sysops | |||
}; | |||
wikipedia_api = new Morebits.wiki.api( 'Grabbing backlinks', query, Twinkle.batchdelete.callbacks.unlinkBacklinksMain ); | |||
wikipedia_api.params = params; | |||
wikipedia_api.post(); | |||
} | } | ||
if( params.unlink_file ) { | |||
query = { | |||
'action': 'query', | |||
'list': 'imageusage', | |||
'iutitle': params.page, | |||
'iulimit': 5000 // 500 is max for normal users, 5000 for bots and sysops | |||
}; | |||
wikipedia_api = new Morebits.wiki.api( 'Grabbing file links', query, Twinkle.batchdelete.callbacks.unlinkImageInstancesMain ); | |||
wikipedia_api.params = params; | |||
wikipedia_api.post(); | |||
} | |||
if( params.delete_page ) { | |||
if ( params.delete_redirects ) { | |||
query = { | |||
'action': 'query', | |||
'titles': params.page, | |||
'prop': 'redirects', | |||
'rdlimit': 5000 // 500 is max for normal users, 5000 for bots and sysops | |||
}; | |||
wikipedia_api = new Morebits.wiki.api( 'Grabbing redirects', query, Twinkle.batchdelete.callbacks.deleteRedirectsMain ); | |||
wikipedia_api.params = params; | |||
wikipedia_api.post(); | |||
} | |||
if ( params.delete_talk ) { | |||
var pageTitle = mw.Title.newFromText(params.page); | |||
if (pageTitle && pageTitle.namespace % 2 === 0 && pageTitle.namespace !== 2) { | |||
pageTitle.namespace++; // now pageTitle is the talk page title! | |||
query = { | |||
'action': 'query', | |||
'titles': pageTitle.toText() | |||
}; | |||
wikipedia_api = new Morebits.wiki.api( 'Checking whether talk page exists', query, Twinkle.batchdelete.callbacks.deleteTalk ); | |||
wikipedia_api.params = params; | |||
wikipedia_api.params.talkPage = pageTitle.toText(); | |||
wikipedia_api.post(); | |||
} | |||
} | } | ||
} | } | ||
}, | |||
deleteRedirectsMain: function( apiobj ) { | |||
var xml = apiobj.responseXML; | |||
var pages = $(xml).find('rd').map(function() { return $(this).attr('title'); }).get(); | |||
if (!pages.length) { | |||
return; | return; | ||
} | } | ||
var | var redirectDeleter = new Morebits.batchOperation("Deleting redirects to " + apiobj.params.page); | ||
redirectDeleter.setOption("chunkSize", Twinkle.getPref('batchdeleteChunks')); | |||
redirectDeleter.setPageList(pages); | |||
redirectDeleter.run(function(pageName) { | |||
var wikipedia_page = new Morebits.wiki.page(pageName, "Deleting " + pageName); | |||
wikipedia_page.setEditSummary('[[SV:CSD#G8|G8]]: Redirect to deleted page "' + apiobj.params.page + '"' + Twinkle.getPref('deletionSummaryAd')); | |||
wikipedia_page.deletePage(redirectDeleter.workerSuccess, redirectDeleter.workerFailure); | |||
}); | |||
var wikipedia_page = new Morebits.wiki.page( | |||
wikipedia_page.setEditSummary('[[ | |||
wikipedia_page. | |||
} | |||
}, | }, | ||
deleteTalk: function( apiobj ) { | |||
var | var xml = apiobj.responseXML; | ||
var | var exists = $(xml).find('page:not([missing])').length > 0; | ||
if( | if( !exists ) { | ||
// no talk page; forget about it | |||
return; | return; | ||
} | } | ||
var | var page = new Morebits.wiki.page(apiobj.params.talkPage, "Deleting talk page of article " + apiobj.params.page); | ||
page.setEditSummary("[[SV:CSD#G8|G8]]: [[Help:Talk page|Talk page]] of deleted page \"" + apiobj.params.page + "\"" + Twinkle.getPref('deletionSummaryAd')); | |||
page.deletePage(); | |||
}, | |||
unlinkBacklinksMain: function( apiobj ) { | |||
var xml = apiobj.responseXML; | |||
var pages = $(xml).find('bl').map(function() { return $(this).attr('title'); }).get(); | |||
if (!pages.length) { | |||
if( | |||
return; | return; | ||
} | } | ||
var unlinker = new Morebits.batchOperation("Unlinking backlinks to " + apiobj.params.page); | |||
unlinker.setOption("chunkSize", Twinkle.getPref('batchdeleteChunks')); | |||
var wikipedia_page = new Morebits.wiki.page( | unlinker.setPageList(pages); | ||
var params = $.extend( {}, | unlinker.run(function(pageName) { | ||
params.title = | var wikipedia_page = new Morebits.wiki.page(pageName, "Unlinking on " + pageName); | ||
params. | var params = $.extend({}, apiobj.params); | ||
params.title = pageName; | |||
params.unlinker = unlinker; | |||
wikipedia_page.setCallbackParameters(params); | wikipedia_page.setCallbackParameters(params); | ||
wikipedia_page.load(Twinkle.batchdelete.callbacks.unlinkBacklinks); | wikipedia_page.load(Twinkle.batchdelete.callbacks.unlinkBacklinks); | ||
} | }); | ||
}, | }, | ||
unlinkBacklinks: function( pageobj ) { | unlinkBacklinks: function( pageobj ) { | ||
Line 385: | Line 376: | ||
if( ! pageobj.exists() ) { | if( ! pageobj.exists() ) { | ||
// we probably just deleted it, as a recursive backlink | // we probably just deleted it, as a recursive backlink | ||
params. | params.unlinker.workerSuccess(pageobj); | ||
return; | return; | ||
} | } | ||
var text; | var text; | ||
if( params.title in Twinkle.batchdelete.unlinkCache ) { | if( params.title in Twinkle.batchdelete.unlinkCache ) { | ||
text = Twinkle.batchdelete.unlinkCache[ params.title ]; | text = Twinkle.batchdelete.unlinkCache[ params.title ]; | ||
Line 404: | Line 394: | ||
if( text === old_text ) { | if( text === old_text ) { | ||
// Nothing to do, return | // Nothing to do, return | ||
params. | params.unlinker.workerSuccess(pageobj); | ||
return; | return; | ||
} | } | ||
Line 411: | Line 400: | ||
pageobj.setPageText(text); | pageobj.setPageText(text); | ||
pageobj.setCreateOption('nocreate'); | pageobj.setCreateOption('nocreate'); | ||
pageobj.save(params. | pageobj.setMaxConflictRetries(10); | ||
pageobj.save(params.unlinker.workerSuccess, params.unlinker.workerFailure); | |||
}, | |||
unlinkImageInstancesMain: function( apiobj ) { | |||
var xml = apiobj.responseXML; | |||
var pages = $(xml).find('iu').map(function() { return $(this).attr('title'); }).get(); | |||
if (!pages.length) { | |||
return; | |||
} | |||
var unlinker = new Morebits.batchOperation("Unlinking backlinks to " + apiobj.params.page); | |||
unlinker.setOption("chunkSize", Twinkle.getPref('batchdeleteChunks')); | |||
unlinker.setPageList(pages); | |||
unlinker.run(function(pageName) { | |||
var wikipedia_page = new Morebits.wiki.page(pageName, "Removing file usages on " + pageName); | |||
var params = $.extend({}, apiobj.params); | |||
params.title = pageName; | |||
params.unlinker = unlinker; | |||
wikipedia_page.setCallbackParameters(params); | |||
wikipedia_page.load(Twinkle.batchdelete.callbacks.unlinkImageInstances); | |||
}); | |||
}, | |||
unlinkImageInstances: function( pageobj ) { | |||
var params = pageobj.getCallbackParameters(); | |||
if( ! pageobj.exists() ) { | |||
// we probably just deleted it, as a recursive backlink | |||
params.unlinker.workerSuccess(pageobj); | |||
return; | |||
} | |||
var image = params.image.replace( /^(?:Image|File):/, '' ); | |||
var text; | |||
if( params.title in Twinkle.batchdelete.unlinkCache ) { | |||
text = Twinkle.batchdelete.unlinkCache[ params.title ]; | |||
} else { | |||
text = pageobj.getPageText(); | |||
} | |||
var old_text = text; | |||
var wikiPage = new Morebits.wikitext.page( text ); | |||
wikiPage.commentOutImage( image , 'Commented out because image was deleted' ); | |||
text = wikiPage.getText(); | |||
Twinkle.batchdelete.unlinkCache[ params.title ] = text; | |||
if( text === old_text ) { | |||
pageobj.getStatusElement().error( 'failed to unlink image ' + image + ' from ' + pageobj.getPageName() ); | |||
params.unlinker.workerFailure(pageobj); | |||
return; | |||
} | |||
pageobj.setEditSummary('Removing instance of file ' + image + " that has been deleted because \"" + params.reason + "\")" + Twinkle.getPref('deletionSummaryAd')); | |||
pageobj.setPageText(text); | |||
pageobj.setCreateOption('nocreate'); | |||
pageobj.setMaxConflictRetries(10); | |||
pageobj.save(params.unlinker.workerSuccess, params.unlinker.workerFailure); | |||
} | } | ||
}; | }; |