Użytkownik:Expert3222/quickPatrol.js: Różnice pomiędzy wersjami

Z Nondanych
m
 
(Nie pokazano 61 pośrednich wersji utworzonych przez tego samego użytkownika)
Linia 4: Linia 4:
* drobne modyfikacje, backend: Ostrzyciel
* drobne modyfikacje, backend: Ostrzyciel
*/
*/

// TODO: $(this) na $this (do zmiennej), lepsza wydajność będzie


mw.loader.load('/wiki/Użytkownik:Expert3222/patrolModule.js?action=raw&ctype=text/javascript');
mw.loader.load('/wiki/Użytkownik:Expert3222/patrolModule.js?action=raw&ctype=text/javascript');


var patrolSuccessCode = "<span style='color: green;' class='patrolButtonClicked'><img src='https://nonsa.pl/images/2/26/Za.svg.png' width='15px' height='15px' />&nbsp;zrobione</span>";
var spinnerCode = "<div class='mw-spinner mw-spinner-small mw-spinner-inline' title='...'></div>";
var patrolFailureCode = "<span style='color: red;' class='patrolButtonClicked'><img src='https://nonsa.pl/images/a/a8/Przeciw.svg.png' width='15px' height='15px' />&nbsp;błąd</span>";

var tryAgainText = "spróbuj ponownie";
var RCPatrolSuccessCode = "<span style='color: green;' class='patrolButtonClicked'><img src='https://nonsa.pl/images/2/26/Za.svg.png' width='15px' height='15px' />&nbsp;zrobione</span>";
var RCPatrolFailureCode = "<span style='color: red;' class='patrolButtonClicked'><img src='https://nonsa.pl/images/a/a8/Przeciw.svg.png' width='15px' height='15px' />&nbsp;błąd</span>";

var RCMultiplePatrolSuccessCode = "<span style='color: green;' class='multiplePatrolButtonClicked'><img src='https://nonsa.pl/images/2/26/Za.svg.png' width='15px' height='15px' />&nbsp;zrobione</span>";
var RCMultiplePatrolFailureCode = "<span style='color: red;' class='multiplePatrolButtonClicked'><img src='https://nonsa.pl/images/a/a8/Przeciw.svg.png' width='15px' height='15px' />&nbsp;błąd</span>";


$(document).ready(function()
$(document).ready(function()
Linia 23: Linia 17:
if (mw.config.get("wgCanonicalSpecialPageName") === "Recentchanges")
if (mw.config.get("wgCanonicalSpecialPageName") === "Recentchanges")
{
{
makePatrolButtons();
makePatrolLinks();
if (!!$('.mw-rcfilters-enabled').length) //wzięte od Polskacafe z gadżetu RollWithReason
if (!!$('.mw-rcfilters-enabled').length) //wzięte od Polskacafe z gadżetu RollWithReason
{
{
setInterval(makePatrolButtons, 2000);
setInterval(makePatrolLinks, 2000);
}
}
}
}
Linia 39: Linia 33:
else if (mw.util.getParamValue("diff") !== null)
else if (mw.util.getParamValue("diff") !== null)
{
{
makeDiffPagePatrolLinks();
makeDiffPagePatrolButtons();
setInterval(makeDiffPagePatrolButtons, 2000); //"przeglądaj historię interaktywnie" na górze
setInterval(makeDiffPagePatrolLinks, 2000); //"przeglądaj historię interaktywnie" na górze
}
}
else if ($(".patrollink").length > 0) //footer
else if ($(".patrollink").length > 0) //footer
{
{
$(".patrollink-page a").off("click").click(function() //remove default click handler and attach our own
$(".patrollink-page a").off("click").click(function(event) //remove default click handler and attach our own
{
{
event.preventDefault();
event.stopImmediatePropagation();
processPagePatrol($(this).parent());
processPagePatrol($(this).parent());
});
});
Linia 66: Linia 62:
});
});


