MediaWiki:Gadget-DelReqHandler.js: Różnice pomiędzy wersjami

Z Wikipedii, wolnej encyklopedii
Usunięta treść Dodana treść
Tufor (dyskusja | edycje)
m lit.
Tufor (dyskusja | edycje)
m obsługa parametru wycofaj
Linia 319: Linia 319:
switch(action)
switch(action)
{
{
case 5: //eject
case 1: //kept
case 1: //kept
this.template_param = 'zostawiono';
this.template_param = 'zostawiono';

Wersja z 18:07, 27 maj 2020

// <nowiki>
/*
  Support for quick deletions and closing of deletion requests at Polish Wikipedia.

  Author: [[User:Lupo]], October 2007 - January 2008
    full list of authors: http://commons.wikimedia.org/w/index.php?title=MediaWiki:Gadget-DelReqHandler.js&action=history

  Adaptation for pl.wiki: [[User:Lampak]]

  Contains parts of code (possibly modified) of commons:MediaWiki:AjaxQuickDelete.js
    by [[User:Ilmari Karonen]], [[User:DieBuche]]
    full list of authors: http://commons.wikimedia.org/w/index.php?title=MediaWiki:AjaxQuickDelete.js&action=history

  Tested only in Firefox.
*/

$(document).ready(function() {
/**** Enable the whole shebang only for sysops. */
if ('object' === typeof DelReqHandler  || -1 === $.inArray('sysop', mw.config.get('wgUserGroups'))) {
	return;
}

/**** Some things may not be defined in some cases */

var DelReqUtils =
{
	// The following function is defined in several places, and unfortunately, it is defined
	// wrongly in some places. (For instance, in [[:en:User:Lupin/popups.js]]: it should use
	// decodeURIComponent, not decodeURI!!!) Make sure we've got the right version here:
	getParamValue : function (paramName, href)
	{
		var cmdRe = RegExp ('[&?]' + paramName + '=([^&]*)');
		var h = href || document.location.href;
		var m = cmdRe.exec (h);
		if (m) {
			try {
				return decodeURIComponent (m[1]);
			} catch (someError) {}
		}
		return null;
	}

}; // End of DelReqUtils

var DelReqHandler =
{

	/*------------------------------------------------------------------------------------------
	  Deletion request closing: add "[d][del]" and "[k][keep]" links to the left of the section edit
	  links of a deletion request. [d] and [k] open the deletion request for editing in a new window
	  (or tab), add "delh" and "delf" with "Deleted." or "Kept." plus the signature (four tildes)
	  and then save and close the tab. [del] and [keep] do the same, but don't save and close the
	  window, so that the user may enter an additional comment.
	  ------------------------------------------------------------------------------------------*/

	lupo_close_del     : 'close_del',
	lupo_close_keep    : 'close_keep',
	lupo_close_no_result : 'close_no_result',
	lupo_close_eject   : 'close_eject',
	close_del_summary  : 'Usunięto.',
	close_keep_summary : 'Zostawiono.',
	close_no_result_summary : 'Nie osiągnięto konsensusu.',
	close_eject_summary: 'Wycofano.',
	deletion_request_pages : ['Wikipedia:Poczekalnia/artykuły', 'Wikipedia:Poczekalnia/biografie', 'Wikipedia:Poczekalnia/kwestie_techniczne', 'Wikipedia:Poczekalnia/zgłoszenia'], 
	archive_section_line : '<!-- Zakończone dyskusje wstawiaj poniżej tej linii -->',
	archive_edit_summary : '[[$1]] − dyskusja zakończona',
	
	script_dependencies : ['jquery.ui'],
	
	beginLoading : function()
	{
		var wgAction = mw.config.get('wgAction');
		var notoldid = document.URL.search (/[?&]oldid=/) < 0;
		if ((wgAction == 'view' || wgAction == 'purge') && this.isItDelReqPage() && notoldid)
		{
			var o = this;
			mw.loader.using(this.script_dependencies, function() {
				$(document).ready(function() {
					o.closeRequestLinks();				    
				});
			});			
		}
		else if (wgAction == 'edit')
			this.maybeSetupForm();
	},

	isItDelReqPage : function()
	{
		var wgPageName = mw.config.get('wgPageName');
		for (var i = 0; i < this.deletion_request_pages.length; i++)
			if (wgPageName.indexOf(this.deletion_request_pages[i]) == 0)
				return true;
		return false;
	},

	isLinkToSubpage : function(href)
	{
		for (var i = 0; i < this.deletion_request_pages.length; i++)
		{
			var searched = encodeURIComponent(this.deletion_request_pages[i] + '/').
			replace(/\%3A/g, ':').replace(/\%20/g, '_').replace(/\(/g, '%28').
			replace(/\)/g, '%29').replace(/\%2F/g, '/');
			if(href.indexOf(searched) > 0)
				return true;
		}
		return false;
	},

	closeRequestLinks : function ()
	{
		function addRequestLinks (name, href, before, parent)
		{
			parent.insertBefore (document.createTextNode ('['), before);
			parent.insertBefore (makeRawLink (
					name.substring (0, 1), 
					href + DelReqHandler.lupo_quick_closure, 
					'_blank'
					), before);
			parent.insertBefore (document.createTextNode (']'), before);

			parent.insertBefore (document.createTextNode ('['), before);
			parent.insertBefore (makeRawLink (name, href, '_blank'), before);
			parent.insertBefore (document.createTextNode (']'), before);
		}

		var edit_lks = $('.mw-editsection').get();
		var lk_number = 0;
		for (i = 0; i < edit_lks.length; i++) {
			// Find the A within:
			var anchors = edit_lks[i].getElementsByTagName ('a');
			if (anchors != null && anchors.length > 0) {
				var anchor = anchors[anchors.length-1]; // first one might be VE, last one is the normal one
				var href   = anchor.getAttribute ('href');
				if (//href.indexOf ('Wikipedia:Poczekalnia/20') < 0 && //I can't see any point in it...
				    this.isLinkToSubpage(href))
				{
					var offset = href.indexOf ('&section=1');
					var len = 10;
					if (offset < 0) {
						offset = href.indexOf ('&section=T-1'); // Fix for MW 1.13alpha
						len = 12;
					}
					if (offset > 0 && offset + len == href.length) {

						// It's really an edit lk to a deletion request subpage, and not a section
						// edit for a daily subpage or something else

						//bold the edit button
						anchor.style.fontWeight = 'bold';

						var orig_bracket = edit_lks[i].firstChild;
						var close_href = href.substring (0, offset);

						//get deletion reason
						var subpage = href.substring (href.indexOf ('title=') + 6);
						var idx = subpage.indexOf ("&");
						if (idx >= 0) subpage = subpage.substring (0, idx);
						subpage = decodeURIComponent(subpage);
						
						var clickHandlerCreator = function(link, action, link_id, fakeaction) {
							var local_action = action;
							var local_link_id = link_id;
							var local_subpage = subpage;
							var local_close_href = close_href;
							if (fakeaction.length) {
								local_close_href = close_href + "&fakeaction=" + fakeaction;
							}
							$(link).click(function(e){
								e.preventDefault();
								DelReqHandler.buttonClicked(local_action, local_link_id, local_subpage, local_close_href);
							});
						};

						//
						// buttons
						//
						//delete
						var link_id = "drh-del-" + lk_number;
						var link = makeActiveLink('usuń', '#');
						link.id = link_id;
						clickHandlerCreator(link, 0, link_id, DelReqHandler.lupo_close_del);
						edit_lks[i].insertBefore(document.createTextNode('['), orig_bracket);
						edit_lks[i].insertBefore(link, orig_bracket);
						edit_lks[i].insertBefore(document.createTextNode('] ['), orig_bracket);

						//keep
						link_id = "drh-keep-" + lk_number;
						link = makeActiveLink('zostaw', '#');
						link.id = link_id;
						clickHandlerCreator(link, 1, link_id, DelReqHandler.lupo_close_keep);
						edit_lks[i].insertBefore(link, orig_bracket);
						edit_lks[i].insertBefore(document.createTextNode('] ['), orig_bracket);

						//no result
						link_id = "drh-noresult-" + lk_number;
						link = makeActiveLink('brak wyniku', '#');
						link.id = link_id;
						clickHandlerCreator(link, 2, link_id, DelReqHandler.lupo_close_no_result);
						edit_lks[i].insertBefore(link, orig_bracket);
						edit_lks[i].insertBefore(document.createTextNode('] ['), orig_bracket);

						//to archive
						link_id = "drh-archive-" + lk_number;
						link = makeActiveLink('do arch.', '#');
						link.id = link_id;
						clickHandlerCreator(link, 4, link_id, '');

						edit_lks[i].insertBefore(link, orig_bracket);
						edit_lks[i].insertBefore(document.createTextNode('] ['), orig_bracket);

						link_id = "drh-eject-" + lk_number;
						link = makeActiveLink('wycofaj', '#');
						link.id = link_id;
						clickHandlerCreator(link, 5, link_id, '');

						edit_lks[i].insertBefore(link, orig_bracket);
						edit_lks[i].insertBefore(document.createTextNode('] '), orig_bracket);

						lk_number++;
					}
				}
			}
		}
	},

	/*------------------------------------------------------------------------------------------
	  Links on every non-deleted image mentioned on a deletion request page. The "[del]" link
	  triggers deletion (auto-completed!) of the image, with a deletion summary linking to the
	  deletion request. If the image has a talk page, it is deleted as well. The "[keep]" link
	  automatically removes the "delete" template from the image page and adds the "kept" template
	  to the image talk page, both linking back to the deletion request.
	  ------------------------------------------------------------------------------------------*/

	/*
	* buttonClicked
	*
	* Called when the user clicked one of the links
	*
	* action - which of the links has been pressed?
	*          0 - delete
	*          1 - keep
	*          2 - no result
	*          3 - repaired (not used)
	*          4 - to archive
	* id - id of the link pressed
	* subpage - subpage of the request
	* old_style_href - URL which marks the request as closed
	*/
	buttonClicked : function (action, id, sub, old_style_href)
	{
		this.startDate = new Date ();
		this.subpage = sub;
		this.reason = '[[' + sub + ']]';
		this.keep_summary = 'Zostawiono po dyskusji: ' + this.reason;
		this.close_href = old_style_href;

		//find the link
		var el = document.getElementById(id);
		if (!el)
		{
			//no such link
			alert("Error - link not found");
			return;
		}
		//go up to the header
		while (el.tagName.search('H\\d') < 0)
		{
			el = el.parentNode;
			if (el == document)
			{
				alert("Error - link outside a header");
				return;
			}
		}

		//find the header line
		var els = $(el).find('.mw-headline').get();

		if (els.length > 1)
		{
			//more then one headline in a header - something's wrong.
			alert("Error!");
			return;
		}
		el = els[0];
		var header = el; //remember for moveToArchive()

		this.pages_to_process = [];

		//find all links in the header
		els  = el.getElementsByTagName('a');
		for (var i = 0; i < els.length; i++)
		{
			///make keep_href and open
			el = $(els[i]);
			if (el.hasClass('new'))
				//red link
				continue;
			var href = el.attr('href');
			this.pages_to_process.push(titleFromHref(href));
		}

		//move the subpage to the 24h archive
		this.subpage_title = titleFromHref(old_style_href);

		this.tasks = [];
		this.addTask('showProgress');
		this.addTask('getEditToken');
		switch(action)
		{
		case 0: //delete
			this.addTask('deletePages');
			break;
		case 5: //eject
		case 3: //repaired
		case 2: //noresult
		case 1: //keep
			this.addTask('removeTemplate');
			switch(action)
			{
			case 5: //eject
			case 1: //kept
				this.template_param = 'zostawiono';
				break;
			case 2: //no result
				this.template_param = 'brak wyniku';
				break;
			}
			break;
		}
		this.addTask('addSubpageToArchive');
		this.addTask('removeSubpage');
		this.addTask('openSubpageForEdit');
		this.addTask('reloadPage');

		this.nextTask();
	},

	removeTemplate : function()
	{
		if (this.pages_to_process.length == 0)
		{
			this.nextTask();
			return;
		}

		this.page_processed = this.pages_to_process.shift();
		this.updateProgress('Usuwam szablon {{DNU}} ze strony „' + this.page_processed + '”');

		this.fetchPage(this.page_processed, 'removeTemplateCB');
	},

	removeTemplateCB : function(result)
	{
		var text = this.extractPageText(result);

		var start = text.indexOf ('\{\{DNU');
		if (start < 0) start = text.indexOf ('\{\{dNU');
		if (start < 0) start = text.indexOf ('\{\{poczSDU');
		if (start < 0) start = text.indexOf ('\{\{PoczSDU');
		if (start < 0) start = text.indexOf ('\{\{PoczSdU');
		if (start < 0) start = text.indexOf ('\{\{poczSdU');
		if (start >= 0) {
			var level = 0;
			var curr = start + 2;
			var end = 0;
			while (curr < text.length && end == 0) {
				var opening = text.indexOf ('\{\{', curr);
				var closing = text.indexOf ('\}\}', curr);
				if (opening >= 0 && opening < closing) {
					level = level + 1;
					curr = opening + 2;
				} else {
					if (closing < 0) {
						// No closing braces found
						curr = text.length;
					} else {
						if (level > 0) level = level - 1;
						else end = closing + 2;
						curr = closing + 2;
					}
				}
			}
			if (end > start) {
				// Also strip whitespace after the "delete" template
				if (start > 0) {
					//text = text.substring (0, start)
					//       + text.substring (end).replace(/^\s*/, '');

					var beginning = text.substring(0,start);
					var ending = text.substring(end);

					//strip <noinclude>, if the template is the only thing in it
					if (beginning.search(/<noinclude>\s*$/) >= 0
					&& ending.search(/^\s*<\/noinclude>/) >= 0)
					{
						beginning = beginning.replace(/<noinclude>\s*$/, '');
						ending = ending.replace(/^\s*<\/noinclude>/, '');
					}
					else
						ending = ending.replace('^\\s*', '');
					text = beginning + ending;
				} else {
					text = text.substring (end).replace(/^\s*/, '');
				}
				var page = {};
				page.title = this.page_processed;
				page.editType = 'text';
				page.text = text;
				this.savePage (
				    page,
				    this.keep_summary,
				    'addKeepToTalk'
				);
				success = true;
			} else {
				this.addWarning ('Nie znaleziono zamknięcia szablonu na stronie ' + this.page_processed + '.');
				this.addKeepToTalk();
			}
		} else {
			this.addWarning ('Nie znaleziono szablonu DNU na stronie ' + this.page_processed + '.');
			this.addKeepToTalk();
		}
	},

	addKeepToTalk : function ()
	{
		//
		var talk_title = this.findTalkPage(this.page_processed);

		this.updateProgress('Dodaję szablon {{DNU}} na stronie dyskusji „' + talk_title + '”.');

		var text;

		try {
			text = '\{\{DNU|' + this.template_param + '|zakończenie='
			+ this.formatDate('YYYY-MM-DD');
			text = text + '|podstrona=' + this.subpage + '\}\}\n';
			success = true;
		} catch (ex) {
			// Swallow
		}
		if (!success) {
			// Huh? Somehow, we couldn't get the date.
			text = '\{\{DNU|' + this.template_param + '|podstrona=' + this.subpage + '\}\}\n';
		}

		var page = {};
		page.editType = 'prependtext';
		page.text = text;
		page.title = talk_title;
		this.savePage(page, this.keep_summary, 'removeTemplate');
	},

	//Find the parent page
	//For example if page_name is Wikipedia:DNU/artykuły/zgłoszenie
	//and deletion_request_pages=['Wikipedia:DNU/artykuły', 'Wikipedia:DNU/techniczne']
	//the function should return 'Wikipedia:DNU/artykuły'
	findParentPage : function(page_name)
	{
		var result;
		for (var i = 0; i < this.deletion_request_pages.length; i++)
		{
			var page = this.deletion_request_pages[i];
			if (page_name.indexOf(page) == 0)
				if (result == null || page.length > result.length)
					result = page;
		}
		return result;
	},

	findTalkPage : function (title) {
		//wgNamespaceIds doesn't contain canonical namespace names (bug 25375)
		//create our own table then.
		var namespaceIds = {
			'talk' : 1,
			'user' : 2,
			'user_talk' : 3,
			'project' : 4,
			'project_talk' : 5,
			'file' : 6,
			'file_talk' : 7,
			'mediawiki' : 8,
			'mediawiki_talk' : 9,
			'template' : 10,
			'template_talk' : 11,
			'help' : 12,
			'help_talk' : 13,
			'category' : 14,
			'category' : 15
		};
		var wgNamespaceIds = mw.config.get('wgNamespaceIds');
		for (var n in wgNamespaceIds)
			namespaceIds[n] = wgNamespaceIds[n];

		var talk_title;
		var idx = title.indexOf(':');
		if (idx < 0)
			//no colon - main namespace
			talk_title = 'Dyskusja:' + title;
		else
		{
			var namespace = title.substring(0, idx).toLowerCase().replace(/ /g, '_');
			if (namespaceIds[namespace] == null)
				//no such namespace - main namespace
				talk_title = 'Dyskusja:' + title;
			else
			{
				var id = namespaceIds[namespace];
				if (id % 2 == 1)
				{
					//already a link to a talk page?
					talk_title = title;
				}
				else
					talk_title = mw.config.get('wgFormattedNamespaces')[id+1] + ':' + title.substring(idx+1);
			}
		}
		return talk_title;
	},

	no_result : false, //says whether 'brak wyniku' should be used as a param of DNU template

	//name of the parent page of a request (i.e. the page where it is (hopefully) included)
	//name of the temorary archive page
	archive_page : '',
	//the subpage which is being moved to archive

	//Moves the given subpage to a temporary archive
	//The archive should be at a page titled like the one with the deletion requests
	//  ended with " załatwione 24".
	//and contain the text spcifed in archive_section_line
	addSubpageToArchive : function()
	{
		this.updateProgress('Dodaję podstronę do archiwum 24...');

		this.parent_page = this.findParentPage(this.subpage);
		this.archive_page = this.parent_page + ' załatwione 24';

		this.fetchPage(this.archive_page, 'addSubpageToArchiveCB');
	},

	addSubpageToArchiveCB : function(result)
	{
		var text = this.extractPageText(result);
		var subpage = this.subpage;

		//if it's possible - strip the prefix
		var idx = subpage.indexOf(DelReqHandler.archivePageName);
		if (idx == 0)
			subpage = subpage.substr(DelReqHandler.archivePageName.length);

		subpage = '{{' + subpage + '}}';

		if (text.indexOf(DelReqHandler.archive_section_line) >= 0)
			text = text.replace(
				   DelReqHandler.archive_section_line,
				   DelReqHandler.archive_section_line + '\n' + subpage
			       );
		else
			//no archive line - just append
			//do not add an extra line break if the current text ends with one
			text =
			    text
			    + (text[text.length-1] == '\n' ? '' : '\n')
			    + subpage;

		var page = {};
		page.title = this.archive_page;
		page.editType = 'text';
		page.text = text;
		this.savePage(
		    page,
		    '+ {{[[' + this.subpage + ']]}}',
		    'nextTask'
		);
	},

	//removes a subpage inclusion from the main request page
	removeSubpage : function()
	{
		this.updateProgress();
		this.fetchPage(this.parent_page, 'removeSubpageCB');
	},

	removeSubpageCB : function (result)
	{
		var text = this.extractPageText(result);

		//find the subpage inclusion
		var searched = "{{" + this.subpage + "}}\n";
		var idx = text.indexOf(searched);
		if (idx < 0)
		{
			//not found - try with spaces instead of underscores
			searched = searched.replace(/_/g, ' ');
			idx = text.indexOf(searched);
			if (idx < 0)
			{
				//not found - but the inclusion may still look like {{/subpage}}
				if (this.subpage.indexOf(this.subpage) == 0)
				{
					searched = this.subpage.substr(this.parent_page.length);
					searched = "{{" + searched + "}}\n";
					idx = text.indexOf(searched);

					if (idx < 0)
					{
						//not found - try with spaces instead of underscores
						searched = searched.replace('_', ' ');
						idx = text.indexOf(searched);
					}
				}
			}
		}
		if (idx >= 0)
		{
			//inclusion found - cut it out
			text = text.substr(0, idx) + text.substr(idx + searched.length);

			var page = {};
			page.title = this.parent_page;
			page.text = text;
			page.editType = 'text';

			this.savePage(
			    page,
			    '{{[[' + this.subpage + ']]}} - przeniesione do archiwum',
			    'nextTask'
			);
		}
		else
		{
			this.nextTask();
		}
	},

	/*
	* This function will pre-fill the form when closing a request.
	* User must be editting and fakeaction must be set.
	*/
	maybeSetupForm : function()
	{
		var param = DelReqUtils.getParamValue ('fakeaction');
		if (param == null)
			return;

		var summary = null;
		var result_param = null;
		if (param == DelReqHandler.lupo_close_del) {
			summary = DelReqHandler.close_del_summary;
			result_param = 'usunięto';
		} else if (param == DelReqHandler.lupo_close_keep) {
			summary = DelReqHandler.close_keep_summary;
			result_param = 'zostawiono';
		} else if (param == DelReqHandler.lupo_close_no_result) {
			summary = DelReqHandler.close_no_result_summary;
			result_param = 'brak wyniku';
		} else if (param == DelReqHandler.lupo_close_eject) {
			summary = DelReqHandler.close_eject_summary;
			result_param = 'wycofano';
		}
		if (summary !== null && result_param !== null) {
			$('#wpSummary').val(summary);
			
			var textbox = document.editform.wpTextbox1;
			var text = textbox.value + '\n\'\'\'' + summary + '\'\'\' \~\~\~\~';
			text = text.replace(/(\{\{lnDNU)/gi, '$1|rezultat=' + result_param + '|data zakończenia=' + this.formatDate("YYYY-MM-DD"));
			textbox.value = text;	

			// Don't close the window so the user can add a comment.
			if (text.scrollHeight > text.clientHeight) {
				text.scrollTop = text.scrollHeight - text.clientHeight;
			}
			textbox.focus();
		}
	},

	deletePages : function()
	{
		if (this.pages_to_process.length == 0)
		{
			this.nextTask();
			return;
		}

		this.page_processed = this.pages_to_process.shift();

		this.updateProgress('Usuwam stronę ' + this.page_processed + '...');

		this.deletePage(this.page_processed, 'Usunięto po dyskusji: ' + this.reason, 'deleteTalkPage');
	},

	deleteTalkPage : function()
	{
		var talk_title = this.findTalkPage(this.page_processed);

		this.updateProgress('Usuwam stronę dyskusji ' + talk_title + '...');

		this.deletePage(talk_title, 'Strona dyskusji artykułu usuniętego po dyskusji: ' + this.reason, 'deletePages');
	},


	openSubpageForEdit : function()
	{
		this.updateProgress('Otwieram podstronę zgłoszenia do edycji...');
		if(!window.DelReqPopup)
		{
			//user preferences - open edit in the same window
			location.href = this.close_href;
		}
		else
		{
			window.open(this.close_href, '_blank');
			$('#del-req-progress').dialog("close");
			document.body.style.cursor = '';
		}
		this.nextTask();
	},

	/**
	* Once we're all done, reload the page.
	* force - if true, the page will be reloaded no matter user preferences
	**/
	reloadPage : function (force) {
		if (!force && (!window.DelReqPopup || window.DelReqDontReload))
			//user preferences - don't reload when finished
			return;

		if (this.there_are_warnings === true)
		{
			//there were warnings - give the user 3 more seconds to read them
			window.setTimeout(function() {
				DelReqHandler.reloadPage();
			}, 3000);
			this.there_are_warnings = false;
			return;
		}

		//reload
		var title = encodeURIComponent(this.destination || mw.config.get('wgPageName')).
			    replace(/\%3A/g, ':').replace(/\%20/g, '_').
			    replace(/\(/g, '%28').replace(/\)/g, '%29').
			    replace(/\%2F/g, '/');
		location.href = mw.config.get('wgServer') + mw.config.get('wgArticlePath').replace("$1", title);
	},

	/**
	* Submit an edited page.
	**/
	savePage : function (page, summary, callback) {
		var edit = {
				action : 'edit',
				summary : summary,
				watchlist : (page.watchlist || 'preferences'),
				title : page.title,
				token : this.edittoken
		};

		edit[page.editType]=page.text;
		this.doAPICall( edit, callback );
	},

	/**
	* Get the page text.
	**/
	fetchPage : function (page, callback) {
		var query = {
				action : 'query',
				prop : 'revisions',
				rvprop : 'content',
				titles : page,
				indexpageids : '1'
		};
		this.doAPICall(query, callback);
	},

	deletePage : function (page, reason, callback)
	{
		var query = {
				action : 'delete',
				title : page,
				token : this.edittoken, //delete token is equal to edit token
				reason : reason
		};
		this.doAPICall(query, callback, true);
		//this[callback]();
	},

	extractPageText : function(res)
	{
		if (res.query.pageids[0] < 0) return ''; //no such page exists
		return res.query.pages[ res.query.pageids[0] ].revisions[0]['*'];
	},

	//Only for speedy deletion. Reporting for discussion obtains the token while performing other tasks.
	getEditToken : function () {
		var query = {
				action  : 'query',
				prop    : 'info|revisions',
				rvprop  : 'timestamp',
				intoken : 'edit',
				titles  : mw.config.get('wgPageName')
		};
		this.doAPICall( query, 'getEditTokenCB' );
	},

	getEditTokenCB : function (result) {
		var pages = result.query.pages;
		for (var id in pages) {  // there should be only one, but we don't know its ID

			// The edittoken only changes between logins
			this.edittoken=pages[id].edittoken;
			this.starttimestamp = pages[id].starttimestamp;
			this.timestamp = pages[id].revisions[0]['timestamp'];
		}

		this.updateProgress( this.i18n.preparingToEdit.replace('%COUNT%', '') );
		this.nextTask();
	},

	/**
	* Does a MediaWiki API request and passes the result to the supplied callback (method name).
	* Uses POST requests for everything for simplicity.
	* TODO: better error handling
	**/
	doAPICall : function ( params, callback, ignore_missing_title ) {
		var o = this;

		params.format='json';
		$.ajax( {
			url: this.apiURL,
			cache: false,
			dataType: 'json',
			data: params,
			type: 'POST',
			success: function(result, status, x) {
				if (!result) return o.fail( "Receive empty API response:\n" + x.responseText );

				// In case we get the mysterious 231 unknown error, just try again
				if (result.error && result.error.info.indexOf('231') != -1) return setTimeout(function() {
					o.doAPICall(params, callback);
				},500);
				if (result.error) {
					if (result.error.code != 'missingtitle' || !ignore_missing_title)
						return o.fail( "API request failed (" + result.error.code + "): " + result.error.info );
				}
				if (result.edit && result.edit.spamblacklist) return o.fail( "The edit failed because " +  result.edit.spamblacklist + " is on the Spam Blacklist");
				try {
					o[callback](result);
				}
				catch (e) {
					return o.fail(e);
				}
			},
			error: function(x, status, error) {
				return o.fail( "API request returned code " + x.status + " " + status + "Error code is " + error);
			}
		});
	},
	
	apiURL: mw.config.get('wgServer') + mw.config.get('wgScriptPath') + "/api.php",

	/**
	* Simple task queue.  addTask() adds a new task to the queue, nextTask() executes
	* the next scheduled task.  Tasks are specified as method names to call.
	**/
	tasks : [],  // list of pending tasks
	currentTask : '',  // current task, for error reporting
	addTask : function ( task ) {
		this.tasks.push( task );
	},
	nextTask : function () {
		var task = this.currentTask = this.tasks.shift();
		try {
			this[task]();
		}
		catch (e) {
			this.fail(e);
		}
	},

	/**
	* For display of progress messages.
	**/
	showProgress : function () {
		document.body.style.cursor = 'wait';

		$progress = $('<div id="del-req-progress"></div>')
			    .html('<div><div id="feedbackContainer">Szykuję się do edytowania...</div><div id="ajax-delete-warnings></div></div>')
		.dialog( {
			width: 600,
			height: 200,
			minHeight: 90,
			modal: false,
			resizable: false,
			draggable: false,
			closeOnEscape: false,
			dialogClass: "ajaxDeleteFeedback",
			close: function() {
				$(this).dialog("destroy");
				$(this).remove();
			}
		});
		$('.ui-dialog-titlebar').hide();

		this.nextTask();

	},

	updateProgress : function (message) {
		$('#feedbackContainer').html(message);
	},

	/**
      * Crude error handler. Just throws an alert at the user and (if we managed to
      * add the {delete} tag) reloads the page.
      **/
	fail : function ( err ) {
		document.body.style.cursor = 'default';
		var msg = this.i18n.taskFailure[this.currentTask] || this.i18n.genericFailure;
		var fix = '';//(this.templateAdded ? this.i18n.completeRequestByHand : this.i18n.addTemplateByHand );

		$('#feedbackContainer').html(msg + " " + fix + "<br>" + this.i18n.errorDetails + "<br>" + err + "<br><a href=" + mw.config.get('wgServer') + "/wiki/MediaWiki_talk:DelReqHandler.js>" + this.i18n.errorReport +"</a>");
		$('#feedbackContainer').addClass('ajaxDeleteError');

		// Allow some time to read the message
		if (this.templateAdded) setTimeout(function() {
			this.reloadPage(true);
		}, 5000);
	},

	there_are_warnings : false,
	addWarning : function(msg)
	{
		$('#ajax-delete-warnings').append('<p><b>UWAGA!</b> ' + msg + '</p>');
		this.there_are_warnings = true;
	},

	/**
	* Very simple date formatter.  Replaces the substrings "YYYY", "MM" and "DD" in a
	* given string with the UTC year, month and day numbers respectively.  Also
	* replaces "MON" with the English full month name and "DAY" with the unpadded day.
	**/
	formatDate : function ( fmt, date ) {
		var pad0 = function ( s ) {
			s = "" + s;
			return (s.length > 1 ? s : "0" + s);
		};  // zero-pad to two digits
		if (!date) date = this.startDate;
		if (!date) date = new Date();
		fmt = fmt.replace( /YYYY/g, date.getUTCFullYear() );
		fmt = fmt.replace( /MM/g, pad0( date.getUTCMonth()+1 ) );
		fmt = fmt.replace( /DD/g, pad0( date.getUTCDate() ) );
		fmt = fmt.replace( /MON/g, this.months[ date.getUTCMonth() ] );
		fmt = fmt.replace( /DAY/g, date.getUTCDate() );
		return fmt;
	},
	months : "styczeń luty marzec kwiecień maj czerwiec lipiec sierpień wrzesień październik listopad grudzień".split(" "),

	i18n : {
		// Errors
		preparingToEdit       : "Szykuję się do edytowania... ",
		genericFailure        : "Wystąpił błąd.",
		taskFailure : {
		},
		errorDetails          : "Szczegółowy opis błędu:",
		errorReport           : "Zgłoś nieprawidłowe działanie"
	}

}; // End of DelReqHandler

DelReqHandler.beginLoading();

})
// </nowiki>