Jump to content

User:Decltype/csdhelper.js

From Wikipedia, the free encyclopedia
Note: After saving, you have to bypass your browser's cache to see the changes. Google Chrome, Firefox, Microsoft Edge and Safari: Hold down the ⇧ Shift key and click the Reload toolbar button. For details and instructions about other browsers, see Wikipedia:Bypass your cache.
/* ============================================== *\
** CSD Helper - JavaScript CSD Script
**   for Wikipedia
**
** Created by Alexander Barley [[User:Ale_jrb]]
**
\* ============================================== */

// the following settings are used in this script:
if (notifyByDefaultDec == null)	 var notifyByDefaultDec	= true;			// whether to check the 'notify tagger' box by default when declining a speedy deletion request
if (notifyByDefaultDel == null)	 var notifyByDefaultDel	= false;		// whether to check the 'notify tagger' box by default when changing a speedy deletion rationale
if (notifyByDefaultPrd == null)	 var notifyByDefaultPrd	= true;			// whether to check the 'notify tagger' box by default when converting a speedy deletion to PROD
if (notifyLimit == null)			 var notifyLimit			= 8;			// how many revisions should be retrieved when determining who tagged the page
if (redirectAfterDel == null)		 var redirectAfterDel	= 'http://en.wikipedia.org/w/index.php?title=Category:Candidates_for_speedy_deletion&action=purge#Pages_in_category'; // where to redirect after deletion
if (overwriteDeclineReasons == null)var overwriteDeclineReasons	= false;	 // whether to overwrite the in-build decline reasons with the user defined ones
if (myDeclineReasons == null)		var myDeclineReasons	= new Array();	 // any addition speedy deletion decline reasons to add to the list
	

//main script
function csdHelper() {
	this.launch = function() {
		// launch helper. check whether there is a deletion tag on this page.
		if ((document.getElementById('delete-criterion') == null) && !(document.body.innerHTML.indexOf('speedy deletion of this page is contested.') > -1)) {
                      return false;
                }
		if ( /*(waUser.isSysop == false) ||*/ (mw.config.get('wgNamespaceNumber') == 10)) { 
                      return false; 
                }

		// all checks OK :).
   	        // launch controller.
		this.control	= new csdH_controller;
		this.control.attachLinks();
		return true;
	}
}

