v50 Steam/Premium information for editors
  • v50 information can now be added to pages in the main namespace. v0.47 information can still be found in the DF2014 namespace. See here for more details on the new versioning policy.
  • Use this page to report any issues related to the migration.
This notice may be cached—the current version can be found here.

Difference between revisions of "User:Lethosor/rater 0.2.js"

From Dwarf Fortress Wiki
Jump to navigation Jump to search
(Update)
m (Lethosor moved page User:Lethosor/rater.js to User:Lethosor/rater 0.2.js: Updating)
 
(7 intermediate revisions by the same user not shown)
Line 60: Line 60:
 
position:'fixed', 'background-color':'rgba(128,128,128,0.5)', 'z-index':9999})
 
position:'fixed', 'background-color':'rgba(128,128,128,0.5)', 'z-index':9999})
 
.hide().appendTo('body');
 
.hide().appendTo('body');
rater.win = $('<div>').css({width:'80%', height:$(window).height()/2, 'font-size':'1.25em', top:'1em', right:0, position:'absolute', 'background-color':'#fbfbf9', 'z-index':10000, padding:'1em',overflow:'auto','border-radius':4, border:'1px solid #ccb'})
+
 +
 +
//See http://jsfiddle.net/AN9qR/4/
 +
var win_height=$(window).height()/2;
 +
var win_width = $('#bodyContent').width()*0.8;
 +
rater.win = $('<div>').css({width:win_width+8, height:win_height+8, 'font-size':'1.25em', top:'1.5em', right:0, position:'absolute', 'background-color':'#fbfbf9', 'z-index':10000, overflow:'auto', 'border-radius':4, border:'1px solid #ccb', 'box-shadow':'0 0 6px rgba(128,128,128,.6)', overflow:'visible',padding:4})
 
.hide().appendTo('#bodyContent');
 
.hide().appendTo('#bodyContent');
 +
 +
rater.win.filler = $('<div>').css({width:win_width+8, height:win_height+8, 'font-size':'1.25em', top:0, left:0, position:'absolute', 'background-color':'#fbfbf9', 'z-index':10002, overflow:'hidden', 'border-radius':4})
 +
.appendTo(rater.win);
 +
 +
rater.win.inner = $("<div>").css({display:'block',position:'relative', top:0,left:0, 'border-radius':4, 'z-index':10003, 'background-color':'#fbfbf9', width:win_width-12, height:win_height, 'overflow-y':'auto', 'overflow-x':'hidden', margin:6})
 +
.appendTo(rater.win);
 +
rater.win.arrow = $("<span>").css({display:'block', position:'absolute', 'background-color':'#fbfbf9', height:'1.5em', width:'1.5em', top:'-.75em', right:'1.5em', 'z-index':10001, '-webkit-transform':'rotate(45deg)', transform:'rotate(45deg)', 'box-shadow':'0 0 6px rgba(128,128,128,0.6)', border:'1px solid #ccb'})
 +
.prependTo(rater.win);
 +
rater.rating_exists=true;
 +
if(!$('.topicon').length){ // No current/visible quality rating
 +
rater.rating_exists=false;
 +
rater.win.arrow.hide();
 +
//create a blank one
 +
$('<div>').addClass('topicon').css({right:10}).appendTo('#bodyContent');
 +
$('.topicon').append($("<span>"));
 +
}
 +
 
rater.cancel_link = $('<a>').text('Cancel').attr('href','#rater-cancel').css({color:'red',  
 
rater.cancel_link = $('<a>').text('Cancel').attr('href','#rater-cancel').css({color:'red',  
 
'float':'right'}).appendTo(rater.win);
 
'float':'right'}).appendTo(rater.win);
Line 96: Line 118:
 
rater.frame.current_frame=function(){return rater.frame.list[rater.frame.current]}
 
rater.frame.current_frame=function(){return rater.frame.list[rater.frame.current]}
 
rater.frame.change=function(name){
 
rater.frame.change=function(name){
if(rater.frame.current) $('.rater-frame').hide();
+
if(rater.frame.current) $('.rater-frame').hide().css({margin:'1em'});
 
if(!(name in rater.frame.list)){
 
if(!(name in rater.frame.list)){
rater.frame.list[name]=$('<div>').addClass('rater-frame');
+
rater.frame.list[name]=$('<div>').addClass('rater-frame').css({margin:'1em'});
 
}
 
}
rater.frame.list[name].appendTo(rater.win).show();
+
rater.frame.list[name].appendTo(rater.win.inner).show();
 
rater.frame.current=name;
 
rater.frame.current=name;
 
};
 
};
Line 118: Line 140:
 
rater.cancel = function(e){
 
rater.cancel = function(e){
 
PD(e);rater.show_link.removeClass('selected');
 
PD(e);rater.show_link.removeClass('selected');
//$('body').css({overflow:'auto'});
+
rater.overlay.stop(1,1).fadeOut(300);
//rater.overlay.stop(1,1).fadeOut(300);
 
 
rater.win.stop(1,1).fadeOut(300);
 
rater.win.stop(1,1).fadeOut(300);
 +
rater.show_link_topicon.show(500);
 
rater.active=false;
 
rater.active=false;
 
};  
 
};  
 
$('body').on('click','a[href=#rater-cancel]',rater.cancel);
 
$('body').on('click','a[href=#rater-cancel]',rater.cancel);
 
 
// Set up link
+
// Set up links
 