function makePatrolButtons()
function makePatrolLinks()
{
{
$(".patrollink-range a").each(function()
$(".patrollink-range a").each(function()
{
{
var $tbody = goUpUntilTag($(this), "tbody");
var $link = $(this);
var $link = $(this);
if (!isEventBound($link))
var lines = $tbody.find("tr");
var firstLine = $(lines).first();
if ($(firstLine).find(".multiplePatrolButtonClicked").length === 0)
{
{
if (!isEventBound($link))
var $tbody = getParentTag($link, "tbody");
$link.on("click", function()
{
{
processMultipleChangeRCPatrol($tbody);
$link.on("click", function()
{
});
processMultipleChangeRCPatrol($tbody);
});
}
}
}
});
});


var $button = $(".patrollink-single a");
$(".patrollink-single a").each(function()
if (!isEventBound($button))
{
{
$button.on("click", function()
var $button = $(this);
if (!isEventBound($button))
{
{
$button.on("click", function()
processRCChangePatrol($(this).parent());
});
{
processRCChangePatrol($(this).parent(), true);
}
});
}
});
}
}


Linia 99: Linia 93:
function processMultipleChangeRCPatrol($tbody)
function processMultipleChangeRCPatrol($tbody)
{
{
var deferred = $.Deferred(),
var $button = $tbody.find(".patrollink-range"),
$patrolLink = $button.find("a"),
failureCount = 0,
$singlePatrolLinks = $tbody.find(".patrollink-single a"),
successCount = 0,
$spinner = $.createSpinner({ size: 'small', type: 'inline' }),
$patrolLink = $tbody.find(".patrollink-range a"),
$buttons = $tbody.find(".patrollink-single"),
$patrolAgainBrackets = $patrolLink.parent().find(".patrolAgainBracket");
buttonsCount = $buttons.length,
$spinner = $.createSpinner({ size: 'small', type: 'inline' });
console.dir($patrolLink);
$patrolLink.hide();
$patrolLink.hide();
$patrolAgainBrackets.hide();
$patrolLink.after($spinner);
$patrolLink.after($spinner);
$patrolLink.parent().find(".multiplePatrolButtonClicked").remove();
$patrolLink.parent().find(".patrolButtonClicked").remove();
patrolModule.patrolRangeOfChanges($patrolLink.attr("data-revision-max")).done(function(data)
$buttons.each(function()
{
{
removeSpinner($button);
processRCChangePatrol($(this))
.done(function()
$patrolLink.after(patrolSuccessCode);
$patrolLink.remove();
$patrolAgainBrackets.remove();
var title = new mw.Title(data["fmod-patrol"].title);
mw.notify( mw.msg( 'markedaspatrollednotifymulti', title.toText() ) );
//replace single buttons with success text
$singlePatrolLinks.replaceWith(patrolSuccessCode);
//remove patrol exclamation marks
$tbody.find("abbr.unpatrolled").replaceWith("&nbsp;");
}).fail(function() {
removeSpinner($button);
if ($patrolAgainBrackets.length === 0)
{
{
$patrolLink.before(patrolFailureCode);
++successCount;
$patrolLink.before("<span class='patrolAgainBracket'> (</span>");
}).fail(function()
$patrolLink.after("<span class='patrolAgainBracket'>)</span>");
}
else
{
{
$patrolAgainBrackets.first().before(patrolFailureCode);
++failureCount;
$patrolAgainBrackets.show();
}).always(function()
{
}
$patrolLink.text(tryAgainText);
$spinner.remove();
$patrolLink.show();
if (successCount == buttonsCount && typeof debugActive == "undefined") //wszystkie wywołania AJAX do patrolowania zakończyły się pomyślnie
{
mw.notify( mw.msg( 'markedaspatrollederrornotify' ), { type: 'error' } );
deferred.resolve(successCount, failureCount);
$patrolLink.after(RCMultiplePatrolSuccessCode);
$patrolLink.remove();
$tbody.find("tr:first-child abbr.unpatrolled").replaceWith("&nbsp;");
}
else if (successCount + failureCount == buttonsCount) //wszystkie zakończyły się, niekoniecznie pomyślnie
{
deferred.reject(successCount, failureCount);
$patrolLink.after(RCMultiplePatrolFailureCode);
$patrolLink.show();
}
});
});
});
/*if (buttonsCount == 0)
{
multiplePatrolButton.replaceWith("<span><img src='https://nonsa.pl/images/2/26/Za.svg.png' width='15px' height='15px' />&nbsp;<span style='color: green;' class='multiplePatrolButtonClicked'>zrobione</span></span>");
$tbody.find("tr:first-child abbr.unpatrolled").replaceWith("&nbsp;");
}*/
return deferred.promise();
}
}


