User:Fox/twinklecopyvio.js
< User:Fox
Note: After saving, you have to bypass your browser's cache to see the changes. Internet Explorer: press Ctrl-F5, Mozilla: hold down Shift while clicking Reload (or press Ctrl-Shift-R), Opera/Konqueror: press F5, Safari: hold down Shift + Alt while clicking Reload, Chrome: hold down Shift while clicking Reload.
Documentation for this user script can be added at User:Fox/twinklecopyvio. |
- Report page listing warnings and errors.
// If TwinkleConfig aint exist.
if( typeof( TwinkleConfig ) == 'undefined' ) {
TwinkleConfig = function() {};
}
/**
TwinkleConfig.summaryAd (string)commons.wikimedia.org
If ad should be added or not to summary, default [[COMMONS:TWINKLE|TWINKLE]]
*/
if( typeof( TwinkleConfig.summaryAd ) == 'undefined' ) {
TwinkleConfig.summaryAd = " using [[COMMONS:TW|TW]]";
}
/**
TwinkleConfig.deletionSummaryAd (string)
If ad should be added or not to deletion summary, default [[COMMONS:TWINKLE|TWINKLE]]
*/
if( typeof( TwinkleConfig.deletionSummaryAd ) == 'undefined' ) {
TwinkleConfig.deletionSummaryAd = " using [[COMMONS:TW|TW]]";
}
/**
TwinkleConfig.notifyUserOnSpeedyDeletionNomination (array)
What types of actions that should result that the author of the page should be notified of nomination
*/
if( typeof( TwinkleConfig.notifyUserOnSpeedyDeletionNomination ) == 'undefined' ) {
TwinkleConfig.notifyUserOnSpeedyDeletionNomination = [ 'copyvio' ];
}
/**
TwinkleConfig.userTalkPageMode may take arguments:
'window': open a new window, remmenber the opened window
'tab': opens in a new tab, if possible.
'blank': force open in a new window, even if a such window exist
*/
if( typeof( TwinkleConfig.userTalkPageMode ) == 'undefined' ) {
TwinkleConfig.userTalkPageMode = 'window';
}
/**
TwinkleConfig.toolboxButtons (string)
If id defined in this array, the button of the action is located in the toolbox instead of in
the actions bar.
if( typeof( TwinkleConfig.toolboxButtons ) == 'undefined' ) {
TwinkleConfig.toolboxButtons = [];
}
*/
function twinklecopyvio() {
if( wgNamespaceNumber < 0 || wgCurRevisionId == false ) {
return;
}
if( userIsInGroup( 'sysop' ) ) {
mw.util.addPortletLink( 'p-cactions', "javascript:twinklecopyvio.callback()", "copyvio", "tw-copyvio", "Tag as a speedily deletable copyright violation", "");
} else if (twinkleConfigExists) {
mw.util.addPortletLink( 'p-cactions', "javascript:twinklecopyvio.callback()", "copyvio", "tw-copyvio", "Tag as a speedily deletable copyright violation", "");
}
else
{
mw.util.addPortletLink('p-cactions', 'javascript:alert("Your account is too new to use Twinkle.");', 'copyvio', 'tw-copyvio', 'Tag as a speedily deletable copyright violation', '');
}
}
$(twinklecopyvio);
twinklecopyvio.callback = function twinklecopyvioCallback() {
var Window = new SimpleWindow( 800, 400 );
Window.setTitle( "Choose criteria for speedy deletion" );
form.append( {
type: 'checkbox',
list: [
{
label: 'Notify if possible',
value: 'notify',
name: 'notify',
tooltip: 'If a notification if defined in the configuration, then notify if this is true, else no notify',
checked: true,
disabled: userIsInGroup( 'sysop' ),
event: function( event ) {
event.stopPropagation();
}
}
]
}
);
if( wgNamespaceNumber == Namespace.IMAGE ) {
form.append( {type:'header', label:'Images/Media' } );
form.append ( {
type: 'radio',
name: 'csd',
list: [
{
label: 'Blatant copyright infringement',
value: 'copyvio',
tooltip: 'The image was copied from a website or other source that does not have a license compatible with Commons, and the uploader does not assert that it is public domain, freely licensed, fair use, or used with permission. Sources that do not have a license compatible with Commons include stock photo libraries such as Getty Images or Corbis. Non-blatant copyright infringements should be discussed at Wikipedia:Images and media for deletion'
},
]
} );
}
}
]
} ); }
var result = form.render();
Window.setContent( result );
Window.display();
}
twinklecopyvio.normalizeHash = {
'copyvio': 'copyvio',
};
twinklecopyvio.reasonHash = {
'copyvio': 'blantant copyright infringement',
};
twinklecopyvio.callbacks = {
sysop: {
main: function( self ) {
var xmlDoc = self.responseXML;
var normal = xmlDoc.evaluate( '//normalized/n/@to', xmlDoc, null, XPathResult.STRING_TYPE, null ).stringValue;
if( normal ) {
wgPageName = normal;
}
var exists = xmlDoc.evaluate( 'boolean(//pages/page[not(@missing)])', xmlDoc, null, XPathResult.BOOLEAN_TYPE, null ).booleanValue;
if( ! exists ) {
self.statelem.error( "It seems that the page doesn't exists, perhaps it has already been deleted" );
return;
}
var query = {
'title': wgPageName,
'action': 'delete'
};
var wikipedia_wiki = new Wikipedia.wiki( 'Deleting page', query, twinklecopyvio.callbacks.sysop.deletePage );
wikipedia_wiki.params = self.params;
wikipedia_wiki.followRedirect = false;
wikipedia_wiki.get();
if(
TwinkleConfig.deleteTalkPageOnDelete &&
self.params.normalized != 'i8' &&
wgNamespaceNumber % 2 == 0 &&
document.getElementById( 'ca-talk' ).className != 'new'
) {
var talk_page = namespaces[ wgNamespaceNumber + 1 ] + ':' + wgTitle;
var query = query = {
'title': talk_page,
'action': 'delete'
};
var wikipedia_wiki = new Wikipedia.wiki( 'Deleting talk page', query, twinklecopyvio.callbacks.sysop.deleteTalkPage );
wikipedia_wiki.params = self.params;
wikipedia_wiki.followRedirect = false;
wikipedia_wiki.get();
}
if( wgNamespaceNumber == 6 && self.params.normalized != 'i8' ) {
var query = {
'action': 'query',
'list': 'imageusage',
'titles': wgPageName,
'iulimit': userIsInGroup( 'sysop' ) ? 5000 : 500 // 500 is max for normal users, 5000 for bots and sysops
};
var wikipedia_api = new Wikipedia.api( 'Grabbing image links', query, twinklecopyvio.callbacks.sysop.unlinkImageInstancesMain );
wikipedia_api.params = self.params;
wikipedia_api.post();
}
var doOrphan = TwinkleConfig.orphanBacklinksOnSpeedyDelete;
if(
doOrphan.orphan &&
doOrphan.exclude.indexOf( self.params.normalized.toLowerCase() ) == -1
) {
var query = {
'action': 'query',
'list': 'backlinks',
'blfilterredir': 'nonredirects',
'bltitle': wgPageName,
'bllimit': userIsInGroup( 'sysop' ) ? 5000 : 500, // 500 is max for normal users, 5000 for bots and sysops
'blnamespace': [0, 100] // Main namespace and portal namespace only, keep on talk pages.
};
var wikipedia_api = new Wikipedia.api( 'Grabbing backlinks', query, twinklecopyvio.callbacks.sysop.unlinkBacklinksMain );
wikipedia_api.params = self.params;
wikipedia_api.post();
}
var query = {
'action': 'query',
'list': 'backlinks',
'blfilterredir': 'redirects',
'bltitle': wgPageName,
'bllimit': userIsInGroup( 'sysop' ) ? 5000 : 500 // 500 is max for normal users, 5000 for bots and sysops
};
var wikipedia_api = new Wikipedia.api( 'Grabbing redirects', query, twinklecopyvio.callbacks.sysop.deleteRedirectsMain );
wikipedia_api.params = self.params;
wikipedia_api.post();
},
unlinkBacklinksMain: function( self ) {
var xmlDoc = self.responseXML;
var snapshot = xmlDoc.evaluate('//backlinks/bl/@title', xmlDoc, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null );
if( snapshot.snapshotLength == 0 ) {
return;
}
var statusIndicator = new Status('Removing backlinks', '0%');
var total = snapshot.snapshotLength * 2;
var onsuccess = function( self ) {
var obj = self.params.obj;
var total = self.params.total;
var now = parseInt( 100 * ++(self.params.current)/total ) + '%';
obj.update( now );
self.statelem.unlink();
if( self.params.current >= total ) {
obj.info( now + ' (completed)' );
Wikipedia.removeCheckpoint();
}
}
var onloaded = onsuccess;
var onloading = function( self ) {}
Wikipedia.addCheckpoint();
if( snapshot.snapshotLength == 0 ) {
statusIndicator.info( '100% (completed)' );
Wikipedia.removeCheckpoint();
return;
}
var params = clone( self.params );
params.current = 0;
params.total = total;
params.obj = statusIndicator;
params.page = wgPageName;
for ( var i = 0; i < snapshot.snapshotLength; ++i ) {
var title = snapshot.snapshotItem(i).value;
var query = {
'title': title,
'action': 'submit'
}
var wikipedia_wiki = new Wikipedia.wiki( "Unlinking on " + title, query, twinklecopyvio.callbacks.sysop.unlinkBacklinks );
wikipedia_wiki.params = params;
wikipedia_wiki.onloading = onloading;
wikipedia_wiki.onloaded = onloaded;
wikipedia_wiki.onsuccess = onsuccess;
wikipedia_wiki.get();
}
},
unlinkBacklinks: function( self ) {
var form = self.responseXML.getElementById('editform');
var text = form.wpTextbox1.value;
var old_text = text;
var wikiPage = new Mediawiki.Page( text );
wikiPage.removeLink( self.params.page );
text = wikiPage.getText();
if( text == old_text ) {
// Nothing to do, return
self.onsuccess( self );
Wikipedia.actionCompleted( self );
return;
}
var postData = {
'wpMinoredit': form.wpMinoredit.checked ? '' : undefined,
'wpWatchthis': undefined,
'wpStarttime': form.wpStarttime.value,
'wpEdittime': form.wpEdittime.value,
'wpAutoSummary': form.wpAutoSummary.value,
'wpEditToken': form.wpEditToken.value,
'wpSummary': 'Removing backlinks to ' + self.params.page + " that has been speedily deleted per ([[WP:CSD#" + self.params.normalized.toUpperCase() + "|CSD " + self.params.normalized.toUpperCase() + "]])" + "; " + TwinkleConfig.deletionSummaryAd,
'wpTextbox1': text
};
self.post( postData );
},
deleteRedirectsMain: function( self ) {
var xmlDoc = self.responseXML;
var snapshot = xmlDoc.evaluate('//backlinks/bl/@title', xmlDoc, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null );
var total = snapshot.snapshotLength * 2;
if( snapshot.snapshotLength == 0 ) {
return;
}
var statusIndicator = new Status('Deleting redirects', '0%');
var onsuccess = function( self ) {
var obj = self.params.obj;
var total = self.params.total;
var now = parseInt( 100 * ++(self.params.current)/total ) + '%';
obj.update( now );
self.statelem.unlink();
if( self.params.current >= total ) {
obj.info( now + ' (completed)' );
Wikipedia.removeCheckpoint();
}
}
var onloaded = onsuccess;
var onloading = function( self ) {}
Wikipedia.addCheckpoint();
if( snapshot.snapshotLength == 0 ) {
statusIndicator.info( '100% (completed)' );
Wikipedia.removeCheckpoint();
return;
}
var params = clone( self.params );
params.current = 0;
params.total = total;
params.obj = statusIndicator;
for ( var i = 0; i < snapshot.snapshotLength; ++i ) {
var title = snapshot.snapshotItem(i).value;
var query = {
'title': title,
'action': 'delete'
}
var wikipedia_wiki = new Wikipedia.wiki( "Deleting " + title, query, twinklecopyvio.callbacks.sysop.deleteRedirects );
wikipedia_wiki.params = params;
wikipedia_wiki.onloading = onloading;
wikipedia_wiki.onloaded = onloaded;
wikipedia_wiki.onsuccess = onsuccess;
wikipedia_wiki.followRedirect = false;
wikipedia_wiki.get();
}
},
deleteRedirects: function( self ) {
var form = this.responseXML.getElementById( 'deleteconfirm' );
if( ! form ) { // Hell, image deletion is b0rked :(
form = this.responseXML.getElementsByTagName( 'form' )[0];
var postData = {
'wpDeleteReasonList': 'other',
'wpReason': "Speedy deleted per ([[WP:CSD#R1|CSD R1]]), Redirect to deleted page \"" + wgPageName + "\"." + TwinkleConfig.deletionSummaryAd,
'wpEditToken': form.wpEditToken.value
}
} else {
var postData = {
'wpWatch': form.wpWatch.checked ? '' : undefined,
'wpDeleteReasonList': 'other',
'wpReason': "Speedy deleted per ([[WP:CSD#R1|CSD R1]]), Redirect to deleted page \"" + wgPageName + "\"." + TwinkleConfig.deletionSummaryAd,
'wpEditToken': form.wpEditToken.value
}
}
self.post( postData );
},
unlinkImageInstancesMain: function( self ) {
var xmlDoc = self.responseXML;
var snapshot = xmlDoc.evaluate('//imageusage/iu/@title', xmlDoc, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null );
if( snapshot.snapshotLength == 0 ) {
return;
}
var statusIndicator = new Status('Unlinking instances image', '0%');
var total = snapshot.snapshotLength * 2;
var onsuccess = function( self ) {
var obj = self.params.obj;
var total = self.params.total;
var now = parseInt( 100 * ++(self.params.current)/total ) + '%';
obj.update( now );
self.statelem.unlink();
if( self.params.current >= total ) {
obj.info( now + ' (completed)' );
Wikipedia.removeCheckpoint();
}
}
var onloaded = onsuccess;
var onloading = function( self ) {}
Wikipedia.addCheckpoint();
if( snapshot.snapshotLength == 0 ) {
statusIndicator.info( '100% (completed)' );
Wikipedia.removeCheckpoint();
return;
}
var params = clone( self.params );
params.current = 0;
params.total = total;
params.obj = statusIndicator;
params.image = wgTitle;
for ( var i = 0; i < snapshot.snapshotLength; ++i ) {
var title = snapshot.snapshotItem(i).value;
var query = {
'title': title,
'action': 'submit'
}
var wikipedia_wiki = new Wikipedia.wiki( "Unlinking on " + title, query, twinklecopyvio.callbacks.sysop.unlinkImageInstances );
wikipedia_wiki.params = params;
wikipedia_wiki.onloading = onloading;
wikipedia_wiki.onloaded = onloaded;
wikipedia_wiki.onsuccess = onsuccess;
wikipedia_wiki.get();
}
},
unlinkImageInstances: function( self ) {
var form = self.responseXML.getElementById('editform');
var text = form.wpTextbox1.value;
var old_text = text;
var wikiPage = new Mediawiki.Page( text );
wikiPage.commentOutImage( self.params.image, 'Commented out because image was deleted' );
text = wikiPage.getText();
if( text == old_text ) {
// Nothing to do, return
self.onsuccess( self );
Wikipedia.actionCompleted( self );
return;
}
var postData = {
'wpMinoredit': form.wpMinoredit.checked ? '' : undefined,
'wpWatchthis': undefined,
'wpStarttime': form.wpStarttime.value,
'wpEdittime': form.wpEdittime.value,
'wpAutoSummary': form.wpAutoSummary.value,
'wpEditToken': form.wpEditToken.value,
'wpSummary': 'Removing instance of image ' + self.params.image + " that has been speedily deleted per ([[WP:CSD#" + self.params.normalized.toUpperCase() + "|CSD " + self.params.normalized.toUpperCase() + "]])" + "; " + TwinkleConfig.deletionSummaryAd,
'wpTextbox1': text
};
self.post( postData );
},
deletePage: function( self ) {
var form = this.responseXML.getElementById( 'deleteconfirm' );
if( ! form ) { // Hell, image deletion is b0rked :(
form = this.responseXML.getElementsByTagName( 'form' )[0];
var postData = {
'wpDeleteReasonList': 'other',
'wpReason': "Speedy deleted per ([[WP:CSD#" + self.params.normalized.toUpperCase() + "|CSD " + self.params.normalized.toUpperCase() + "]]), " + self.params.reason + "." + TwinkleConfig.deletionSummaryAd,
'wpEditToken': form.wpEditToken.value
}
self.post( postData );
} else {
var postData = {
'wpWatch': self.params.watch || form.wpWatch.checked ? '' : undefined,
'wpDeleteReasonList': 'other',
'wpReason': "Speedy deleted per ([[WP:CSD#" + self.params.normalized.toUpperCase() + "|CSD " + self.params.normalized.toUpperCase() + "]]), " + self.params.reason + "." + TwinkleConfig.deletionSummaryAd,
'wpEditToken': form.wpEditToken.value
}
self.post( postData );
}
},
deleteTalkPage: function( self ) {
form = this.responseXML.getElementById( 'deleteconfirm' );
var postData = {
'wpWatch': self.params.watch || form.wpWatch.checked ? '' : undefined,
'wpDeleteReasonList': 'other',
'wpReason': "Speedy deleted per ([[WP:CSD#g8|CSD g8]]), was a talk page of deleted page." + TwinkleConfig.deletionSummaryAd,
'wpEditToken': form.wpEditToken.value
}
self.post( postData );
}
},
user: {
main: function( self ) {
var xmlDoc = self.responseXML;
var exists = xmlDoc.evaluate( 'boolean(//pages/page[not(@missing)])', xmlDoc, null, XPathResult.BOOLEAN_TYPE, null ).booleanValue;
if( ! exists ) {
self.statelem.error( "It seems that the page doesn't exists, perhaps it has already been deleted" );
return;
}
var query = {
'title': wgPageName,
'action': 'submit'
};
var wikipedia_wiki = new Wikipedia.wiki( 'Tagging page', query, twinklecopyvio.callbacks.user.tagPage );
wikipedia_wiki.params = self.params;
wikipedia_wiki.followRedirect = false;
wikipedia_wiki.get();
},
tagPage: function( self ) {
form = this.responseXML.getElementById( 'editform' );
var text = form.wpTextbox1.value;
self.statelem.status( 'Checking for tags on the page...' );
var tag = /(\{\{copyvio}\})/.exec( text );
if( tag ) {
self.statelem.error( [ htmlNode( 'strong', tag[0] ) , " is already placed on the page." ] )
return;
}
var xfd = /(\{\{(?:[rsaitcm]fd|md1)[^{}]*?\}\})/i.exec( text );
if( xfd && !confirm( "The deletion related template " + xfd[0] + " is already present on the page, do you still want to apply CSD template?" ) ) {
return;
}
var code;
// Notification to first contributor
var query = {
'action': 'query',
'prop': 'revisions',
'titles': wgPageName,
'rvlimit': 1,
'rvprop': 'user',
'rvdir': 'newer'
}
var callback = function( self ) {
var xmlDoc = self.responseXML;
var user = xmlDoc.evaluate( '//rev/@user', xmlDoc, null, XPathResult.STRING_TYPE, null ).stringValue;
var query = {
'title': 'User talk:' + user,
'action': 'submit'
};
var wikipedia_wiki = new Wikipedia.wiki( 'Notifying of initial contributor (' + user + ')', query, twinklecopyvio.callbacks.user.userNotification );
wikipedia_wiki.params = self.params;
wikipedia_wiki.get();
}
if( self.params.usertalk ) {
var wikipedia_api = new Wikipedia.api( 'Grabbing data of initial contributor', query, callback );
wikipedia_api.params = self.params;
wikipedia_api.post();
}
var postData = {
'wpMinoredit': TwinkleConfig.markSpeedyPagesAsMinor ? '' : undefined,
'wpWatchthis': self.params.watch ? '' : undefined,
'wpStarttime': form.wpStarttime.value,
'wpEdittime': form.wpEdittime.value,
'wpAutoSummary': form.wpAutoSummary.value,
'wpEditToken': form.wpEditToken.value,
'wpSummary': "Tagging as a copyright violation." + TwinkleConfig.summaryAd,
'wpTextbox1': code + "\n" + text
};
self.post( postData );
},
userNotification: function( self ) {
var form = self.responseXML.getElementById( 'editform' );
var text = form.wpTextbox1.value;
text += "\n\{\{subst:db-csd-notice-custom|1=" + wgPageName + "|2=" + self.params.value + "\}\} \~\~\~\~";
var postData = {
'wpMinoredit': form.wpMinoredit.checked ? '' : undefined,
'wpWatchthis': form.wpWatchthis.checked ? '' : undefined,
'wpStarttime': form.wpStarttime.value,
'wpEdittime': form.wpEdittime.value,
'wpAutoSummary': form.wpAutoSummary.value,
'wpEditToken': form.wpEditToken.value,
'wpSummary': 'Notification: Speedy deletion nomination of \[\[' + wgPageName + '\]\].' + TwinkleConfig.summaryAd,
'wpTextbox1': text
};
self.post( postData );
}
}
}
twinklecopyvio.callback.evaluateSysop = function twinklecopyvioCallbackEvaluateSysop(e) {
wgPageName = wgPageName.replace( /_/g, ' ' ); // for queen/king/whatever and country!
var tag_only = e.target.form.tag_only;
if( tag_only && tag_only.checked ) {
return twinklecopyvio.callback.evaluateUser(e);
}
var value = e.target.value;
var normalized = twinklecopyvio.normalizeHash[ value ];
var params = {
value: value,
normalized: normalized,
watch: TwinkleConfig.watchSpeedyPages.indexOf( normalized ) != -1,
reason: twinklecopyvio.reasonHash[ value ]
};
Status.init( e.target.form );
var query = {
'action': 'query',
'titles': wgPageName
}
var wikipedia_api = new Wikipedia.api( 'Checking if page exists', query, twinklecopyvio.callbacks.sysop.main );
wikipedia_api.params = params;
wikipedia_api.post();
}
twinklecopyvio.callback.evaluateUser = function twinklecopyvioCallbackEvaluateUser(e) {
wgPageName = wgPageName.replace( /_/g, ' ' ); // for queen/king/whatever and country!
var value = e.target.value;
var normalized = twinklecopyvio.normalizeHash[ value ];
var params = {
value: value,
normalized: normalized,
watch: TwinkleConfig.watchSpeedyPages.indexOf( normalized ) != -1,
usertalk: TwinkleConfig.notifyUserOnSpeedyDeletionNomination.indexOf( normalized ) != -1 && e.target.form.notify.checked
};
Status.init( e.target.form );
Wikipedia.actionCompleted.redirect = wgPageName;
Wikipedia.actionCompleted.notice = "Tagging complete";
var query = {
'action': 'query',
'titles': wgPageName
}
var wikipedia_api = new Wikipedia.api( 'Checking if page exists', query, twinklecopyvio.callbacks.user.main );
wikipedia_api.params = params;
wikipedia_api.post();
}