rater.show_link = $("<li>").append($('<span>').append(
 
rater.show_link = $("<li>").append($('<span>').append(
 
$("<a href='#rater-invoke'>").text('Rate')
 
$("<a href='#rater-invoke'>").text('Rate')
Line 131: Line 153:
 
$("#left-navigation #p-namespaces ul:nth(0)").append('<li><span><a></a></span></li>')
 
$("#left-navigation #p-namespaces ul:nth(0)").append('<li><span><a></a></span></li>')
 
$("#left-navigation #p-namespaces ul:nth(0)").append(rater.show_link)
 
$("#left-navigation #p-namespaces ul:nth(0)").append(rater.show_link)
 +
 +
rater.show_link_topicon = $('<a>').attr({href:'#rater-invoke',title:"Change this page's rating"}).text('Change').appendTo('.topicon').css({'padding-left':6});
 +
if(!rater.rating_exists) rater.show_link_topicon.hide()
 
 
 
rater.active=false;
 
rater.active=false;
Line 137: Line 162:
 
if(rater.active) return;
 
if(rater.active) return;
 
rater.win.stop(1,1).fadeIn(300);
 
rater.win.stop(1,1).fadeIn(300);
rater.box.clear()
+
rater.frame.change('main');
 +
rater.box.clear();
 
if(!rater.is_valid_page(wgPageName) && !force)
 
if(!rater.is_valid_page(wgPageName) && !force)
 
return rater.error_invalid_page();
 
return rater.error_invalid_page();
rater.box.clear();rater.show_link.addClass('selected');
+
rater.show_link_topicon.hide(500);
 +
rater.show_link.addClass('selected');
 
rater.box.append('<p>Performing automatic tests, please wait...</p>');
 
rater.box.append('<p>Performing automatic tests, please wait...</p>');
 
rater.begin_tests();
 
rater.begin_tests();
Line 159: Line 186:
 
'history':rater.page.url+'&action=history&limit=100'
 
'history':rater.page.url+'&action=history&limit=100'
 
};
 
};
 +
/*
 +
Tests to be performed
 +
Structure: {
 +
name: 'Human-readable name',
 +
init: function(data){... return Object},
 +
[str: function(obj){... return String}]
 +
[int: function(obj){... return Number}]
 +
score: function(obj){... return Number}
 +
[info: function(obj,view){...}]
 +
}
 +
Functions in [brackets] are optional
 +
 +
Parameters:
 +
- data: The raw data returned from the URLs in rater.metadata.urls (e.g. rater.raw is raw page text)
 +
- obj: An object returned from the object's init()
 +
- view: A HTML element (usually <div>) that will be displayed to the user
 +
 +
*/
 
rater.metadata.tests = {
 
rater.metadata.tests = {
 
redlinks:{
 
redlinks:{
Line 255: Line 300:
 
loader.num_waiting = 0;
 
loader.num_waiting = 0;
 
loader.total_tests = 0;
 
loader.total_tests = 0;
 +
loader.key=Math.floor(Math.random()*1e8); //prevent caching
 
 
 
loader.add = function(name,url){  
 
loader.add = function(name,url){  
 
loader.list[name] = {url:url};
 
loader.list[name] = {url:url};
$.get(url, {rater:1}, function(data){
+
$.get(url, {rater:loader.key}, function(data){
 
loader.ready(name, data);
 
loader.ready(name, data);
 
});
 
});
Line 440: Line 486:
 
;
 
;
 
rater.box.append($("<p>").text("Score: "+rater.score))
 
rater.box.append($("<p>").text("Score: "+rater.score))
rater.select.init($("<div>").appendTo(rater.box));
+
//rater.select.init($("<div>").appendTo(rater.box));
 +
$("<a>").attr({href:'#rater-override'}).html('Select rating &rarr;').appendTo(rater.box);
 
};
 
};
 
rater.select={};
 
rater.select={};
 
rater.select.view=$("<div>").css({padding:'.2em'});
 
rater.select.view=$("<div>").css({padding:'.2em'});
rater.select.init=function(){
+
rater.select.init=function(e){PD(e);
 +
rater.frame.change('rating-desc');
 +
rater.select.frame=rater.frame.current_frame();
 
rater.select.current=rater.tests.current_rating.toLowerCase()||'tattered';
 
rater.select.current=rater.tests.current_rating.toLowerCase()||'tattered';
rater.select.view.appendTo(rater.box);
+
rater.select.view.appendTo(rater.select.frame);
 
rater.select.draw();
 
rater.select.draw();
 
};
 
};
rater.select.draw=function(){var c,selected,a,view=rater.select.view;
+
$('body').on('click','a[href=#rater-override]',rater.select.init);
view.text('\nDesired rating: ');
+
rater.select.draw=function(){
list=$('<span>').css({'font-size':'.8em'}).appendTo(rater.select.view)
+
$('.topicon > span').hide();
 +
var c, selected, a,  
 +
view=rater.select.view,
 +
topview=$('<span>').appendTo('.topicon');
 +
view.html(''); topview.html('');
 +
$("<span>").text('Select rating: ').appendTo(topview);
 +
list=$('<span>').css({'font-size':'.8em'}).appendTo(topview)
 
for(i in rater.ratings){if(i in {}) continue;
 
for(i in rater.ratings){if(i in {}) continue;
 
c=rater.ratings[i];
 
c=rater.ratings[i];
Line 465: Line 520:
 
}
 
}
 
if(rater.is_valid_page()){
 
if(rater.is_valid_page()){
rater.submit_link=$('<a>').attr({href:'#rater-submit'}).text("Submit").appendTo(view);
+
rater.select.submit_link=$('<a>').attr({href:'#rater-select-submit'}).text("Submit").appendTo(topview);
view.append(' ');
+
topview.append(' ');
 
}
 
}
rater.reset_link=$('<a>').attr({href:'#rater-reset'}).text("Reset").appendTo(view);
+
rater.select.reset_link=$('<a>').attr({href:'#rater-select-reset'}).text("Reset").appendTo(topview);
 +
topview.append(' ');
 +
rater.select.cancel_link=$('<a>').attr({href:'#rater-select-cancel'}).text("Back").appendTo(topview).css({color:'red'});
 +
rater.select.cancel_link.clone().appendTo(view)
 
rater.help.view.appendTo(view);
 
rater.help.view.appendTo(view);
 
rater.help.update(selected.id);
 
rater.help.update(selected.id);
Line 481: Line 539:
 
rater.select.reset=function(e){PD(e);rater.select.init();};
 
rater.select.reset=function(e){PD(e);rater.select.init();};
 
 
$('body').on('click','a[href=#rater-reset]',rater.select.reset);
+
rater.select.cancel=function(e){PD(e);
$('body').on('click','a[href=#rater-submit]',function(e){PD(e);
+
rater.select.reset();
 +
$('.topicon > span').hide().filter(':nth(0)').show();
 +
rater.frame.change('main');
 +
};
 +
 +
$('body').on('click','a[href=#rater-select-reset]',rater.select.reset);
 +
$('body').on('click','a[href=#rater-select-cancel]',rater.select.cancel);
 +
$('body').on('click','a[href=#rater-select-submit]',function(e){PD(e);
 
rater.submit_rating();
 
rater.submit_rating();
 
});
 
});
 
 
 
rater.submit_rating=function(){
 
rater.submit_rating=function(){
rater.box.clear();stat=$('<pre>').appendTo(rater.box);
+
rater.overlay.fadeIn(400);
 +
rater.frame.change('submit-progress');
 +
var view=rater.frame.current_frame();
 +
view.html('');
 +
rater.progress.reset();
 +
rater.progress.view.appendTo(view);
 +
var stat=$('<div>').css({'white-space':'pre'}).appendTo(view);
 
function w(s){stat.append(s);}
 
function w(s){stat.append(s);}
 
var r=rater.select.current;
 
var r=rater.select.current;
Line 496: Line 567:
 
w('Retrieving token... ');
 
w('Retrieving token... ');
 
$.get(wgScriptPath+'/api.php?format=json&action=query&prop=info&indexpageids=1&intoken=edit&titles='+wgPageName,function(d){
 
$.get(wgScriptPath+'/api.php?format=json&action=query&prop=info&indexpageids=1&intoken=edit&titles='+wgPageName,function(d){
 +
rater.progress.update(1,4);
 
var token=d.query.pages[d.query.pageids[0]].edittoken;
 
var token=d.query.pages[d.query.pageids[0]].edittoken;
 
w('Ok ({0})\nReplacing quality template... '.format(token.slice(0,-2)));
 
w('Ok ({0})\nReplacing quality template... '.format(token.slice(0,-2)));
 
console.log(token);
 
console.log(token);
var text=rater.loader.results.raw.replace(/{{quality[^}]*?}}/gi,'');
+
var text=rater.loader.results.raw.replace(/{{quality[^}]*?}}\n*/gi,'');
text='{{Quality|'+rating+'|~~~~~}}\n'+text
+
text='{{Quality|'+rating+'|~~~~~}}\n'+text;
//console.log(text)
+
w('Ok\nEditing page... ');
w('Ok\nEditing page... ')
 
 
var e=encodeURIComponent;
 
var e=encodeURIComponent;
 
var page=rater.page.name;
 
var page=rater.page.name;
 +
rater.progress.update(2,4);
 
$.post(wgScriptPath+'/api.php', {action:'edit',title:rater.page.name,text:text,
 
$.post(wgScriptPath+'/api.php', {action:'edit',title:rater.page.name,text:text,
 
token:token,minor:1,summary:'Rated article "{0}" using the rating script.'.format(rating)},function(d){
 
token:token,minor:1,summary:'Rated article "{0}" using the rating script.'.format(rating)},function(d){
//console.log(d,'DONE')
+
rater.progress.update(3,4);
w('Finished!\nReloading...');
+
w('Finished!\nUpdating...');
$('body').load(rater.page.url + ' body',function(d){
+
$.get(wgScriptPath+'/api.php',{
window.location.reload(); //maybe load w/ ajax?
+
action:'parse',text:'{{Quality|'+rating+'|~~~~~}}',
 +
format:'json',title:wgPageName},
 +
function(d){
 +
rater.progress.update(4,4);
 +
$('.topicon > *').hide().parent().prepend($(d.parse.text['*']).filter(':nth(0)').contents());
 +
// Replace categories
 +
$('.catlinks li a:contains(Quality Articles)').hide();
 +
var cats = d.parse.categories;
 +
for(i=0;i<cats.length;i++){
 +
$('<a>').attr({href:wgScript+'/Category:'+cats[i]['*']}).text(cats[i]['*'].replace(/_/g,' ')).appendTo($("<li>").appendTo('.catlinks ul'));
 +
}
 +
 +
$('.catlinks li a:hidden').remove();
 +
$('.catlinks li:empty').remove();
 +
 +
rater.progress.update(5,4);
 +
rater.cancel();
 
});
 
});
 +
 
});
 
});
 
});
 
});
Line 520: Line 609:
 
rater.auto_link=$('<a>').attr('href',window.location.hash).appendTo('body');
 
rater.auto_link=$('<a>').attr('href',window.location.hash).appendTo('body');
 
setTimeout(function(){rater.auto_link.click()},100);//after this returns, anon for scope
 
setTimeout(function(){rater.auto_link.click()},100);//after this returns, anon for scope
};
+
}
 +
//Check querystring for message
 +
rater.qs_raw=window.location.search.slice(1);rater.qs_list=rater.qs_raw.split('&');rater.qs={};
 +
for(var i=0;i<rater.qs_list.length;i++){
 +
var v=rater.qs_list[i].split('=');
 +
rater.qs[v[0]]=v[1]
 +
}
 +
if(rater.qs.rated=='success'){
 +
jsMsg('Rated article <b>'+rater.qs.rating+'</b>')
 +
}
 
 
 
//export
 
//export

Latest revision as of 21:42, 8 May 2013

/* <nowiki>
Rating Script (DF Wiki)

Improved version -- now uses jQuery, extra options (existence not guaranteed)
*/

//Like python: 'a{0}b'.format('c') == 'acb'
String.prototype.format=function(){s=this;for(i=0;i<arguments.length;i++){s=s.replace(RegExp('\\{'+i+'\\}','g'), arguments[i])};return s};
String.prototype.capitalize=function(){return this.slice(0,1).toUpperCase()+this.slice(1)};
addOnloadHook(function(){jQuery(function($){
	SCOPE = this
	var rater = {}
	
	rater.event=$({});//for event bindings
	//Temporary! (importScript doesn't seem to work here)
	$.getScript(wgScript+'?title=User:Lethosor/raterwarn.js&action=raw');
	
	function PD(e){//preventDefault
		if(e && e['preventDefault'] && 'call' in e.preventDefault)
			e.preventDefault()
	}
	function is_func(x){return !!(x&&x['call'])}
	rater.page = {
		name: wgPageName.replace(/_/g,' '),
		ns:wgCanonicalNamespace||'Main',
		url: wgScript+'?title='+wgPageName,
		exists:!$('#left-navigation').find('li[class*=selected]').find('a[href*=redlink]').length,
		load_time:$('body').html().match(/<!--.*-->/g).slice(-1)[0].match(/\d+\.\d+/)[0]
	}
	
	rater.is_valid_page = function(page){
		if(!rater.page.exists) return false;
		if(!page) page=wgPageName;
		if('Masterwork DF2012 v0.31 40d 23a'.split(' ').indexOf(rater.page.ns)+1) return true
		if($('#norate').length) return false
		return false
	};
	
	rater.error_invalid_page=function(){
		if('Special File Image Unused'.indexOf(rater.page.ns)+1||
			rater.page.ns.toLowerCase().indexOf('talk')+1){
			rater.box.clear().append('<span class="error">I\'m afraid I can\'t let you do that,'+
			' Urist.</span><p>This page isn\'t an article, and doesn\'t have some of the necessary'+
			' properties to be rated. <a href="#rater-cancel">Close this window</a></p>')
			rater.box.find('a:nth(1)').focus();
		}
		else if(!rater.page.exists){
			rater.box.clear().append('<p class="error">This page doesn\'t exist!</p><a href="#rater-cancel">Close this window</a>');rater.box.find('a:nth(1)').focus();
		}
		else{
			rater.box.clear().append('<span class="error">Invalid page</span>')
			.append("<p>This page is in an invalid namespace. You can "+
				"<a href='#rater-force'>view this page's rating anyway</a> or "+
				"<a href='#rater-cancel'>close this window</a>.</p>")
		}
	};
	
	// Set up UI
	rater.overlay = $('<div>').css({width:'100%', height:'100%', top:0, left:0,
		position:'fixed', 'background-color':'rgba(128,128,128,0.5)', 'z-index':9999})
		.hide().appendTo('body');
	
	
	//See http://jsfiddle.net/AN9qR/4/
	var win_height=$(window).height()/2;
	var win_width = $('#bodyContent').width()*0.8;
	rater.win = $('<div>').css({width:win_width+8, height:win_height+8, 'font-size':'1.25em', top:'1.5em', right:0, position:'absolute', 'background-color':'#fbfbf9', 'z-index':10000, overflow:'auto', 'border-radius':4, border:'1px solid #ccb', 'box-shadow':'0 0 6px rgba(128,128,128,.6)', overflow:'visible',padding:4})
		.hide().appendTo('#bodyContent');
	
	rater.win.filler = $('<div>').css({width:win_width+8, height:win_height+8, 'font-size':'1.25em', top:0, left:0, position:'absolute', 'background-color':'#fbfbf9', 'z-index':10002, overflow:'hidden', 'border-radius':4})
		.appendTo(rater.win);
	
	rater.win.inner = $("<div>").css({display:'block',position:'relative', top:0,left:0, 'border-radius':4, 'z-index':10003, 'background-color':'#fbfbf9', width:win_width-12, height:win_height, 'overflow-y':'auto', 'overflow-x':'hidden', margin:6})
		.appendTo(rater.win);
	rater.win.arrow = $("<span>").css({display:'block', position:'absolute', 'background-color':'#fbfbf9', height:'1.5em', width:'1.5em', top:'-.75em', right:'1.5em', 'z-index':10001, '-webkit-transform':'rotate(45deg)', transform:'rotate(45deg)', 'box-shadow':'0 0 6px rgba(128,128,128,0.6)', border:'1px solid #ccb'})
		.prependTo(rater.win);
	rater.rating_exists=true;
	if(!$('.topicon').length){ // No current/visible quality rating
		rater.rating_exists=false;
		rater.win.arrow.hide();
		//create a blank one
		$('<div>').addClass('topicon').css({right:10}).appendTo('#bodyContent');
		$('.topicon').append($("<span>"));
	}
	
	rater.cancel_link = $('<a>').text('Cancel').attr('href','#rater-cancel').css({color:'red', 
		'float':'right'}).appendTo(rater.win);
	
	rater.popup={};
	rater.popup.overlay = $('<div>').css({width:'100%', height:'100%', top:0, left:0,
		position:'fixed', 'background-color':'rgba(128,128,128,0.5)', 'z-index':10001})
		.hide().appendTo('body');
	rater.popup.box = $('<div>').css({width:'40%', height:'60%', top:'20%', left:'30%',
		position:'fixed', 'background-color':'white', 'z-index':10002, padding:'1em',
		overflow:'auto','border-radius':4})
		.hide().appendTo('body');
	rater.popup.close_link = $('<a>').text('Close').attr('href','#rater-popup-hide').css({color:'red', 
		'float':'right'}).appendTo(rater.popup.box);

	rater.popup_show=function(e){//note _ - avoid $ clash
		PD(e);
		rater.popup.box.stop(1,1).fadeIn(300);
		rater.popup.overlay.stop(1,1).fadeIn(300);
	};
	rater.popup_hide = function(e){
		PD(e);
		rater.popup.overlay.stop(1,1).fadeOut(300);
		rater.popup.box.stop(1,1).fadeOut(300);
	}; 
	$('body').on('click','a[href=#rater-popup-hide]',rater.popup_hide);
	
	rater.popup.clear=function(){
		rater.popup.box.html('').append(rater.popup.close_link);
	};
	rater.popup.clear();

	rater.frame={list:{}};
	rater.frame.current_frame=function(){return rater.frame.list[rater.frame.current]}
	rater.frame.change=function(name){
		if(rater.frame.current) $('.rater-frame').hide().css({margin:'1em'});
		if(!(name in rater.frame.list)){
			rater.frame.list[name]=$('<div>').addClass('rater-frame').css({margin:'1em'});
		}
		rater.frame.list[name].appendTo(rater.win.inner).show();
		rater.frame.current=name;
	};
	
	rater.frame.change('main')
	rater.box=rater.frame.list['main'];
	
	rater.box.clear = function(){
		rater.box.html('')
		rater.box.append(rater.cancel_link)
			.append($('<h2>').text('Rating '+rater.page.name));
		rater.event.trigger('box-clear');
		return rater.box;
	};
	rater.box.clear()
	
	rater.cancel = function(e){
		PD(e);rater.show_link.removeClass('selected');
		rater.overlay.stop(1,1).fadeOut(300);
		rater.win.stop(1,1).fadeOut(300);
		rater.show_link_topicon.show(500);
		rater.active=false;
	}; 
	$('body').on('click','a[href=#rater-cancel]',rater.cancel);
	
	// Set up links
	rater.show_link = $("<li>").append($('<span>').append(
		$("<a href='#rater-invoke'>").text('Rate')
	));
	$("#left-navigation #p-namespaces ul:nth(0)").append('<li><span><a></a></span></li>')
	$("#left-navigation #p-namespaces ul:nth(0)").append(rater.show_link)
	
	rater.show_link_topicon = $('<a>').attr({href:'#rater-invoke',title:"Change this page's rating"}).text('Change').appendTo('.topicon').css({'padding-left':6});
	if(!rater.rating_exists) rater.show_link_topicon.hide()
	
	rater.active=false;
	rater.invoke = function(e, force){
		PD(e);
		if(rater.active) return;
		rater.win.stop(1,1).fadeIn(300);
		rater.frame.change('main');
		rater.box.clear();
		if(!rater.is_valid_page(wgPageName) && !force)
			return rater.error_invalid_page();
		rater.show_link_topicon.hide(500);
		rater.show_link.addClass('selected');
		rater.box.append('<p>Performing automatic tests, please wait...</p>');
		rater.begin_tests();
		rater.active=true;
	};
	$('body').on('click', 'a[href=#rater-invoke]', rater.invoke)
	$('body').on('click', 'a[href=#rater-force]', function(e){rater.invoke(e,1)});
	
	
	/*
	Decriptions of URLs, tests, etc.
	*/
	rater.metadata={};
	rater.metadata.urls = {
		'raw':rater.page.url+'&action=raw',
		'render':rater.page.url+'&action=render',
		'whatlinkshere':wgScript+'/Special:WhatLinksHere/'+wgPageName,
		'history':rater.page.url+'&action=history&limit=100'
	};
	/*
	Tests to be performed
	Structure: {
		name: 'Human-readable name',
		init: function(data){... return Object},
		[str: function(obj){... return String}]
		[int: function(obj){... return Number}]
		score: function(obj){... return Number}
		[info: function(obj,view){...}]
	}
	Functions in [brackets] are optional
	
	Parameters:
	- data: The raw data returned from the URLs in rater.metadata.urls (e.g. rater.raw is raw page text)
	- obj: An object returned from the object's init()
	- view: A HTML element (usually <div>) that will be displayed to the user
	
	*/
	rater.metadata.tests = {
		redlinks:{
			name:'Redlinks',
			init:function(data){
				all_links = data.render.match(/<a .*<\/a>/g);
				if(!all_links) return 0; //no links
				total_redlinks=0;
				$.each(all_links, function(i,link){
					if(link.match(/href=.*redlink=1/)) total_redlinks++;
				});
				return total_redlinks
			}
		},
		links:{
			name:'Outbound links',
			init:function(data){
				return $(data.render).find('a[href*="'+wgScript+'"]').length;
			}
		},
		linkshere:{
			name:'Incoming links',
			init:function(data){
				return $(data.whatlinkshere).find('#mw-whatlinkshere-list').find('li').length;
			}
		},
		editors: {
			name:'Editor count',
			init:function(data){
				all_editors = data.history.match(/<li>.*<\/li>/g)
				if(!all_editors) return 0; //no editors
				var editors={};
				$.each(all_editors, function(i,li){
					ed = $(li).find('.mw-userlink:nth(0)').text()
					if(!(ed in editors)) editors[ed]=0;
					editors[ed]++ 
				});
				num=0;
				for(i in editors){
					if(i in {}) continue;
					num++
				}
				editors.total=num;editors.total_edits=all_editors.length;
				return editors;
			},
			str:function(o){return o.total},	int:function(o){return o.total;},
			info:function(o,view){
				tbl=$("<table>").css({width:'100%'}).append('<tr><th colspan="2">User</th><th>Edits</th></tr>').addClass('wikitable sortable').appendTo(view)
				for(i in o){
					if(i in {}||!i.indexOf('total')) continue;
					tbl.append('<tr><td colspan="2"><a href="{2}/User:{0}">{0}</a>:</td><td>{1}</td></tr>'.format(i,o[i],wgScript))
				}
				tbl.append('<tr style="font-weight:bold"><td>Total:</td><td>{0}</td><td>{1}</td></tr>'
					.format(o.total,o.total_edits))
			},
		},
		length: {str:function(obj){
			return "Weighted: {0} ({1} characters, {2} without templates)"
				.format(obj.average,obj.full,obj.notemplate);},
		name:'Source length'},
		html_length:{name:'Text length',
			str:function(o){return '{0} (HTML: {1})'.format(o.text,o.html)},
			int:function(o){return o.text}},
		verify:{name:'{{Verify}} tags',score:function(o){
			if(o<1) return 0; if(o==1) return -10; return o*-20}},
		current_rating:{
			name:'Current rating',
			init:function(data){
				m=data.raw.match(/{{quality[^}]*?}}/i);
				return (m&&m.length&&m[0].slice(2,-2).split('|')[1])||'';
			},
			score:function(){return 0}
		}
	};
	
	rater.ratings={
		tattered:{id:1,color:{b:'#333',bg:'#ccc',c:'#333'},s:'x'},
		fine:{id:2,color:{b:'#db8',bg:'#ffe0cc',c:'#ca7a02'},s:'+'},
		superior:{id:3,color:{b:'#b8f',bg:'#e4ccff',c:'#80c'},s:'*'},
		exceptional:{id:4,color:{b:'#9df',bg:'#cce4ff',c:'#08c'},s:'\u2261'},
		masterwork:{id:5,color:{b:'#bd8',bg:'#e2fdce',c:'#72a329'},s:'\u263c'}
	};
	
	/* Stores the results of tests */
	rater.tests={};
	
	/*
	Loader
	Loads multiple URLs, with optional callbacks 
	*/
	var loader={};
	loader.list={}; //list of all tests
	loader.results={}; //shortcut: data[x]==lists[x].data
	
	loader.event=$({});
	loader.num_waiting = 0;
	loader.total_tests = 0;
	loader.key=Math.floor(Math.random()*1e8); //prevent caching
	
	loader.add = function(name,url){ 
		loader.list[name] = {url:url};
		$.get(url, {rater:loader.key}, function(data){
			loader.ready(name, data);
		});
		loader.num_waiting++
		loader.total_tests++
	};
	loader.ready = function(name,data){
		loader.list[name].result = loader.results[name] = data
		loader.num_waiting--
		loader.event.trigger('ready',{left:loader.num_waiting,total:loader.total_tests,name:name,data:data}); 
		if(loader.num_waiting <= 0){
			setTimeout(loader.all_complete, 1); //async
		}
	};
	
	loader.all_complete = function(){
		loader.event.trigger('done');
		loader.total_tests=0; //reset
	};
	loader.add_callback=function(func){
		//Compatibility: triggered on `done` event
		loader.event.bind('done',func);
	};
	
	rater.help={view:$('<div>').css({height:'100%'})};
	rater.help.init=function(){
		$.get(wgScript+'/DF:Quality',function(d){
			d=$(d);
			rater.help.data=[];
			for(var i=0;i<=5;i++){
				rater.help.data[i]=d.find('h3:nth({0})'.format(i)).nextUntil('h3');
				rater.help.data[i].splice(0,0,d.find('h3:nth({0})'.format(i))[0]); // prepend header
			};
			rater.help.update();
		});	
	};
	rater.help.update=function(n){
		if(!rater.help.data)return;
		if(!(n+1)){
			try{
				n=rater.ratings[rater.select.current].id;
			} catch(e){return}
		}
		rater.help.view.text('').append(rater.help.data[n]);
		rater.help.view.find('.editsection').hide();
		//rater.box.scrollTop(rater.box.height());
	};
	
	rater.progress={};
	rater.progress.view=$("<div>").css({width:'100%',padding:0,margin:0});
	
	rater.progress.bar=$('<div>').css({width:'100%','background-color':'#fff',border:'1px solid #ac7',padding:3,'border-radius':2,overflow:'hidden'}).appendTo(rater.progress.view);
	
	rater.progress.fill=$('<div>').css({float:'left',padding:0,margin:0,'background-color':'#ce9','border-right':'1px solid #ac7',height:'100%',width:0,margin:-3, position:'relative',top:0,left:0, 'border-radius':2}).appendTo(rater.progress.bar).html('&nbsp;');
		
	rater.progress.update=function(done,total){
		var perc=done/Math.max(total,1)*100;
		rater.progress.fill.stop().animate({width:perc+'%'},150)
	};
	rater.progress.reset=function(){rater.progress.update(0,1);};
	
	rater.begin_tests = function(){
		render_url=rater.page.url+'&action=render'
		raw_url=rater.page.url+'&action=raw'
		rater.help.init();
		for(i in rater.metadata.urls){if(i in {})continue;
			loader.add(i, rater.metadata.urls[i]);
		}
		loader.event.bind('ready',function(e,d){rater.progress.update(d.total-d.left,d.total)});
		rater.progress.view.appendTo(rater.box)
		loader.event.bind('done', rater.process_tests)
		loader.event.bind('done', rater.display_test_results)
		loader.event.bind('done', rater.progress.reset)
		/*
		tests.add('redlinks', render_url, function(data){
			all_links = data.match(/<a .*<\/a>/g);
			if(!all_links) return 0; //no links
			total_redlinks=0;
			$.each(all_links, function(i,link){
				if(link.match(/href=.*redlink=1/)) total_redlinks++;
			});
			return total_redlinks
		});
		tests.add('editors', rater.page.url+'&action=history&limit=100', function(data){
			all_editors = data.match(/<li>.*<\/li>/g)
			if(!all_editors) return 0; //no editors
			editors={};
			$.each(all_editors, function(i,li){
				ed = $(li).find('.mw-userlink:nth(0)').text()
				if(!(ed in editors)) editors[ed]=0;
				editors[ed]++ 
			});
			num=0;
			for(i in editors){
				if(i in {}) continue;
				num++
			}
			editors.total=num;editors.total_edits=all_editors.length;
			return editors;
		});
		tests.add('linkshere', wgScript+'/Special:WhatLinksHere/'+wgPageName, function(data){
			return $(data).find('#mw-whatlinkshere-list').length;
		});
		tests.add('links', render_url, function(data){
			return $(data).find('a[href*="'+wgScript+'"]').length;
		});
		tests.add('length', raw_url, function(data){
			rater.raw_text=data;
			var a={
				'full':data.length,
				'nospace':data.replace(/\s/g,'').length,
				'notemplate':data.replace(/{{[^}]*?}}/g,'').length,
				'raw':data.replace(/\s/g,'').replace(/{{[^}]*?}}/g,'').length
			};
			a.average=Math.round(.1 * a.full + .2*a.nospace + .3*a.notemplate + .4*a.raw)
			return a
		});
		tests.add('html_length', render_url, function(data){
			var a={'html':data.length,'text':$(data).text().length};
			return a;
		});
		tests.add('verify',raw_url,function(data){
			var m=data.match(/{{verify/g);return +(m&&m.length);
		});
		tests.add('current_rating',raw_url,function(data){
			m=data.match(/{{quality[^}]*?}}/i);
			return (m&&m.length&&m[0].slice(2,-2).split('|')[1])||''
		});
		tests.add_callback(function(){
			rater.display_test_results();
		});
		*/
	};
	
	rater.score_bool=function(v,y,n){
		if(isNaN(Number(n))) n=-y;
		return Number(v?y:n);
	};
	rater.score_int=function(v,weight,base){
		if(!base) base=0;
		return v*weight+base;
	};
	
	rater.tests={}
	
	rater.process_tests=function(){
		var mdt=rater.metadata.tests;
		for(i in mdt){if(i in {})continue;
			if(is_func(mdt[i].init))
				rater.tests[i]=mdt[i].init(loader.results);
		}
	};
	
	rater.display_test_results=function(){
		var md=rater.metadata.tests;
		rater.box.clear();
		data=rater.tests;
		for(var i in data){
			name=md[i].name;
			str=is_func(md[i].str)?md[i].str(data[i]):data[i];
			app=''
			if(is_func(md[i].info)){
				app=$('<a href="#">[Info]</a>').data({f:md[i].info,d:data[i]})
				.click(function(e){d=$(this).data()
					rater.popup.clear();	rater.popup_show(e);
					d.f(d.d,rater.popup.box.append($("<div>")))
				}).css('padding-left','1em');
			}
			rater.box.append($("<p>"+name+": "+str+"</p>").append(app));
		}
		
		
		rater.score = 0
			+rater.score_bool(!data.links,-25) 		//orphaned
			+rater.score_bool(!data.linkshere,-30) 	//dead end
			+rater.score_int(data.links,0.5)
			+rater.score_int(data.linkshere,0.75)
			+rater.score_int(data.redlinks,-5,10)
			+rater.score_int(data.editors.total,20,-15)
			
		;
		rater.box.append($("<p>").text("Score: "+rater.score))
		//rater.select.init($("<div>").appendTo(rater.box));
		$("<a>").attr({href:'#rater-override'}).html('Select rating &rarr;').appendTo(rater.box);
	};
	rater.select={};
	rater.select.view=$("<div>").css({padding:'.2em'});
	rater.select.init=function(e){PD(e);
		rater.frame.change('rating-desc');
		rater.select.frame=rater.frame.current_frame();
		rater.select.current=rater.tests.current_rating.toLowerCase()||'tattered';
		rater.select.view.appendTo(rater.select.frame);
		rater.select.draw();
	};
	$('body').on('click','a[href=#rater-override]',rater.select.init);
	rater.select.draw=function(){
		$('.topicon > span').hide();
		var c, selected, a, 
			view=rater.select.view,
			topview=$('<span>').appendTo('.topicon');
		view.html(''); topview.html('');
		$("<span>").text('Select rating: ').appendTo(topview);
		list=$('<span>').css({'font-size':'.8em'}).appendTo(topview)
		for(i in rater.ratings){if(i in {}) continue;
			c=rater.ratings[i];
			a=$('<span>').appendTo(list).data('rating',i).attr({tabindex:0}).css({cursor:'pointer'}); //not real link
			a.append($('<span>').text(c.s+i.toUpperCase()+c.s)
				.css({'text-decoration':'none','color':c.color.c}));
			if(i==rater.select.current){
				selected=rater.ratings[i];
				a.find('span').css({'border-color':c.color.b,'background-color':c.color.bg,'border-width':1,'border-style':'solid','border-radius':2,padding:'.2em'})
			}
			a.on('click focus',rater.select.click);
			list.append(' ');
		}
		if(rater.is_valid_page()){
			rater.select.submit_link=$('<a>').attr({href:'#rater-select-submit'}).text("Submit").appendTo(topview);
			topview.append(' ');
		}
		rater.select.reset_link=$('<a>').attr({href:'#rater-select-reset'}).text("Reset").appendTo(topview);
		topview.append(' ');
		rater.select.cancel_link=$('<a>').attr({href:'#rater-select-cancel'}).text("Back").appendTo(topview).css({color:'red'});
		rater.select.cancel_link.clone().appendTo(view)
		rater.help.view.appendTo(view);
		rater.help.update(selected.id);
		//rater.box.scrollTop(rater.box.height());
	};
	
	rater.select.click=function(e){if(e.type=='click')PD(e);
		rater.select.current=$(this).data('rating');
		rater.select.draw();
	};
	
	rater.select.reset=function(e){PD(e);rater.select.init();};
	
	rater.select.cancel=function(e){PD(e);
		rater.select.reset();
		$('.topicon > span').hide().filter(':nth(0)').show();
		rater.frame.change('main');
	};
	
	$('body').on('click','a[href=#rater-select-reset]',rater.select.reset);
	$('body').on('click','a[href=#rater-select-cancel]',rater.select.cancel);
	$('body').on('click','a[href=#rater-select-submit]',function(e){PD(e);
		rater.submit_rating();
	});
	
	rater.submit_rating=function(){
		rater.overlay.fadeIn(400);
		rater.frame.change('submit-progress');
		var view=rater.frame.current_frame();
		view.html('');
		rater.progress.reset();
		rater.progress.view.appendTo(view);
		var stat=$('<div>').css({'white-space':'pre'}).appendTo(view);
		function w(s){stat.append(s);}
		var r=rater.select.current;
		if(r in {}||!(r in rater.ratings)) return;
		var rating=rater.select.current.capitalize();
		if(!rater.loader.results.raw) return;
		//get token
		w('Retrieving token... ');
		$.get(wgScriptPath+'/api.php?format=json&action=query&prop=info&indexpageids=1&intoken=edit&titles='+wgPageName,function(d){
			rater.progress.update(1,4);
			var token=d.query.pages[d.query.pageids[0]].edittoken;
			w('Ok ({0})\nReplacing quality template... '.format(token.slice(0,-2)));
			console.log(token);
			var text=rater.loader.results.raw.replace(/{{quality[^}]*?}}\n*/gi,'');
			text='{{Quality|'+rating+'|~~~~~}}\n'+text;
			w('Ok\nEditing page... ');
			var e=encodeURIComponent;
			var page=rater.page.name;
			rater.progress.update(2,4);
			$.post(wgScriptPath+'/api.php', {action:'edit',title:rater.page.name,text:text,
			token:token,minor:1,summary:'Rated article "{0}" using the rating script.'.format(rating)},function(d){
				rater.progress.update(3,4);
				w('Finished!\nUpdating...');
				$.get(wgScriptPath+'/api.php',{
					action:'parse',text:'{{Quality|'+rating+'|~~~~~}}',
					format:'json',title:wgPageName},
				function(d){
					rater.progress.update(4,4);
					$('.topicon > *').hide().parent().prepend($(d.parse.text['*']).filter(':nth(0)').contents());
					// Replace categories
					$('.catlinks li a:contains(Quality Articles)').hide();
					var cats = d.parse.categories;
					for(i=0;i<cats.length;i++){
						$('<a>').attr({href:wgScript+'/Category:'+cats[i]['*']}).text(cats[i]['*'].replace(/_/g,' ')).appendTo($("<li>").appendTo('.catlinks ul'));
					}
					
					$('.catlinks li a:hidden').remove();
					$('.catlinks li:empty').remove();
					
					rater.progress.update(5,4);
					rater.cancel();
				});
				
			});
		});
	};
	
	//check for a provided hash...
	if(window.location.hash.length){
		rater.auto_link=$('<a>').attr('href',window.location.hash).appendTo('body');
		setTimeout(function(){rater.auto_link.click()},100);//after this returns, anon for scope
	}
	//Check querystring for message
	rater.qs_raw=window.location.search.slice(1);rater.qs_list=rater.qs_raw.split('&');rater.qs={};
	for(var i=0;i<rater.qs_list.length;i++){
		var v=rater.qs_list[i].split('=');
		rater.qs[v[0]]=v[1]
	}
	if(rater.qs.rated=='success'){
		jsMsg('Rated article <b>'+rater.qs.rating+'</b>')
	}
	
	//export
	rater.loader = loader;
	window.rater=rater
	return rater;
	
});});
// </nowiki>