Linia 154: Linia 144:
function processRCChangePatrol($button)
function processRCChangePatrol($button)
{
{
var deferred = $.Deferred();
var $patrolLink = $button.find("a"),
var revid = $button.find("a").attr("data-revision");
revid = $patrolLink.attr("data-revision"),
$spinner = $.createSpinner({ size: 'small', type: 'inline' }),
$button.find("a").replaceWith(spinnerCode);
$patrolAgainBrackets = $button.find(".patrolAgainBracket");
$patrolLink.hide();
$patrolAgainBrackets.hide();
$patrolLink.after($spinner);
$patrolLink.parent().find(".patrolButtonClicked").remove();
patrolModule.resetLastClick();
patrolModule.resetLastClick();
patrolModule.patrolChange(revid).done(function()
patrolModule.patrolChange(revid).done(function(data)
{
{
removeSpinner($button);
$button.find("div").replaceWith(RCPatrolSuccessCode);
goUpUntilTag($button, "tr").find("abbr.unpatrolled").replaceWith("&nbsp;");
$patrolLink.after(patrolSuccessCode);
deferred.resolve();
$patrolLink.remove();
$patrolAgainBrackets.remove();
getParentTag($button, "tr").find("abbr.unpatrolled").replaceWith("&nbsp;");
var title = new mw.Title(data["fmod-patrol"].title);
mw.notify( mw.msg( 'markedaspatrollednotify', title.toText() ) );
}).fail(function()
}).fail(function()
{
{
removeSpinner($button);
$button.find("div").replaceWith(RCPatrolFailureCode);
deferred.reject();
if ($patrolAgainBrackets.length === 0)
{
$patrolLink.before(patrolFailureCode);
$patrolLink.before("<span class='patrolAgainBracket'> (</span>");
$patrolLink.after("<span class='patrolAgainBracket'>)</span>");
}
else
{
$patrolAgainBrackets.first().before(patrolFailureCode);
$patrolAgainBrackets.show();
}
$patrolLink.text(tryAgainText);
$patrolLink.show();
mw.notify( mw.msg( 'markedaspatrollederrornotifychange' ), { type: 'error' } );
});
});
return deferred.promise();
}
}


function processPagePatrol($button)
function processPagePatrol($button)
{
{
//diff page, new pages and any new page on the bottom
var pageid = $button.find("a").attr("data-pageid");
$button.find("a").replaceWith(spinnerCode);
var pageid = $button.find("a").attr("data-pageid"),
$patrolLink = $button.find("a"),
$spinner = $.createSpinner({ size: 'small', type: 'inline' }),
$patrolAgainBrackets = $button.find(".patrolAgainBracket");
$patrolLink.hide();
$patrolAgainBrackets.hide();
$patrolLink.after($spinner);
$patrolLink.parent().find(".patrolButtonClicked").remove();
patrolModule.resetLastClick();
patrolModule.resetLastClick();
patrolModule.patrolPage(pageid).done(function()
patrolModule.patrolPage(pageid).done(function(data)
{
{
removeSpinner($button);
$button.find("div").replaceWith(RCMultiplePatrolSuccessCode);
}).fail(function(error)
$patrolLink.after(patrolSuccessCode);
$patrolLink.remove();
$patrolAgainBrackets.remove();
// if we are on diff page remove range patrol button, because we just patrolled all page revisions
$(".patrollink-range a").replaceWith(patrolSuccessCode);
//if we are on Special:Newpages change background to match patrolled
if (mw.config.get("wgCanonicalSpecialPageName") == "Newpages")
{
getParentTag($button, "li").removeClass("not-patrolled");
}
var title = new mw.Title(data["fmod-patrol"].title);
mw.notify( mw.msg( 'markedaspatrollednotifypage', title.toText() ) );
}).fail(function()
{
{
removeSpinner($button);
console.log(error);
$button.find("div").replaceWith(RCMultipleFailureSuccessCode);
if ($patrolAgainBrackets.length === 0)
{
$patrolLink.before(patrolFailureCode);
$patrolLink.before("<span class='patrolAgainBracket'> (</span>");
$patrolLink.after("<span class='patrolAgainBracket'>)</span>");
}
else
{
$patrolAgainBrackets.first().before(patrolFailureCode);
$patrolAgainBrackets.show();
}
$patrolLink.text(tryAgainText);
$patrolLink.show();
mw.notify( mw.msg( 'markedaspatrollederrornotifypage' ), { type: 'error' } );
});
});
}
}


