Welcome to the DFO World Wiki. With many major updates since the release of DFO, many items are missing. Visit Item Database Project to learn more.
Please remember to click "show preview" before saving the page.
Thanks for the updated logo snafuPop!

MediaWiki:Gadget-dashboard.UndeletionRequester.js

From DFO World Wiki
Jump to: navigation, search

Note: After saving, you may have to bypass your browser's cache to see the changes.

  • Firefox / Safari: Hold Shift while clicking Reload, or press either Ctrl-F5 or Ctrl-R (⌘-R on a Mac)
  • Google Chrome: Press Ctrl-Shift-R (⌘-Shift-R on a Mac)
  • Internet Explorer: Hold Ctrl while clicking Refresh, or press Ctrl-F5
  • Opera: Go to Menu → Settings (Opera → Preferences on a Mac) and then to Privacy & security → Clear browsing data → Cached images and files.
/**
 **  Undeletion request helper for Wikimedia Commons
 **  @description
 **     Easily post undeletion requests
 **
 **  @autor Rillke, 2012
 **  @license GPL v.3
 **
 **  Adds an UI to [[Template:Dashboard/Widgets/Post undeletion request]].
 **  Also a dashboard widget.
 **
 **/
 
/*jshint curly:false, laxbreak:true */
/*global jQuery:false, mediaWiki:false*/

// Invoke automated jsHint-validation on save: A feature on WikimediaCommons
// Interested? See [[:commons:MediaWiki:JSValidator.js]].