function csdH_controller() {
	csdHController		 = this;
	csdHController.doNotifyDec = ''; csdHController.doNotifyDel = ''; csdHController.doNotifyPrd = ''; 
	if (notifyByDefaultDec == true) csdHController.doNotifyDec = ' checked';
	if (notifyByDefaultDel == true) csdHController.doNotifyDel = ' checked';
	if (notifyByDefaultPrd == true) csdHController.doNotifyPrd = ' checked';
	
	this.declineReasons = new Array(
					['G1',		 'the page is not nonsense - there is meaningful content.'],
					['G2',		 'the page is not a test page.'],
					['G3',		 'the page is not blatantly vandalism or a hoax.'],
					['G4',		 'the page has not previously been deleted via a deletion discussion.'],
					['G5',		 'the page was not created by a banned user, or the page does not violate the user\'s ban.'],
					['G6',		 'the deletion of this page may be controvertial or is under discussion.'],
					['G7',		 'the author has not requested deletion, or other users have added substantial content.'],
					['G8',		 'the page does not rely on one that does not exist.'],
					['G9',		 'this criterion can only be used at the request of, or by, the Wikimedia Foundation.'],
					['G10',	 'the page is not an attack page or negative unsourced BLP'],
					['G11',	 'the page is not unambiguously promotional.'],
					['G12',	 'the page is not an unambiguous copyright infringement, or there is other content to save.'],
					
					['A1',		 'there is sufficient context to identify the subject of the article.'],
					['A2',		 'the article is in English, or does not exist at a foreign project.'],
					['A3',		 'the article contains sufficient content to be a stub.'],
					['A5',		 'the article has not been transwikied to another project.'],
					['A7',		 'the article makes a credible claim of importance or significance.'],
					['A7',		 'A7 does not apply to books, software, buildings etc.'],
					['A9',		 'the article makes a credible claim of importance or significance or is not a musical recording'],
					
					['R2',		 'the page does not redirect to a different or incorrect namespace.'],
					['R3',		 'the page is a plausible, useful redirect or is not a redirect at all.'],
                                        ['R3',		 'the redirect page was not recently created'],
					
					['U1',		 'this criterion does not apply to user talk pages, or this is not a user page.'],
					['U2',		 'the user does exist, or this is not a user page.']
						);
	// Handle user defined content...
	if (overwriteDeclineReasons == true) {
		this.declineReasons.length = 0;
		this.declineReasons = myDeclineReasons;
	} else {
		this.declineReasons = this.declineReasons.concat(myDeclineReasons);
	}
	
	var declineReasonsEnd = new Array(
					['NA',		 'the reason given is not a valid \[\[WP:CSD|criterion for speedy deletion\]\]. Use \[\[WP:PROD\]\] or \[\[WP:AFD\]\] instead.'],
					['-',		 'no reason given.'],	 // don't touch this
					['O',		 'Other...']				// don't touch this
						);
	this.declineReasons = this.declineReasons.concat(declineReasonsEnd);
	
	
	
	this.deleteReasons = new Array(
					['N/A',		 'You must select a rationale...'],
					['G1',		 '[[WP:PN|Patent nonsense]], meaningless, or incomprehensible'],
					['G2',		 'Test page'],
					['G3',		 '[[WP:VANDAL|Vandalism]]'],
					['G4',		 'Recreation of a page that was [[WP:DEL|deleted]] per a [[WP:XFD|deletion discussion]]'],
					['G5',		 'Creation by a [[WP:BAN|banned]] user in violation of ban'],
					['G6',		 'Housekeeping and routine (non-controversial) cleanup'],
					['G7',		 'One author who has requested deletion or blanked the page'],
					['G8',		 'Page dependent on a deleted or nonexistent page'],
					['G10',	 '[[WP:ATP|Attack page]] or negative unsourced [[WP:BLP|BLP]]'],
					['G11',	 'Unambiguous [[WP:ADS|advertising]] or promotion'],
					['G12',	 'Unambiguous [[WP:C|copyright infringement]]'],

					['A1',		 'Not enough context to identify article\'s subject'],
					['A2',		 'Article in a foreign language that exists on another project'],
					['A3',		 'Article that has no meaningful, substantive content'],
					['A5',		 'Article that has been transwikied to another project'],
					['A7',		 'Article about a real person, which does not indicate the importance or significance of the subject'],
					['A7',		 'Article about a company, corporation, organization, or group, which does not indicate the importance or significance of the subject'],
					['A7',		 'Article about a group or club, which does not indicate the importance or significance of the subject'],
					['A7',		 'Article about a band, singer, musician, or musical ensemble, which does not indicate the importance or significance of the subject'],
					['A7',		 'Article about a web site, blog, web forum, webcomic, podcast, browser game, or similar web content, which does not indicate the importance or significance of the subject'],
					['A7',		 'No indication that the article might meet the guidelines for inclusion'],
					['A9',		 'Non-notable music by artist with no Wikipedia article'],
					
					['R2',		 'Cross-[[WP:NS|namespace]] [[WP:R|redirect]] from mainspace'],
					['R3',		 'Recently-created, implausible [[WP:R|redirect]]'],
					
					['U1',		 'User request to delete pages in own userspace'],
					['U2',		 'Userpage or subpage of a nonexistent user'],
					['U3',		 '[[WP:NFC|Non-free]] [[Help:Gallery|gallery]]']
						);
	
	this.showcsdHWindow = function() {
		// grab position of button
		var offset = document.getElementById('ca-speedy').offsetLeft;
		
		// build window to show user
		if (this.interface == null) { 
			this.interface = new wa_window(document.getElementById('content')); this.visible = true; this.csdHelperLink.ele_obj.setAttribute('class', 'selected'); 
			this.interface.win_content = ''+
					'<div><div style="width: 596px; border-bottom: 1px solid #aaaaaa; padding: 2px; font-weight: bold;">Handle Speedy Deletion</div>'+
					'<div style="font-size: 11px; margin-left: 7px;">What do you want to do to this page?</div>'+
					'<div style="font-size: 11px; text-align: center; width: 100%;">'+
						'<div style="margin: auto; width: 95%; cursor: pointer; background: #dfdfdf; border: 1px solid #cfcfcf; height: 22px; margin-top: 20px;" onclick="csdHController.deletePage();" onmouseover="this.style.border = \'1px solid #333333\';" onmouseout="this.style.border = \'1px solid #cfcfcf\';">Delete Page</div>'+
						'<div style="margin: auto; width: 80%; cursor: pointer; background: #dfdfdf; border: 1px solid #cfcfcf; height: 16px; margin-top: 20px;" onclick="csdHController.declinePage();" onmouseover="this.style.border = \'1px solid #333333\';" onmouseout="this.style.border = \'1px solid #cfcfcf\';">Decline Speedy</div>'+
						'<div style="margin: auto; width: 80%; cursor: pointer; background: #dfdfdf; border: 1px solid #cfcfcf; height: 16px; margin-top:  5px;" onclick="csdHController.prodPage();" onmouseover="this.style.border = \'1px solid #333333\';" onmouseout="this.style.border = \'1px solid #cfcfcf\';">Change to PROD</div>'+
					'</div>'+
					'';
		} else {
			this.interface.win_content = ''+
					'<div><div style="width: 596px; border-bottom: 1px solid #aaaaaa; padding: 2px; font-weight: bold;">Handle Speedy Deletion</div>'+
					'<div style="font-size: 11px; margin-left: 7px;">What do you want to do to this page?</div>'+
					'<div style="font-size: 11px; text-align: center; width: 100%;">'+
						'<div style="margin: auto; width: 95%; cursor: pointer; background: #dfdfdf; border: 1px solid #cfcfcf; height: 22px; margin-top: 20px;" onclick="csdHController.deletePage();" onmouseover="this.style.border = \'1px solid #333333\';" onmouseout="this.style.border = \'1px solid #cfcfcf\';">Delete Page</div>'+
						'<div style="margin: auto; width: 80%; cursor: pointer; background: #dfdfdf; border: 1px solid #cfcfcf; height: 16px; margin-top: 20px;" onclick="csdHController.declinePage();" onmouseover="this.style.border = \'1px solid #333333\';" onmouseout="this.style.border = \'1px solid #cfcfcf\';">Decline Speedy</div>'+
						'<div style="margin: auto; width: 80%; cursor: pointer; background: #dfdfdf; border: 1px solid #cfcfcf; height: 16px; margin-top:  5px;" onclick="csdHController.prodPage();" onmouseover="this.style.border = \'1px solid #333333\';" onmouseout="this.style.border = \'1px solid #cfcfcf\';">Change to PROD</div>'+
					'</div>'+
					'';
			
			if (this.visible == true) { 
				this.csdHelperLink.ele_obj.setAttribute('class', '');
				this.interface.win_disp = 'none'; 
				this.interface.applyAll(); 
				this.visible = false; 
				return true; 
			} else { 
				this.csdHelperLink.ele_obj.setAttribute('class', 'selected');
				this.interface.win_disp = 'block';
				this.interface.win_height = 170;
				this.interface.applyAll();
				this.visible = true; 
				return true;
			}
		}
		
		this.interface.win_left = offset - 17;
		this.interface.win_top = -1;
		this.interface.win_width = 600;
		this.interface.win_height = 170;
		this.interface.win_bg = '#fff';
		this.interface.win_bd = '#aaaaaa';
		this.interface.win_bd_wd = 1;
		this.interface.applyAll();
	}
	
	this.declinePage = function() {
		// build the selection options
		var declineOptions = '';
		for (var i = 0; i < this.declineReasons.length; i++) {
			var selected = '';
			if (document.getElementById('delete-criterion') != null) { 
				if (document.getElementById('delete-criterion').innerHTML == this.declineReasons[i][0]) selected = ' selected '; 
			} else {
				if (this.declineReasons[i][0] == 'O') selected = ' selected '; 
			}
			
			if (this.declineReasons[i][0] == 'NA') {
				declineOptions += '<option'+selected+'>No such criterion: '+this.declineReasons[i][1]+'</option>';
			} else if (this.declineReasons[i][0] == '-') {
				declineOptions += '<option'+selected+'>Criterion does not apply: '+this.declineReasons[i][1]+'</option>';
			} else if (this.declineReasons[i][0] == 'O') {
				declineOptions += '<option'+selected+'>Other - supply your own reason below.</option>';
			} else {
				declineOptions += '<option'+selected+'>'+this.declineReasons[i][0]+': '+this.declineReasons[i][1]+'</option>';
			}
		}
		
		this.interface.win_content = ''+
					'<div><div style="width: 596px; border-bottom: 1px solid #aaaaaa; padding: 2px; font-weight: bold;">Decline Speedy Deletion</div>'+
					'<div style="font-size: 11px; margin-left: 7px;">Select the reason for declining the deletion from the list. This text will be used as the edit summary.</div>'+
					'<select id="declineReason" style="font-size: 11px; margin-left: 9px;" onchange="document.getElementById(\'declineText\').value = \'\'">'+declineOptions+'</select>'+
					'<div style="font-size: 11px; margin-left: 7px; margin-top: 8px;">Or provide your own reason and summary below.</div>'+
					'<input id="declineText" style="margin-left: 9px; font-size: 11px; width: 576px;" type="text" onkeyup="document.getElementById(\'declineReason\').selectedIndex = csdHController.declineReasons.length-1;" />'+
					'<div style="margin-top: 13px; float: right; margin-right: 300px; font-size: 11px; ">-- <a href="#" onclick="csdHController.declineDo();">decline speedy deletion</a> --</div>'+
					'<div style="margin-top: 10px; font-size: 11px; margin-left: 20px; vertical-align: middle;">notify tagger <input id="notifyTagger"'+csdHController.doNotifyDec+' style="position: relative; top: 3px; " type="checkbox" /></div>'+
					'</div>'+
					'';
		this.interface.applyAll();
	}
	this.declineDo = function(callback) {
		// get page content
		if (!callback) var callback = 0;
		switch (callback) {
			default:
				// main vars
				csdHController.declineText =	 document.getElementById('declineText').value;
				csdHController.declineSel =	 document.getElementById('declineReason').selectedIndex;
				csdHController.declineNotify =	 document.getElementById('notifyTagger').checked;
			
				if ((csdHController.declineText == '') && (csdHController.declineSel == csdHController.declineReasons.length-1)) {
					csdHController.declineSel == csdHController.declineReasons.length-2;
				} else if ((csdHController.declineText != '') && (csdHController.declineSel == csdHController.declineReasons.length-1)) {
					csdHController.declineSel == csdHController.declineReasons.length-2;
				}
				
				csdHController.declineCategory	 =	 csdHController.declineReasons[csdHController.declineSel][0];
				csdHController.declineReason	=	 csdHController.declineReasons[csdHController.declineSel][1];
				
				// finish building messages
				if (csdHController.declineSel == csdHController.declineReasons.length - 3) {
					csdHController.declineReason = 'No such criterion: '+csdHController.declineReason+'';
				} else if (csdHController.declineSel == csdHController.declineReasons.length - 2) {
					csdHController.declineReason = 'Criterion does not apply. '+csdHController.declineReason+'';
				} else if (csdHController.declineSel == csdHController.declineReasons.length - 1) {
					csdHController.declineReason = csdHController.declineText;
				} else {
					csdHController.declineReason = csdHController.declineReason;
				}
				
				// start
				this.interface.win_content = ''+
					'<div><div style="width: 596px; border-bottom: 1px solid #aaaaaa; padding: 2px; font-weight: bold;">Working...</div>'+
					'<div style="font-size: 11px; margin-left: 7px;">Please wait while CSDHelper performs the requested operations. This can take several seconds.</div>'+
					'<div id="workingStatus" style="font-size: 11px; margin-left: 15px;">- Retrieving existing content...<br /></div>'+
					'</div>'+
					'';
				
				this.interface.applyAll();
			
				csdHController.pageReq = new wa_mediawikiApi();
				csdHController.pageReq.onCompleteAction = function() { csdHController.declineDo('1'); };
				csdHController.pageReq.getPage(mw.config.get('wgPageName'), notifyLimit, 'user|content');
				break;
				
			case '1':
				document.getElementById('workingStatus').innerHTML += '- Removing tags...<br />';
				csdHController.pageContent = csdHController.pageReq.data['page']['revisions'][0]['content'];
				
				var regReplace = /[\s]*\{\{db(?:-?(?:.+?)?|\|(.+))\}\}[\s]*/gi;
				csdHController.pageContent = csdHController.pageContent.replace(regReplace, '');
				var regReplace = /[\s]*\{\{hangon\}\}[\s]*/gi;
				csdHController.pageContent = csdHController.pageContent.replace(regReplace, '');
				
				csdHController.newContent = csdHController.pageContent; // grab a record of that
				if (csdHController.declineSel < csdHController.declineReasons.length-1) { // normal case
					csdHController.editSummary = 'removed speedy tag- '+csdHController.declineReason+' ([[User:Ale_jrb/Scripts|CSDH]])';
				} else if (csdHController.declineSel == csdHController.declineReasons.length-1) {
					csdHController.editSummary = 'removed speedy tag- '+csdHController.declineText+' ([[User:Ale_jrb/Scripts|CSDH]])';
				} else {
					csdHController.displayError(); return false;
				}
				
				document.getElementById('workingStatus').innerHTML += '- Updating page...<br />';
				
				csdHController.editReq = new wa_mediawikiApi();
				csdHController.editReq.onCompleteAction = function() { csdHController.declineDo('2'); };
				csdHController.editReq.editPage(mw.config.get('wgPageName'), csdHController.newContent, csdHController.editSummary, false, 'text');
				break;
				
			case '2':
				// check for notify
				if (csdHController.declineNotify == true) {
					document.getElementById('workingStatus').innerHTML += '- Determining user who tagged page...<br />';
					
					var tags = 0; csdHController.tagger = '';
				
					for (var i = 0; i < notifyLimit; i ++) {
						var thisPage = csdHController.pageReq.data['page']['revisions'][i]['content'];
						
						// count tags
						var regTest = /[\s]*\{\{db(?:-?(?:.+?)?|\|(.+))\}\}[\s]*/gi;
						var k = 1; var count = 0;
						while (k != null) {
							k = regTest.exec(thisPage);
							if (k != null) count ++;
						}
						regTest.lastIndex = 0;
						
						// check if we have fewer than last time (1 was added on that rev)
						if (count < tags) {
							csdHController.tagger = csdHController.pageReq.data['page']['revisions'][i - 1]['user'];
							break;
						} else {
							tags = count;
						}
					}
					if (csdHController.tagger == '') { document.getElementById('workingStatus').innerHTML += '- Could not determine tagger: will not notify. Finished.<br />'; break; }
					
					document.getElementById('workingStatus').innerHTML += '- Tagged by \''+csdHController.tagger+'\' - notifying user...<br />';
					csdHController.declineDo('3');
					
				} else { window.location.reload(true); csdHController.showcsdHWindow(); }
				break;
				
			case '3':
				// edit summary
				csdHController.editSummary = 'Notifying about removed speedy deletion tag ([[User:Ale_jrb/Scripts|CSDH]])';
				
				// message
				var message = '== Removed speedy deletion tag: [['+mw.config.get('wgPageName').replace(/_/g, ' ')+']] == \nHi '+csdHController.tagger+'! I just wanted to inform you that '+
					'I removed the speedy deletion tag you placed on [['+mw.config.get('wgPageName').replace(/_/g, ' ')+']]- because: \'\'\''+csdHController.declineReason+'\'\'\' If you have any questions or comments, please do not hesitate to contact me. ~~' + '~~';
				
				csdHController.saveReq = new wa_mediawikiApi();
				csdHController.saveReq.onCompleteAction = function() { window.location.reload(true); csdHController.showcsdHWindow(); };
				csdHController.saveReq.editPage('User_talk:'+csdHController.tagger, message, csdHController.editSummary, false, 'appendtext');
				break;
			
		}
		
	}
	
	this.prodPage = function() {
		var prodOptions = '';
		
		var content = document.getElementById('bodyContent');
		var regTest = /criteria for speedy deletion<\/a><\/i> because (.*?)\.<\/b> <i>For valid criteria,/i
		var rationale = regTest.exec(content);
		if (rationale != null) { rationale = rationale[1]; } else { rationale = ''; }
		
		this.interface.win_content = ''+
					'<div><div style="width: 596px; border-bottom: 1px solid #aaaaaa; padding: 2px; font-weight: bold;">Convert to PROD</div>'+
					'<div style="font-size: 11px; margin-left: 7px;">You are asserting that the page cannot be speedy deleted, but <em>can</em> be deleted by proposed deletion. '+
					'Enter the reason for deletion below - if the tagger provided one, it will be filled automatically.</div>'+
					'<input id="prodReason" style="margin-left: 9px; font-size: 11px; width: 576px;" type="text" value="'+rationale+'" />'+
					'<div id="notifyTaggerDiv" style="margin-top: 10px; font-size: 11px; margin-left: 20px; float: left; vertical-align: middle;">notify tagger of convertion <input id="notifyTagger"'+csdHController.doNotifyPrd+' style="position: relative; top: 3px; " type="checkbox" /></div>'+
					'<div style="margin: auto; margin-top: 13px; font-size: 11px; width: 200px; text-align: center;">-- <a href="#" onclick="csdHController.prodDo();">convert to PROD</a> --</div>'+
					'</div>'+
					'';
		this.interface.applyAll();
	}
	this.prodDo = function(callback) {
		if (!callback) var callback = 0;
		switch (callback) {
			default:
				csdHController.prodReason = document.getElementById('prodReason').value;
				csdHController.prodNotify = document.getElementById('notifyTagger').checked;
				
				this.interface.win_content = ''+
					'<div><div style="width: 596px; border-bottom: 1px solid #aaaaaa; padding: 2px; font-weight: bold;">Working...</div>'+
					'<div style="font-size: 11px; margin-left: 7px;">Please wait while CSDHelper performs the requested operations. This can take several seconds.</div>'+
					'<div id="workingStatus" style="font-size: 11px; margin-left: 15px;"></div>'+
					'</div>'+
					'';
				
				this.interface.applyAll();
			
				if (csdHController.prodNotify == true) {
					document.getElementById('workingStatus').innerHTML += '- Searching for tagger...<br />';
					
					if (notifyLimit > 10) notifyLimit = 10;
					csdHController.pageReq = new wa_mediawikiApi();
					csdHController.pageReq.onCompleteAction = function() { csdHController.prodDo('1'); };
					csdHController.pageReq.getPage(mw.config.get('wgPageName'), notifyLimit + 1, 'content|user');
				} else { 
					csdHController.pageReq = new wa_mediawikiApi();
					csdHController.pageReq.onCompleteAction = function() { csdHController.prodDo('3'); };
					csdHController.pageReq.getPage(mw.config.get('wgPageName'), 1, 'content|user');
				}
				break;
				
			case '1':
				var tags = 0; csdHController.tagger = '';
				
				for (var i = 0; i < notifyLimit; i ++) {
					var thisPage = csdHController.pageReq.data['page']['revisions'][i]['content'];
					
					// count tags
					var regTest = /[\s]*\{\{db(?:-?(?:.+?)?|\|(.+))\}\}[\s]*/gi;
					var k = 1; var count = 0;
					while (k != null) {
						k = regTest.exec(thisPage);
						if (k != null) count ++;
					}
					regTest.lastIndex = 0;
					
					// check if we have fewer than last time (1 was added on that rev)
					if (count < tags) {
						csdHController.tagger = csdHController.pageReq.data['page']['revisions'][i - 1]['user'];
						break;
					} else {
						tags = count;
					}
				}
				
				if (csdHController.tagger == '') { document.getElementById('workingStatus').innerHTML += '- Could not determine tagger. Moving to tag page...<br />'; csdHController.prodDo('3'); break; }
				
				csdHController.prodDo('2');
				break;
				
			case '2': // notify tagger
				document.getElementById('workingStatus').innerHTML += '- Tagged by \''+csdHController.tagger+'\' - notifying user...<br />';
			
				// edit summary
				csdHController.editSummary = 'Notifying about speedy deletion converted to PROD ([[User:Ale_jrb/Scripts|CSDH]])';
				
				// message
				var message =	 '== Speedy Deletion Converted to PROD: [['+mw.config.get('wgPageName').replace(/_/g, ' ')+']] == \nHello '+csdHController.tagger+', and thanks for your work patrolling new changes. I am just informing you that '+
					'I have changed a page you tagged ([['+mw.config.get('wgPageName').replace(/_/g, ' ')+']]) from being tagged for [[WP:CSD|speedy deletion]] to being tagged for [[WP:PROD|proposed deletion]]. '+
					'The speedy deletion criteria are very narrow, and do not fit the page in question. Consider reviewing the [[WP:CSD|criteria for speedy deletion]]. '+
					'If you have any queries, please let me know. Thanks again! ~~'+'~~';
				
				csdHController.notifyReq = new wa_mediawikiApi();
				csdHController.notifyReq.onCompleteAction = function() { csdHController.prodDo('3'); };
				csdHController.notifyReq.editPage('User_talk:'+csdHController.tagger, message, csdHController.editSummary, false, 'appendtext');
				break;
				
			case '3':
				document.getElementById('workingStatus').innerHTML += '- Converting tags...<br />';
				csdHController.pageContent = csdHController.pageReq.data['page']['revisions'][0]['content'];
				
				var regReplace = /[\s]*\{\{db(?:-?(?:.+?)?|\|(.+))\}\}[\s]*/gi;
				csdHController.pageContent = csdHController.pageContent.replace(regReplace, '{'+'{subst:prod|'+csdHController.prodReason+'}'+'}\n');
				var regReplace = /[\s]*\{\{hangon\}\}[\s]*/gi;
				csdHController.pageContent = csdHController.pageContent.replace(regReplace, '');
				
				csdHController.newContent = csdHController.pageContent; // grab a record of that
				csdHController.editSummary = 'Speedy deletion converted to PROD ([[User:Ale_jrb/Scripts|CSDH]])';
				
				document.getElementById('workingStatus').innerHTML += '- Updating page...<br />';
				
				csdHController.editReq = new wa_mediawikiApi();
				csdHController.editReq.onCompleteAction = function() { window.location.reload(true); csdHController.showcsdHWindow(); };
				csdHController.editReq.editPage(mw.config.get('wgPageName'), csdHController.newContent, csdHController.editSummary, false, 'text');
				break;
		}
	}
	
	this.deletePage = function() {
		// build the selection options
		var deleteOptions = '';
		for (var i = 0; i < this.deleteReasons.length; i++) {
			var selected = '';
			if (document.getElementById('delete-criterion') != null) { 
				if (document.getElementById('delete-criterion').innerHTML == this.deleteReasons[i][0]) selected = ' selected'; 
			} else {
				if (this.deleteReasons[i][0] == 'N/A') selected = ' selected '; 
			}
			
			// general
			var visibleReasoning = this.deleteReasons[i][1].replace(/\[\[(?:.*?\|)(.+?)\]\]/g, '$1');
			deleteOptions += '<option value="[[WP:CSD#'+this.deleteReasons[i][0]+'|'+this.deleteReasons[i][0]+']]: '+this.deleteReasons[i][1]+'"'+selected+' >'+this.deleteReasons[i][0]+': '+visibleReasoning+'</option>';
		}
		
		if (document.getElementById('delete-criterion') == null) { var displayTagCommand = 'display: none;'; } else { var displayTagCommand = 'display: block;'; }
		
		this.interface.win_content = ''+
					'<div><div style="width: 596px; border-bottom: 1px solid #aaaaaa; padding: 2px; font-weight: bold;">Perform Speedy Deletion</div>'+
					'<div style="font-size: 11px; margin-left: 7px;">Select the reason for deletion from the list. The rationale specified by the tagger is automatically selected. If you select a reason that does not '+
					'match the tag, will be given the option of notifying the tagger.</div>'+
					'<select id="deleteReason" style="font-size: 11px; margin-left: 9px; width: 576px;" onchange="'+
						'if (document.getElementById(\'delete-criterion\') != null) {'+
					'if (csdHController.deleteReasons[document.getElementById(\'deleteReason\').selectedIndex][0] != document.getElementById(\'delete-criterion\').innerHTML) { '+
						'if (csdHController.deleteReasons[document.getElementById(\'deleteReason\').selectedIndex][0] == \'N/A\') { document.getElementById(\'notifyTaggerDiv\').style.display = \'none\'; } else { document.getElementById(\'notifyTaggerDiv\').style.display = \'block\'; }'+
					'} else {'+
						'document.getElementById(\'notifyTaggerDiv\').style.display = \'none\'; '+
					'}'+
						'} else { document.getElementById(\'notifyTaggerDiv\').style.display = \'none\'; }'+
						
						'if (csdHController.deleteReasons[document.getElementById(\'deleteReason\').selectedIndex][0] == \'N/A\') {'+
					'document.getElementById(\'performDeletionDiv\').style.display = \'none\'; '+
						'} else {'+
					'document.getElementById(\'performDeletionDiv\').style.display = \'block\'; '+
						'}'+
					'">'+deleteOptions+'</select>'+
					'<div id="notifyTaggerDiv" style="display: none; margin-top: 10px; font-size: 11px; margin-left: 20px; float: left; vertical-align: middle;">notify tagger of rationale change <input id="notifyTagger"'+csdHController.doNotifyDel+' style="position: relative; top: 3px; " type="checkbox" /></div>'+
					'<div id="performDeletionDiv" style="margin: auto; margin-top: 13px; font-size: 11px; width: 200px; text-align: center; '+displayTagCommand+'">-- <a href="#" onclick="csdHController.deleteDo();">perform speedy deletion</a> --</div>'+
					'</div>'+
					'';
		this.interface.applyAll();
	}
	this.deleteDo = function(callback) {
		if (!callback) var callback = 0;
		switch (callback) {
			default:
				csdHController.deleteReason = document.getElementById('deleteReason').value + ' ([[User:Ale_jrb/Scripts|CSDH]])';
				csdHController.deleteSel = document.getElementById('deleteReason').selectedIndex;
				csdHController.deleteNotify = document.getElementById('notifyTagger').checked;
				if (document.getElementById('delete-criterion') == null) {
					csdHController.allowDelNotify = false;
				} else { csdHController.allowDelNotify = (csdHController.deleteReasons[csdHController.deleteSel][0] != document.getElementById('delete-criterion').innerHTML); }
				
				this.interface.win_content = ''+
					'<div><div style="width: 596px; border-bottom: 1px solid #aaaaaa; padding: 2px; font-weight: bold;">Working...</div>'+
					'<div style="font-size: 11px; margin-left: 7px;">Please wait while CSDHelper performs the requested operations. This can take several seconds.</div>'+
					'<div id="workingStatus" style="font-size: 11px; margin-left: 15px;"></div>'+
					'</div>'+
					'';
				
				this.interface.applyAll();
			
				if ((csdHController.deleteNotify == true) && (csdHController.allowDelNotify == true)) {
					document.getElementById('workingStatus').innerHTML += '- Searching for tagger...<br />';
					
					if (notifyLimit > 10) notifyLimit = 10;
					csdHController.pageReq = new wa_mediawikiApi();
					csdHController.pageReq.onCompleteAction = function() { csdHController.deleteDo('1'); };
					csdHController.pageReq.getPage(mw.config.get('wgPageName'), notifyLimit + 1, 'content|user');
				} else { csdHController.deleteDo('3'); }
				break;
				
			case '1':
				var tags = 0; csdHController.tagger = '';
				
				for (var i = 0; i < notifyLimit; i ++) {
					var thisPage = csdHController.pageReq.data['page']['revisions'][i]['content'];
					
					// count tags
					var regTest = /[\s]*\{\{db(?:-?(?:.+?)?|\|(.+))\}\}[\s]*/gi;
					var k = 1; var count = 0;
					while (k != null) {
						k = regTest.exec(thisPage);
						if (k != null) count ++;
					}
					regTest.lastIndex = 0;
					
					// check if we have fewer than last time (1 was added on that rev)
					if (count < tags) {
						csdHController.tagger = csdHController.pageReq.data['page']['revisions'][i - 1]['user'];
						break;
					} else {
						tags = count;
					}
				}
				
				if (csdHController.tagger == '') { document.getElementById('workingStatus').innerHTML += '- Could not determine tagger. Moving to deletion...<br />'; csdHController.deleteDo('3'); break; }
				
				csdHController.deleteDo('2');
				break;
				
			case '2': // notify tagger
				document.getElementById('workingStatus').innerHTML += '- Tagged by \''+csdHController.tagger+'\' - notifying user...<br />';
			
				// edit summary
				csdHController.editSummary = 'Notifying about altered speedy deletion rationale ([[User:Ale_jrb/Scripts|CSDH]])';
				
				// message
				var message =	 '== Altered Speedy Deletion rationale: [['+mw.config.get('wgPageName').replace(/_/g, ' ')+']] == \nHello '+csdHController.tagger+', and thanks for your work patrolling new changes. I am just informing you that '+
					'I have deleted a page you tagged ([['+mw.config.get('wgPageName').replace(/_/g, ' ')+']]) under a different criteria, because the one you provided was inappropriate or incorrect. CSD criteria are narrow and specific, '+
					'and the process is more effective if the correct deletion rationale is supplied. Consider reviewing the [[WP:CSD|criteria for speedy deletion]]. '+
					'If you have any queries, please let me know. Thanks again! ~~'+'~~';
				
				csdHController.notifyReq = new wa_mediawikiApi();
				csdHController.notifyReq.onCompleteAction = function() { csdHController.deleteDo('3'); };
				csdHController.notifyReq.editPage('User_talk:'+csdHController.tagger, message, csdHController.editSummary, false, 'appendtext');
				break;
				
			case '3':
				// perform the edit
				document.getElementById('workingStatus').innerHTML += '- Deleting page...<br />';
				
				csdHController.deleteReq = new wa_mediawikiApi();
				csdHController.deleteReq.onCompleteAction = function() { window.location = redirectAfterDel; csdHController.showcsdHWindow(); };
				csdHController.deleteReq.performAction('delete', mw.config.get('wgPageName'), csdHController.deleteReason);
				break;
		}
	}
	
	this.displayError = function() {
		this.interface.win_content = ''+
					'<div><div style="width: 596px; border-bottom: 1px solid #aaaaaa; padding: 2px; font-weight: bold;">An error occured...</div>'+
					'</div>'+
					'';
		this.interface.applyAll();
	}
	
	this.attachLinks = function() {
		this.csdHelperLink						 = new wa_element('li');
		this.csdHelperLink.ele_obj.id			= 'ca-speedy';
		this.csdHelperLink.ele_obj.innerHTML	= '<a href="#" title="handle speedy deletion">speedy</a>';
		this.csdHelperLink.addScriptEvent('click', function() { csdHController.showcsdHWindow(); });
		
		this.csdHelperLink.attach(document.getElementById('ca-move'), 'before');
	};
}



// -- run program
function launchCsdHelper() {
	// lib proto
	wa_window.prototype = new wa_document;
	wa_element.prototype = new wa_document;
	
	// init object
	var obj_csdHelper = new csdHelper;
	obj_csdHelper.launch();
	
	return true;
}

importScript('User:Ale_jrb/Scripts/waLib.js');
hookEvent('load', launchCsdHelper);