function makeDiffPagePatrolButtons()
function makeDiffPagePatrolLinks()
{
{
var $button = $(".patrollink-range a");
var $button = $(".patrollink-range a");
Linia 203: Linia 260:
$button.click(function()
$button.click(function()
{
{
processPagePatrol($button.parent());
processDiffPageFullPatrol();
});
});
}
}
Linia 211: Linia 268:
function processDiffPageRangePatrol()
function processDiffPageRangePatrol()
{
{
var $button = $(".patrollink-range");
var $button = $(".patrollink-range"),
var to = $button.find("a").attr("data-revision-max");
$patrolLink = $button.find("a"),
$spinner = $.createSpinner({ size: 'small', type: 'inline' }),
var from = $button.find("a").attr("data-revision-min");
$patrolAgainBrackets = $button.find(".patrolAgainBracket"),
to = $patrolLink.attr("data-revision-max"),
from = $patrolLink.attr("data-revision-min");
$patrolLink.hide();
$button.find("a").replaceWith(spinnerCode);
$patrolAgainBrackets.hide();
$patrolLink.after($spinner);
$patrolLink.parent().find(".patrolButtonClicked").remove();
patrolModule.resetLastClick();
patrolModule.resetLastClick();
patrolModule.patrolRangeOfChanges(to, from).done(function()
patrolModule.patrolRangeOfChanges(to, from).done(function(data)
{
{
removeSpinner($button);
$button.find("div").replaceWith(RCMultiplePatrolSuccessCode);
}).fail(function(error)
$patrolLink.after(patrolSuccessCode);
$patrolLink.remove();
$patrolAgainBrackets.remove();
var title = new mw.Title(data["fmod-patrol"].title);
mw.notify( mw.msg( 'markedaspatrollednotifymulti', title.toText() ) );
}).fail(function()
{
{
removeSpinner($button);
console.log(error);
$button.find("div").replaceWith(RCMultipleFailureSuccessCode);
if ($patrolAgainBrackets.length === 0)
});
{
}
$patrolLink.before(patrolFailureCode);

$patrolLink.before("<span class='patrolAgainBracket'> (</span>");
function processDiffPageFullPatrol()
$patrolLink.after("<span class='patrolAgainBracket'>)</span>");
{
}
var $button = $(".patrollink-page");
else
{
var pageid = $button.find("a").attr("data-pageid");
$patrolAgainBrackets.first().before(patrolFailureCode);
$button.find("a").replaceWith(spinnerCode);
$patrolAgainBrackets.show();
}
patrolModule.resetLastClick();
$patrolLink.text(tryAgainText);
patrolModule.patrolPage(pageid).done(function()
$patrolLink.show();
{
$button.find("div").replaceWith(RCMultiplePatrolSuccessCode);
mw.notify( mw.msg( 'markedaspatrollederrornotifypage' ), { type: 'error' } );
}).fail(function(error)
{
console.log(error);
$button.find("div").replaceWith(RCMultipleFailureSuccessCode);
});
});
}
}


function getParentTag($anchor, tag)
function processGroupMarksAndButtons($anchor) //usuwa grupowy wykrzyknik i przycisk patrolowania, jak zajdzie potrzeba
{
var $parent = $anchor;
while ($parent.prop("tagName") != "TABLE" && $parent.prop("tagName") != "BODY")
{
$parent = $parent.parent();
}
//wszystkie rozwijalne zmiany/pliki spatrolowane, drugi warunek po to,
//zeby nie ignorowalo sytuacji, gdy zmiany nie udalo sie spatrolowac
if ($parent.find(".patrolButton").length === 0 && $parent.find("abbr.unpatrolled").length == 1)
{
$parent.find("abbr.unpatrolled").replaceWith("&nbsp;");
$parent.find(".multiplePatrolButton").replaceWith("<span><img src='https://nonsa.pl/images/2/26/Za.svg.png' width='15px' height='15px' />&nbsp;<span style='color: green;' class='multiplePatrolButtonClicked'>zrobione</span></span>");
}
}