// <nowiki>
(function($, mw, undefined) {
'use strict';

$(function() {
mw.loader.using([
	'jquery.ui.dialog', 
	'ext.gadget.AjaxQuickDelete',
	'mediawiki.util'
], function() {

// utility method: Should be moved out into some global site code since used everywhere
$.createIcon = function (iconClass) {
	return $('<span>', { 'class': 'ui-icon ' + iconClass + ' ajaxInlineIcon', text: ' ' });
};

mw.util.addCSS(
		'.undelete-item { margin:0.5em; padding:4px; }\n'
	+	'.undelete-item-heading { padding:4px; }\n'
	+	'.undelete-option-details { padding-left:4px; }\n'
	+	'.undelete-recycle { background: url(//upload.wikimedia.org/wikipedia/commons/4/47/Crystal_Clear_mimetype_recycled.png) no-repeat center }\n'
	+	'#AjaxUndeleteItems { border: 1px dotted #55a; max-height:350px; min-height:200px; overflow:auto; background-color:#fff; }\n'
	+	'#AjaxUndeleteOptions { min-height:125px; border: 1px dotted #55a; margin-top:0.5em; }\n'
);

var AQD, udh;

var __onRemoveClick = function() {
	var $el = $(this).parents('.undelete-item');
	AQD.secureCall('uRmPageItem', $el);
	$el.remove();
};

// Just some HTML
var $uC = $('<div>').attr({ id: 'AjaxUndeleteContainer', title: "Request undeletion of deleted pages and files – Recycling protects the environment" }),
	$uO_desc = $('<p>', { text: "Add items to the list of pages to be restored by" }).appendTo($uC),
	$uO = $('<div>').attr({ id: 'AjaxUndeleteOptions' }).appendTo($uC),
	$uI_desc = $('<p>', { text: "Pages that should be restored:" }).appendTo($uC),
	$uI = $('<div>').attr({ id: 'AjaxUndeleteItems', 'class': 'undelete-recycle', title: "Add pages or files using the controls above." }).appendTo($uC),
	// Options
	$uOI = $('<div>').attr({ id: 'AjaxUndeleteOptionInput' }).appendTo($uO),
	$uOU = $('<div>').attr({ id: 'AjaxUndeleteOptionUploader' }).appendTo($uO),
	$uOD = $('<div>').attr({ id: 'AjaxUndeleteOptionDeleter' }).appendTo($uO),
	// Construct Option UI
	// direct input
	$uOI_r = $('<input name="undelAddOption" id="optionInputOption" type="radio" checked="checked" value="page" />').appendTo($uOI),
	$uOI_rl = $('<label>').attr({ 'for': 'optionInputOption' }).text('File name or URL').appendTo($uOI),
	$uOI_d = $('<div>').attr({ 'class': 'undelete-option-details' }).appendTo($uOI),
	$uOI_t = $('<input>').attr({ type: 'text', size: 70, maxlength: 500, placeholder: 'Full page name or URL of the page or file to restore' }).appendTo($uOI_d),
	$uOI_b = $('<button>').text("Add").button({ icons: { primary: 'ui-icon-circle-plus' } }).appendTo($uOI_d),
	// uploader
	$uOU_r = $('<input name="undelAddOption" id="optionUploaderOption" type="radio" value="uploader"/>').appendTo($uOU),
	$uOU_rl = $('<label>').attr({ 'for': 'optionUploaderOption' }).text('Uploader').appendTo($uOU),
	$uOU_d = $('<div>').attr({ 'class': 'undelete-option-details' }).css('display', 'none').appendTo($uOU),
	$uOU_t = $('<input>').attr({ type: 'text', size: 20, maxlength: 100, placeholder: 'Uploader (user name)' }).appendTo($uOU_d),
	$uOU_df = $('<input>').attr({ type: 'text', size: 20, maxlength: 20, placeholder: 'From YYYY-MM-DD' }).appendTo($uOU_d),
	$uOU_dt = $('<input>').attr({ type: 'text', size: 20, maxlength: 20, placeholder: 'To YYYY-MM-DD' }).appendTo($uOU_d),
	$uOU_b = $('<button>').text("Add").button({ icons: { primary: 'ui-icon-circle-plus' } }).appendTo($uOU_d),
	// deleter
	$uOD_r = $('<input name="undelAddOption" id="optionDeleterOption" type="radio" value="deleter"/>').appendTo($uOD),
	$uOD_rl = $('<label>').attr({ 'for': 'optionDeleterOption' }).text('Deleting Administrator').appendTo($uOD),
	$uOD_d = $('<div>').attr({ 'class': 'undelete-option-details' }).css('display', 'none').appendTo($uOD),
	$uOD_t = $('<input>').attr({ type: 'text', size: 20, maxlength: 100, placeholder: 'Deleting administrator' }).appendTo($uOD_d),
	$uOD_df = $('<input>').attr({ type: 'text', size: 20, maxlength: 20, placeholder: 'From YYYY-MM-DD' }).appendTo($uOD_d),
	$uOD_dt = $('<input>').attr({ type: 'text', size: 20, maxlength: 20, placeholder: 'To YYYY-MM-DD' }).appendTo($uOD_d),
	$uOD_b = $('<button>').text("Add").button({ icons: { primary: 'ui-icon-circle-plus' } }).appendTo($uOD_d),
	// reason
	$uR = $('<textarea>', { text: "Reason: ", rows: 4, css: { width: '99%' }, title: "Fill in the reason: Why should these pages be restored?" }).appendTo($uC),
	$uR_ParseL = $('<span>', { text: "Preview:" }).appendTo($uC),
	$uR_Parse = $('<div>').attr({ id: 'AjaxQuestionParse' }).appendTo($uC),
	
	// Templates for page items
	$uIT = $('<div>').attr({ 'class': 'undelete-item ui-widget ui-widget-content ui-helper-clearfix ui-corner-all' }),
	$uITH = $('<div>').attr({ 'class': 'undelete-item-heading ui-widget-header ui-corner-all' }).appendTo($uIT),
	$uITC = $('<div>').attr({ 'class': 'undelete-item-content' }).appendTo($uIT),
	$rmBtn = $('<button>').text("Remove").css('float', 'right'); // We can't append it right now because when removing parent and attempting to add a new item button style is gone.

	
udh = window.undeleteHelper = {
	uVersion: '0.0.4.0',
	uPagesToRestore: {},
	uRmPageItem: function($item) {
		delete this.uPagesToRestore[$item.data('udh_name')];
	},
	uAddPageItem: function(pagename, content, uploader, deleter) {
		pagename = pagename.replace(/_/g, ' ');
		if (pagename in this.uPagesToRestore) {
			var $item = this.uPagesToRestore[pagename].ui;
			$uI.stop().clearQueue().animate({scrollTop: $item.position().top - $uI.position().top}, 600);
			udh.hIfEmpty(this.uPagesToRestore[pagename].ui, '', 1);
			return;
		}
		var pg = this.uPagesToRestore[pagename] = {
			content: content,
			uploader: uploader,
			deleter: deleter,
			ui: $uIT.clone().find('.undelete-item-heading').text(pagename).append($rmBtn.clone().button({ icons: { primary: 'ui-icon-circle-minus' } }).click(__onRemoveClick)).parent().find('.undelete-item-content').text(content).parent().attr('title', pagename).data('udh_name', pagename)
		};
		$uI.append(pg.ui);
		
		var __onContentParsed = function(r) {
			if (pg && pg.ui) pg.ui.find('.undelete-item-content').text('').append(r);
		};
		mw.libs.commons.api.parse(content, mw.config.get('wgUserLanguage'), mw.config.get('wgPageName'), __onContentParsed);
	},
	uFormatTimestamp: function(t) {
		return '{{ISOdate|' + t.replace(/T/, ' ').replace(/Z/, '') + '}}';
	},
	uBindEvents: function() {
		// Autocomplete
		var nsUser = mw.config.get('wgFormattedNamespaces')[2],
			rxUser = new RegExp('^' + nsUser + ':', 'i'),
			lastXHR = 0,
			pLastCB = 0,
			delayXHR = 500;
	
		var didXHR = function(result, pCallback) {
			var searchTerms = [];
			if (!result) {
				if ('function' === typeof pCallback) pCallback(searchTerms);
				return;
			}
			result = result.query.allusers;
			$.each(result, function(id, it) {
				searchTerms.push( { 'value': (it.name || it['*']) } );
			});
			if ('function' === typeof pCallback) pCallback(searchTerms);
			pLastCB = 0;
		};
		var doXHR = function(request, pCallback) {
			var queryU = {
				action: 'query',
				format: 'json',
				list: 'allusers',
				auprefix: request.term.replace(rxUser, '')
			};
			lastXHR = $.getJSON( mw.util.wikiScript('api'), queryU, function(r) { didXHR(r, pCallback); });
		};
		var __autocomplete = {
			minLength: 1,
			delay: delayXHR,
			select: function(event, ui) {
				var _this = this;
				setTimeout(function() {
					$(_this).triggerHandler('change');
				}, 10);
			},
			source: function ( request, callback ) { 
				if (pLastCB) pLastCB([]);
				pLastCB = callback;
				if (lastXHR) lastXHR.abort();
				delayXHR += 100;
				doXHR(request, callback);
			}
		};
		$uOU_t.autocomplete(__autocomplete).placeholder();
		$uOD_t.autocomplete(__autocomplete).placeholder();
		
		// Option Accordion
		var __optionChange = function() {
			if (this !== $uOI_r[0]) $uOI_d.slideUp();
			if (this !== $uOU_r[0]) $uOU_d.slideUp();
			if (this !== $uOD_r[0]) $uOD_d.slideUp();
			$(this).parent().find('.undelete-option-details').slideDown();
		};
		$uOI_r.change(__optionChange);
		$uOU_r.change(__optionChange);
		$uOD_r.change(__optionChange);
		
		// Date pickers an tipsy
		$.datepicker.setDefaults( $.datepicker.regional[ mw.config.get('wgUserLanguage') ] );
		var __datepicker = {
			changeYear: true,
			changeMonth: true,
			'dateFormat': 'yy-mm-dd 12:00:00',
			showWeek: true,
			firstDay: 1
		};
		var __tipsy = {
			trigger: 'focus',
			gravity: 's',
			html: true,
			title: function() {
				return "Format:  YYYY-MM-DD<br/> or, optionally<br/>YYYY-MM-DD&nbsp;hh:mm:ss<br/>or use the picker";
			}
		};
		$uOU_df.datepicker(__datepicker).tipsy(__tipsy).placeholder();
		$uOU_dt.datepicker(__datepicker).tipsy(__tipsy).placeholder();
		$uOD_df.datepicker(__datepicker).tipsy(__tipsy).placeholder();
		$uOD_dt.datepicker(__datepicker).tipsy(__tipsy).placeholder();
		
		// The "Add Buttons"
		$uOI_b.click(function() { udh.secureCall('uAddDirect'); });
		$uOU_b.click(function() { udh.secureCall('uAddFromUploadLog'); });
		$uOD_b.click(function() { udh.secureCall('uAddFromDeletionLog'); });
		
		var handleKey = function(e, $toClick, self) {
			if (13 === e.which) { 
				$toClick.click(); 
			}
			var oldVal = self.value,
				newVal = udh.uCleanTitle(oldVal);
			if (oldVal !== newVal) self.value = newVal;
		};
		// Input fields
		$uOI_t.keyup(function(e) { handleKey(e, $uOI_b, this); });
		$uOU_t.keyup(function(e) { handleKey(e, $uOU_b, this); });
		$uOD_t.keyup(function(e) { handleKey(e, $uOD_b, this); });
		
		// Reason parsing
		$uR_ParseL.text(this.i18n.previewLabel);
		var oldVal = '';
		$uR.bind('input keyup', function() {
			var $el = $(this),
				val = $el.val();
			if (val === oldVal) return;
			oldVal = val;
         
			$uR_Parse.css('color', '#877');
			
			var __gotParsedText = function(r) {
				$uR_Parse.html(r);
				$uR_Parse.css('color', '#000');
			};
			mw.libs.commons.api.parse(val, mw.config.get('wgUserLanguage'), mw.config.get('wgPageName'), __gotParsedText);
		});
	},
	uCleanTitle: function(txt) {
		return $.trim($.ucFirst(txt));
	},
	uAddDirect: function() {
		var pg = $uOI_t.val();
		if (!pg || 0 === $.trim(pg).length) {
			if (!udh.hIfEmpty($uOI_t, '', 1)) return;
		}
		if (pg.indexOf('//')) {
			var t = mw.util.getParamValue('page', pg);
			if (!t) t = mw.util.getParamValue('title', pg);
			if (t) {
				pg = t;
				try {
					pg = decodeURIComponent(pg);
				} catch (ex) {
				}
			} else {
				try {
					pg = decodeURI(pg);
				} catch (ex) {
				}
				var RE_Page = new RegExp($.escapeRE(mw.config.get('wgServer') + mw.config.get('wgArticlePath')).replace('\\$1', '(.+)'));
				var m = pg.match(RE_Page);
				if (m && m[1]) pg = m[1];
				pg = pg.replace(/#.+$/, '');
			}
		}
		pg = $.trim(pg.replace(/[\|_]/g, ' ').replace(/[\]\}>]/g, ')').replace(/[\[\{<]/g, '('));
		$uOI_t.val(pg);
		
		$uOI_d.block({ message: $.createSpinner() });
		udh.queryAPI({
			action: 'query',
			list: 'logevents',
			letitle: pg,
			lelimit: 500
		}, 'uAddDirectCB');
	},
	uAddDirectCB: function(r) {
		var deleter,
			uploader,
			title,
			comment;

		var _onFunctionExit = function() {
			if (udh.cbAfterItemAdded) udh.secureCall(udh.cbAfterItemAdded);
			delete udh.cbAfterItemAdded;
		};
		$.each(r.query.logevents, function(i, le) {
			if (le.title) title = le.title;
			if (!deleter && 'delete' === le.action) {
				deleter = le.user;
				comment = "was deleted by [[User:" + le.user + "|]] on " + udh.uFormatTimestamp(le.timestamp) + " because ''" + le.comment + "''";
			}
			if ('upload' === le.action) uploader = le.user;
		});
		$uOI_d.unblock();
		if (!deleter) {
			var __hideTipsy = function() {
				$uOI_t.tipsy('hide');
			};
			var t = $uOI_t.val(),
				m = t.match(/\.(\S{2,5})$/),
				extAllowed = !!(m && m[1] && (-1 !== $.inArray(m[1].toLowerCase(), mw.config.get('wgFileExtensions'))));
				
			if (extAllowed && !/^(?:[Ff]ile|[Ii]mage):/.test(t)) {
				$uOI_t.val('File:' + t);
				return this.uAddDirect();
			} else {
				var text = (title || t || "This page") + " <b>was never deleted</b>. Namespace and file extension (e.g. <b>File:</b>Example<b>.jpg</b>) must be included.";
				if (m && m[1] && !extAllowed) text = text + " <i>" + m[1] + "</i> is not an accepted file format on Commons.";
				$uOI_t.attr('title', text).tipsy({
					gravity: 'sw',
					html: true,
					trigger: 'manual',
					fade: true
				}).blur(__hideTipsy);
				$uOI_t.tipsy('show');
				setTimeout(__hideTipsy, 20000);
				udh.hIfEmpty($uOI_t, '', 1);
				return _onFunctionExit();
			}
		}
		if (uploader) {
			comment = comment + " and was uploaded by [[User:"  + uploader + "|]]";
		}
		this.uAddPageItem(title, comment, uploader, deleter);
		_onFunctionExit();
	},
	getMwDate: function(dateX) {
		var mwDateRx = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z$/;
		if ('string' !== typeof dateX) return dateX;
		if (mwDateRx.test(dateX)) return dateX;
		var m1 = dateX.match(/(\d{4}).(\d{2}).(\d{2})\D*(\d{2}:\d{2}:\d{2})?/);
		if (m1) return (m1[1] + '-' + m1[2] + '-' + m1[3] + 'T' + (m1[4] ? m1[4] : '12:00:00') + 'Z');
		m1 = dateX.match(/(\d{2}).(\d{2}).(\d{4})\D*(\d{2}:\d{2}:\d{2})?/);
		if (m1) return (m1[3] + '-' + m1[2] + '-' + m1[1] + 'T' + (m1[4] ? m1[4] : '12:00:00') + 'Z');
		else return '';
	},
	uAddFromUploadLog: function() {
		this.udhDoesUserExist($uOU_t, 'uQueryUploadLog');
	},
	uQueryUploadLog: function(uploader) {
		var query = {
			action: 'query',
			list: 'logevents',
			letype: 'upload',
			leuser: uploader,
			ledir: 'newer',
			lelimit: 100
		};
		var fromDate = this.getMwDate($uOU_df.val());
		var toDate = this.getMwDate($uOU_dt.val());
		if (fromDate) query.lestart = fromDate;
		if (toDate) query.leend = toDate;
		$uOU_d.block({ message: $.createSpinner() });
		this.queryAPI(query, 'uQueryUploadLogCB');
	},
	uQueryUploadLogCB: function(r) {
		$.each(r.query.logevents, function(i, le) {
			if (!le.pageid) udh.uAddPageItem(le.title, 'uploaded on ' + udh.uFormatTimestamp(le.timestamp) + ' by ' + le.user, le.user);
		});
		$uOU_d.unblock();
	},
	uAddFromDeletionLog: function() {
		this.udhDoesUserExist($uOD_t, 'uQueryDeletionLog');
	},
	uQueryDeletionLog: function(deleter) {
		var query = {
			action: 'query',
			list: 'logevents',
			letype: 'delete',
			leuser: deleter,
			ledir: 'newer',
			lelimit: 100
		};
		var fromDate = this.getMwDate($uOD_df.val());
		var toDate = this.getMwDate($uOD_dt.val());
		if (fromDate) query.lestart = fromDate;
		if (toDate) query.leend = toDate;
		$uOD_d.block({ message: $.createSpinner() });
		this.queryAPI(query, 'uQueryDeletionLogCB');
	},
	uQueryDeletionLogCB: function(r) {
		$.each(r.query.logevents, function(i, le) {
			if (!le.pageid) udh.uAddPageItem(le.title, 'deleted on ' + udh.uFormatTimestamp(le.timestamp) + ' by ' + le.user + ' because ' + le.comment, undefined, le.user);
		});
		$uOD_d.unblock();
	},
	udhDoesUserExist: function($el, cb) {
		var u = $.trim($el.val());
		if (!this.hIfEmpty($el, u, 1)) return;
		u = $.ucFirst(u);
		$el.val(u);
		
		udh.queryAPI({
			action: 'query',
			list: 'allusers',
			aufrom: u,
			auto: u,
			lelimit: 1
		}, function(r) {
			if (!udh.hIfEmpty($el, r.query.allusers, 1)) return;
			udh.secureCall(cb, u);
		});
	},
	udhCheckRequest: function() {
		if ($uOI_r[0].checked && $uOI_t.val().length) {
			udh.cbAfterItemAdded = 'udhPrepareRequest';
			$uOI_b.click();
			return;
		}
		udh.secureCall('udhPrepareRequest');
	},
	udhPrepareRequest: function() {
		if (!udh.hIfEmpty($uR, $uR.val(), 10)) return;
		if (!udh.hIfEmpty($uO, $uI.find('.undelete-item'), 1)) return;
	
		// 1) Guess a good heading
		var maxCount = 0,
			heading,
			uploaders = {},
			deleter = {};

		$.each(this.uPagesToRestore, function(pgName, details) {
			maxCount++;
			heading = pgName;
			if (details.uploader && ('number' !== typeof uploaders[details.uploader])) {
				uploaders[details.uploader] = 0;
			} else {
				uploaders[details.uploader]++;
			}
			if (details.deleter && ('number' !== typeof deleter[details.deleter])) {
				deleter[details.deleter] = 0;
			} else {
				deleter[details.deleter]++;
			}
		});
		if (maxCount < 4) return this.secureCall('udhSendRequest', heading);
		maxCount = 0;
		$.each(uploaders, function(uName, count) {
			if (count > maxCount) {
				maxCount = count;
				heading = "Files uploaded by " + uName;
			}
		});
		$.each(deleter, function(dName, count) {
			if (count > maxCount) {
				maxCount = count;
				heading = "Files deleted by " + dName;
			}
		});
		this.secureCall('udhSendRequest', heading);
	},
	udhSendRequest: function(heading) {
		// mw.libs.commons.api.getCurrentDate()
		var plainHeading = heading,
			clickableHeading = /^(File:|Category:)/.test(heading) ? ('[[:' + heading + ']]') : heading,
			text = "\n== " + clickableHeading + " ==\n" + '<!-- x-origin: ' + mw.config.get('wgPageName') + ' -->' + "Please restore the following pages: ";
			
		$.each(this.uPagesToRestore, function(pgName, details) {
			if (/^File:/i.test(pgName)) {
				text += '\n* {{Il|1=' + pgName.replace(/^File:/i, '') + "}}";
			} else {
				text += '\n* [[' + pgName.replace(/^Category:/i, ':Category:') + ']]';
			}
		});
		
		text += "\nReason: " + this.cleanReason($uR.val()).replace(/^Reason:? ?/i, '') + " ~~~~";
		
		var page = {
			title: this.udhPage,
			text: text,
			editType: 'appendtext',
			watchlist: 'watch'
		};
		this.uPlainHeading = plainHeading;
		this.showProgress("Posting undeletion request");
		this.savePage(page, "([[MediaWiki:Gadget-dashboard.UndeletionRequester.js|Script]]): Posting undeletion request [[#" + plainHeading + "]]", 'udhRequestComplete');
	},
	udhRequestComplete: function() {
		this.showProgress();
		var dlgButtons = {};
		dlgButtons['Ok – Show my request!'] = function() {
			window.location.href = mw.config.get('wgServer') + 
				mw.config.get('wgArticlePath').replace('$1', udh.udhPage.replace(/ /g, '_')) + "?x=" + Math.random() + 
				"#footer";
		};
		$uC.text("Your request for restoration was successfully posted. Please check back regularly for answering questions.").dialog({ buttons: dlgButtons, title: "Request posted successfully – Please watch your request" });
	},
	hIfEmpty: function($el, l, minLen) {
		if (l.length < minLen) {
			$el.addClass('ui-state-error');
			setTimeout(function() {
				$el.removeClass('ui-state-error');
			}, 2000);
			return false;
		}
		return true;
	},
	udhShowDlg: function() {
		$uC.dialog('open');
	},
	udhInstall: function() {
		var dlgButtons = {};
		dlgButtons["Request undeletion"] = udh.udhCheckRequest;
		
		if (mw.user.isAnon()) {
			var $logInNode = $('#pt-login');
			if (!$logInNode.length) return;
			dlgButtons[$logInNode.text() || 'LogIn'] = function() {
				var logInLink = ($logInNode.find('a').length ? $logInNode.find('a').attr('href') : $logInNode.attr('href')) || mw.util.wikiScript() + '?' + $.param({ title: 'Special:UserLogin', returnto: mw.config.get('wgPageName') });
				window.location = logInLink;
			};
		}
		
		var dlgWidth = Math.min(600, $(window).width() - 250);
		$uC.dialog({
			modal: true,
			autoOpen: false,
			width: dlgWidth,
			buttons: dlgButtons,
			create: function() {
				var $buttons = $(this).parent().find('.ui-dialog-buttonpane button'),
					$submitButton = $buttons.eq(0).button({ icons: { primary: 'ui-icon-circle-check' } }).addClass('ui-button-green'),
					$logInButton = $buttons.eq(1).button({ icons: { primary: 'ui-icon-key' } }).addClass('ui-button-orange'),
					$feedback = $('<a>', { href: mw.util.getUrl('Commons talk:Undeletion requests') + '#Tool_feedback', target: '_blank', text: "Constructive comments/feedback appreciated" });
				$(this).parent().find('.ui-dialog-buttonpane').append($feedback);
			}
		});
		mw.loader.using([
			'ext.gadget.libAPI', 
			'ext.gadget.jquery.blockUI', 
			'jquery.ui.autocomplete', 
			'jquery.ui.datepicker', 
			'jquery.placeholder',
			'jquery.spinner', 
			'jquery.tipsy'
		], function() {
			udh.secureCall('uBindEvents');
			$(document).triggerHandler('scriptLoaded', ['undeleteHelper']);
		});
	},
	udhPage: 'Commons:Undeletion requests/Current requests',
	
	/**
	*  Implement Commons Dashboard Widget interface
	*  @dashboardwidgetinterface
	**/
	$getUI: function() {
		var $btn = $('<button>', { 'class': 'ui-button-large ui-button-blue' }).text("Request undeletion tool").button();
		$btn.find('.ui-button-text').prepend($('<div>', { css: { height: '128px', width: '128px' }, 'class': 'undelete-recycle' }));
		$btn.click(udh.udhShowDlg);
		return $btn;
	},
	createUI: function() {
		$('#udhContainer').text('').append(udh.$getUI());
	}
};

AQD = window.AjaxQuickDelete;
$.extend(AQD, window.undeleteHelper);
window.undeleteHelper = AQD;
udh = AQD;
udh.secureCall('createUI');
udh.secureCall('udhInstall');
		
}); // mw.loader.using
}); // $(document).ready()
	
})(jQuery, mediaWiki);
// </nowiki>