User:Jamesofur/2010SEstatupdate.js

From Meta, a Wikimedia project coordination wiki

Note: After publishing, 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 / Edge: Hold Ctrl while clicking Refresh, or press Ctrl-F5
  • Opera: Press Ctrl-F5.
<source lang="javascript">
/*********************
** Functions
*********************/
// report to box
function ses_report(text) {
	$('stewiestats').adopt(document.createTextNode(text));
}

/*********************
** Initialize
*********************/
function ses_initialize() {
	// display status box
	if(!document.getElementById('stewiestats')) {
		// create box
		var box = document.createElement('pre');
		box.setAttribute('id', 'stewiestats');
		box.setAttribute('style', 'margin:1em; padding:0.5em; border:1px solid #C00;');
		box.appendChild(document.createTextNode('Loading required framework...\n'));
		editbox.parentNode.insertBefore(box, editbox.parentNode.firstChild);

		// jump to box
		window.location.hash = "#stewiestats";
	}

	// wait until WikiMooTools loaded
	if(!window.$chk) {
		setTimeout('init_update()', 500);
		return;
	}

	// reset box
	$('stewiestats').set({'text':'Loading required framework...\n'});

	// start script
	ses_fetch_page();
}

/*********************
** Fetch page text
*********************/
function ses_fetch_page() {
	/* update status box */
	ses_report('Fetching elections page...\n');

	/* grab page text */
	var request = new Request({
		url:'http://meta.wikimedia.org/wiki/Stewards/elections_2010/votes?action=render',
		method: 'GET',
		onSuccess:ses_parse_page,
		onFailure: function(xhr) {
			ses_report('AJAX error while fetching elections page: ' + xhr.status + ' (' + xhr.statusText + ')\n');
		}
	}).send();
}

/*********************
** Count unique participants
*********************/
function ses_count_participants(text) {
	ses_report('Counting unique participants... ');

	var links = text.match(/title="User:[^\/"]+/ig);
	var names = {};
	var count = 0;

	if(links) {
		for(var i=0, len=links.length; i<len; i++) {
			var name = links[i].match(/User:(.+)/)[1];
			if(!names[name]) {
				names[name] = 1;
				count++;
			}
		}
	}

	ses_report(count + '\n');
	editbox.value = editbox.value.replace(/(<span id="ses_count">).*?(<\/span>)/, '$1' + count + '$2');
}

/*********************
** Extract data from page
*********************/
function ses_parse_page(text, xml) {
	/* update status box */
	ses_report('Extracting data...\n');

	// strip out cruft
	text = text.replace(/^[\s\S]+?<table id="toc"[\s\S]+?<\/table>/, '');		// introduction, TOC, etc
	text = text.replace(/^(<h2.+?<\/h2>)[\s\S]+?<h3[\s\S]+?(<h3)/mg, '$1\n$2');	// statements, 'questions' header
	text = text.replace(/<ul>[\s\S]+?<\/ul>/g, '');					// threaded bullets
	text = text.replace(/^(<(?:h2|h3|li).+\n*)|^.+\n*/mg, '$1');			// everything else except headers and list items
	text = text.replace(/^<h(\d)>.*<span class="mw-headline">.*?>\s*([^<>]+?)\s*<.+<\/h\1>/mg, '<h$1>$2</h$1>');	// simplify headers

 	// count participants
 	ses_count_participants(text);

	// data
	var names    = [];	// all candidate names
	var votes    = [];	// all section titles
	var counts   = {};	// vote counts per section per candidate
	var name     = '';	// current candidate name
	var vote     = '';	// current section ('Yes', 'No', 'Neutral')

 	// parse text
	text    = text.split('\n');
	var len = text.length;
	var line;
	for(var i=0; i<len; i++) {
		line = text[i];

		// li: new vote
		if(line.match('<li')) {
			counts[name][vote]++;
		}
		// h3: new vote section
		else if(line.match('<h3')) {
			vote = line.match(/<h3>(.+)<\/h3>/)[1];
			votes.push(vote);
			counts[name][vote] = 0;
		}
		// h2: new candidate
		else if(line.match('<h2')) {
			name = line.match(/<h2>(.+)<\/h2>/)[1];
			names.push(name);
			counts[name] = {};
		}
	}

	// update table
	ses_gen_table(names, votes, counts);
}

/*********************
** Return formatted date
*********************/
function ses_get_date() {
	// zero pad
	function zero_pad(num) {
		if(num<10)
			num = '0' + num;
		return num;
	}

	// generate string
	var d = new Date();
	var str = d.getUTCFullYear() + '-' + zero_pad(d.getUTCMonth()+1) + '-' + zero_pad(d.getUTCDate()) + ' '
	        + zero_pad(d.getUTCHours()) + ':' + zero_pad(d.getUTCMinutes()) + ' (UTC)';
	return str;
}

/*********************
** Update table
*********************/
function ses_gen_table(names, votes, counts) {
	/* update status box */
	ses_report('Generating updated table...\n');

	/***************
	** Variables
	***************/
	// constants
	var len = names.length;	// number of candidates
	var yes = votes[0];	// title of support headers
	var no  = votes[1];	// title of oppose headers
	// data
	var rows = {};		// all template texts
	var ratios = {};	// all support ratios
	var sorted = [];	// candidate names, sorted by ratio
	// other
	var text = editbox.value;

	/***************
	** Regex to match candidate row template
	***************/
	function reg_candidate_template(name) {
		return new RegExp('{{user[^}]+name *= *' + name + '[^}]+}}', 'mi');
	}

	/***************
	** Fetch & update rows
	***************/
	for(var i=0; i<len; i++) {
		// grab text
		var name = names[i];
		var row  = text.match(reg_candidate_template(name)).toString();

		// update
		row = row.replace(/(support *=).*/, '$1 ' + counts[name][yes]);
		row = row.replace(/(oppose *=).*/, '$1 ' + counts[name][no]);

		// store
		rows[name]   = row;
		ratios[name] = counts[name][yes]/(counts[name][yes]+counts[name][no]);
	}

	/***************
	** Sort rows
	***************/
	for(var i=0; i<len; i++) {
		var name  = names[i];
		var ratio = counts[name][yes]/(counts[name][yes]+counts[name][no]);

		// insert into sorted position
		for(var x=0; x<=sorted.length; x++) {
			// end of array, just stick it in
			if(x==sorted.length) {
				sorted.push(name);
				break;
			}
			else if(ratios[name]>ratios[sorted[x]]) {
				sorted.splice(x, 0, name);
				break;
			}
		}
	}

	/***************
	** Update text
	***************/
	// date
	text = text.replace(/(<span id="ses_date">).*?(<\/span>)/, '$1' + ses_get_date() + '$2');

	// rows
	var str = '';
	for(var i=0; i<len; i++)
		str += rows[sorted[i]] + '\n';
	text = text.replace(/(<!--ses-start-->)[\s\S]+?(<!--ses-end-->)/i, '$1\n' + str + '$2');

	// text
	editbox.value = text;

	/* update status box */
	ses_report('Done.');
}
ses_initialize();
</source>