function goUpUntilTag($anchor, tag)
{
{
tag = tag.toUpperCase();
tag = tag.toUpperCase();
Linia 276: Linia 326:
function isEventBound($element)
function isEventBound($element)
{
{
if ($element == null || $element.length == 0)
{
return false;
}
var events = $._data($element.get(0), "events");
var events = $._data($element.get(0), "events");
return events != null;
return events != null;
}

function removeSpinner($node)
{
$node.find("div.mw-spinner").remove();
}
}

Aktualna wersja na dzień 17:25, 28 maj 2020

/*
 * gadżet do szybkiego oznaczania wersji jako sprawdzonych na OZ, nowych stronach i widoku diffów
 * autor: Expert3222
 * drobne modyfikacje, backend: Ostrzyciel
 */

mw.loader.load('/wiki/Użytkownik:Expert3222/patrolModule.js?action=raw&ctype=text/javascript');

var patrolSuccessCode = "<span style='color: green;' class='patrolButtonClicked'><img src='https://nonsa.pl/images/2/26/Za.svg.png' width='15px' height='15px' />&nbsp;zrobione</span>";
var patrolFailureCode = "<span style='color: red;' class='patrolButtonClicked'><img src='https://nonsa.pl/images/a/a8/Przeciw.svg.png' width='15px' height='15px' />&nbsp;błąd</span>";
var tryAgainText = "spróbuj ponownie";

$(document).ready(function()
{
	mw.loader.using(["jquery.spinner", "mediawiki.notification"], function()
	{
		if (mw.config.get("wgCanonicalSpecialPageName") === "Recentchanges")
		{
			makePatrolLinks();
			if (!!$('.mw-rcfilters-enabled').length) //wzięte od Polskacafe z gadżetu RollWithReason
			{
				setInterval(makePatrolLinks, 2000);
			}
		}
		else if (mw.config.get("wgCanonicalSpecialPageName") == "Newpages")
		{
			var $buttons = $(".patrollink-page a");
			$buttons.click(function()
			{
				processPagePatrol($(this).parent());
			});
		}
		else if (mw.util.getParamValue("diff") !== null)
		{
			makeDiffPagePatrolLinks();
			
			setInterval(makeDiffPagePatrolLinks, 2000); //"przeglądaj historię interaktywnie" na górze
		}
		else if ($(".patrollink").length > 0) //footer
		{
			$(".patrollink-page a").off("click").click(function(event) //remove default click handler and attach our own
			{
				event.preventDefault();
				event.stopImmediatePropagation();
				processPagePatrol($(this).parent());
			});
		}
		else if (mw.config.get("wgCanonicalSpecialPageName") == "MobileDiff")
		{
			//TODO
			
			/*var oldid = mw.util.getParamValue("oldid", $("#mw-mf-diff-info a").attr("href"));
			alert("oldid = " + oldid);
			var urlArray = window.location.href.split("/");
			var curid = urlArray[urlArray.length - 1];
			alert("curid = " + curid);
			
			var title = $("#mw-mf-diff-info a").text();
			makeDiffViewRevidsList(oldid, curid, title);*/
		}
	});
});

function makePatrolLinks()
{
	$(".patrollink-range a").each(function()
	{
		var $link = $(this);
		if (!isEventBound($link))
		{
			var $tbody = getParentTag($link, "tbody");
			$link.on("click", function()
			{
				processMultipleChangeRCPatrol($tbody);
			});
		}
	});

	$(".patrollink-single a").each(function()
	{
		var $button = $(this);
		if (!isEventBound($button))
		{
			$button.on("click", function()
			{
				processRCChangePatrol($(this).parent(), true);
			});
		}
	});
}

//helper function to process multiple change RC patrol, including spinner etc.
function processMultipleChangeRCPatrol($tbody)
{
	var $button = $tbody.find(".patrollink-range"),
		$patrolLink = $button.find("a"),
		$singlePatrolLinks = $tbody.find(".patrollink-single a"),
		$spinner = $.createSpinner({ size: 'small', type: 'inline' }),
		$patrolAgainBrackets = $patrolLink.parent().find(".patrolAgainBracket");
	
	$patrolLink.hide();
	$patrolAgainBrackets.hide();
	$patrolLink.after($spinner);
	$patrolLink.parent().find(".patrolButtonClicked").remove();
	
	patrolModule.patrolRangeOfChanges($patrolLink.attr("data-revision-max")).done(function(data)
	{
		removeSpinner($button);
		
		$patrolLink.after(patrolSuccessCode);
		$patrolLink.remove();
		$patrolAgainBrackets.remove();
		
		var title = new mw.Title(data["fmod-patrol"].title);
		mw.notify( mw.msg( 'markedaspatrollednotifymulti', title.toText() ) );
		
		//replace single buttons with success text
		$singlePatrolLinks.replaceWith(patrolSuccessCode);
		
		//remove patrol exclamation marks
		$tbody.find("abbr.unpatrolled").replaceWith("&nbsp;");
	}).fail(function() {
		removeSpinner($button);
		
		if ($patrolAgainBrackets.length === 0)
		{
			$patrolLink.before(patrolFailureCode);
			$patrolLink.before("<span class='patrolAgainBracket'> (</span>");
			$patrolLink.after("<span class='patrolAgainBracket'>)</span>");
		}
		else
		{
			$patrolAgainBrackets.first().before(patrolFailureCode);
			$patrolAgainBrackets.show();
		}
		$patrolLink.text(tryAgainText);
		$patrolLink.show();
		
		mw.notify( mw.msg( 'markedaspatrollederrornotify' ), { type: 'error' } );
	});
}

//helper function to process one RC link including spinner etc.
function processRCChangePatrol($button)
{
	var $patrolLink = $button.find("a"),
		revid = $patrolLink.attr("data-revision"),
		$spinner = $.createSpinner({ size: 'small', type: 'inline' }),
		$patrolAgainBrackets = $button.find(".patrolAgainBracket");
		
	$patrolLink.hide();
	$patrolAgainBrackets.hide();
	$patrolLink.after($spinner);
	$patrolLink.parent().find(".patrolButtonClicked").remove();
	
	patrolModule.resetLastClick();
	patrolModule.patrolChange(revid).done(function(data)
	{
		removeSpinner($button);
		
		$patrolLink.after(patrolSuccessCode);
		$patrolLink.remove();
		$patrolAgainBrackets.remove();
		
		getParentTag($button, "tr").find("abbr.unpatrolled").replaceWith("&nbsp;");
		
		var title = new mw.Title(data["fmod-patrol"].title);
		mw.notify( mw.msg( 'markedaspatrollednotify', title.toText() ) );
	}).fail(function()
	{
		removeSpinner($button);
		
		if ($patrolAgainBrackets.length === 0)
		{
			$patrolLink.before(patrolFailureCode);
			$patrolLink.before("<span class='patrolAgainBracket'> (</span>");
			$patrolLink.after("<span class='patrolAgainBracket'>)</span>");
		}
		else
		{
			$patrolAgainBrackets.first().before(patrolFailureCode);
			$patrolAgainBrackets.show();
		}
		$patrolLink.text(tryAgainText);
		$patrolLink.show();
		
		mw.notify( mw.msg( 'markedaspatrollederrornotifychange' ), { type: 'error' } );
	});
}

function processPagePatrol($button)
{
	//diff page, new pages and any new page on the bottom
	var pageid = $button.find("a").attr("data-pageid"),
		$patrolLink = $button.find("a"),
		$spinner = $.createSpinner({ size: 'small', type: 'inline' }),
		$patrolAgainBrackets = $button.find(".patrolAgainBracket");
	
	$patrolLink.hide();
	$patrolAgainBrackets.hide();
	$patrolLink.after($spinner);
	$patrolLink.parent().find(".patrolButtonClicked").remove();
	
	patrolModule.resetLastClick();
	patrolModule.patrolPage(pageid).done(function(data)
	{
		removeSpinner($button);
		
		$patrolLink.after(patrolSuccessCode);
		$patrolLink.remove();
		$patrolAgainBrackets.remove();
		
		// if we are on diff page remove range patrol button, because we just patrolled all page revisions
		$(".patrollink-range a").replaceWith(patrolSuccessCode);
		
		//if we are on Special:Newpages change background to match patrolled
		if (mw.config.get("wgCanonicalSpecialPageName") == "Newpages")
		{
			getParentTag($button, "li").removeClass("not-patrolled");
		}
		
		var title = new mw.Title(data["fmod-patrol"].title);
		mw.notify( mw.msg( 'markedaspatrollednotifypage', title.toText() ) );
	}).fail(function()
	{
		removeSpinner($button);
		
		if ($patrolAgainBrackets.length === 0)
		{
			$patrolLink.before(patrolFailureCode);
			$patrolLink.before("<span class='patrolAgainBracket'> (</span>");
			$patrolLink.after("<span class='patrolAgainBracket'>)</span>");
		}
		else
		{
			$patrolAgainBrackets.first().before(patrolFailureCode);
			$patrolAgainBrackets.show();
		}
		$patrolLink.text(tryAgainText);
		$patrolLink.show();
		
		mw.notify( mw.msg( 'markedaspatrollederrornotifypage' ), { type: 'error' } );
	});
}

function makeDiffPagePatrolLinks()
{	
	var $button = $(".patrollink-range a");
	if (!isEventBound($button))
	{
		$button.click(function()
		{
			processDiffPageRangePatrol();
		});
	}
	
	$button = $(".patrollink-page a");
	if (!isEventBound($button))
	{
		$button.click(function()
		{
			processPagePatrol($button.parent());
		});
	}
}

//helper function to process diff page range patrol including spinner etc.
function processDiffPageRangePatrol()
{
	var $button = $(".patrollink-range"),
		$patrolLink = $button.find("a"),
		$spinner = $.createSpinner({ size: 'small', type: 'inline' }),
		$patrolAgainBrackets = $button.find(".patrolAgainBracket"),
		to = $patrolLink.attr("data-revision-max"),
		from = $patrolLink.attr("data-revision-min");
	
	$patrolLink.hide();
	$patrolAgainBrackets.hide();
	$patrolLink.after($spinner);
	$patrolLink.parent().find(".patrolButtonClicked").remove();
	
	patrolModule.resetLastClick();
	patrolModule.patrolRangeOfChanges(to, from).done(function(data)
	{
		removeSpinner($button);
		
		$patrolLink.after(patrolSuccessCode);
		$patrolLink.remove();
		$patrolAgainBrackets.remove();
		
		var title = new mw.Title(data["fmod-patrol"].title);
		mw.notify( mw.msg( 'markedaspatrollednotifymulti', title.toText() ) );
	}).fail(function()
	{
		removeSpinner($button);
		
		if ($patrolAgainBrackets.length === 0)
		{
			$patrolLink.before(patrolFailureCode);
			$patrolLink.before("<span class='patrolAgainBracket'> (</span>");
			$patrolLink.after("<span class='patrolAgainBracket'>)</span>");
		}
		else
		{
			$patrolAgainBrackets.first().before(patrolFailureCode);
			$patrolAgainBrackets.show();
		}
		$patrolLink.text(tryAgainText);
		$patrolLink.show();
		
		mw.notify( mw.msg( 'markedaspatrollederrornotifypage' ), { type: 'error' } );
	});
}

function getParentTag($anchor, tag)
{
	tag = tag.toUpperCase();
	var $a = $anchor;
	while ($a.prop("tagName") != tag && $a.prop("tagName") != "BODY")
	{
		$a = $a.parent();
	}
	return $a;
}

function isEventBound($element)
{
	if ($element == null || $element.length == 0)
	{
		return false;
	}
	var events = $._data($element.get(0), "events");
	return events != null;
}

function removeSpinner($node)
{
	$node.find("div.mw-spinner").remove();
}