User:Interiot/Tool2/code.js'
// see http://paperlined.org/apps/wikipedia/Tool2/ for instructions on adding this to your monobook.js
// To run this tool on other servers: // 1. copy this script to the target server (this is required because of javascript cross-site security restrictions)
// 2. update the following URL // for example: "User:Interiot/Tool2/code.js" var tool2_url = "User:Interiot/Tool2/code.js";
// 3. update this namespace list, extracted from something like http://en.wikiquote.org/wiki/Special:Export// // These *should not* have colons after them. var namespaces = [ "Talk", "User", "User talk", "Wikiquote", "Wikiquote talk", "Image", "Image talk", "MediaWiki", "MediaWiki talk", "Template", "Template talk", "Help", "Help talk", "Category", "Category talk", // 3b. these two project project entries are not added by Special:Export, and might or might not need to be updated "Wikipedia", "Wikipedia talk" ];
namespaces[100] = "Portal"; namespaces[101] = "Portal talk";
// 4. update this date-parser to match the format and language of your specific wiki. Feel free to contact Interiot regarding this, if you can't find another // copy of this script that uses the same language. // input: a text string from Special:Contributions. output: a javascript Date object // documentation: http://www.quirksmode.org/js/introdate.html#parse, http://www.elated.com/tutorials/programming/javascript/dates/ function date_parse(text) { var matches = text.match(/^([0-9:]+), +([0-9]+) +([a-z]+) +([0-9]+)$/i); if (!matches) { //dump_text("XXX"); // for debugging return matches; }
parseme = matches[3] + ", " + matches[2] + " " + matches[4] + " " + matches[1] + ":00";
//dump_text(parseme); // for debugging
var dt = new Date(); dt.setTime( Date.parse(parseme));
//dump_text(dt.toLocaleString()); // for debugging
return dt; }
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ end of server-specific configuration ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
// TODO: // - the current document.location method doesn't work when the page is accessed sans-mod_rewrite // - test with non-ASCII characters // - non-ascii usernames // - ??
var prefix = ""; var params = parse_params();
addOnloadFunction(function() {
var path_len = document.location.pathname.length; // trigger once we view the right page if (document.location.pathname.substring(path_len - tool2_url.length, path_len) == tool2_url) { // get the prefix (needs to be fixed to work sans-mod_rewrite prefix = document.location.protocol + "//" + document.location.host + "/" + document.location.pathname.substring(1, path_len - tool2_url.length);
// blank the inner contents of the page var bodyContent = document.getElementById("bodyContent"); while (bodyContent.childNodes.length > 0) bodyContent.removeChild(bodyContent.lastChild);
if (document.location.search.length == 0) { generate_input_form(bodyContent); } else { generate_main_report(bodyContent); } }
});
function generate_input_form(bodyContent) {
if (navigator.userAgent.toLowerCase().indexOf('msie')+1) { bodyContent.innerHTML = "This counter does not currently work in Internet Explorer. Please <a href='http://www.getfirefox.com'>get Firefox</a> or use <a href='http://en.wikipedia.org/wiki/Wikipedia:WikiProject_edit_counters/Flcelloguy%27s_Tool'>Flcelloguy's Tool</a> instead."; } else { bodyContent.innerHTML =
"<form>
Username | <input maxlength=128 name=username value= id=username title='username'>" + " |
<input type=submit value='Submit'>" + " |
</form>";
var form = bodyContent.getElementsByTagName("form")[0]; form.method = "get"; form.action = document.location;
document.getElementById("username").focus(); }
}
function generate_main_report() {
fetch_data(params["username"].replace(/\+/g, " "),
"", output_main_report, 0, []); }
function add_stats_row(left_col, right_col) {
var row = document.createElement("tr");
var left = document.createElement("td");
var right = document.createElement("td");
document.getElementById("basic_stats").appendChild(row); row.appendChild(left); row.appendChild(right); //left.innerHTML = left_col; left.appendChild( document.createTextNode(left_col) ); right.appendChild( document.createTextNode(right_col) ); return row; }
function output_main_report(history) { // -- generate summary statistics var unique_articles = new Array(); var namespace_numedits = new Array(); for (var i=0; i<namespaces.length; i++) { namespace_numedits[ namespaces[i] ] = 0; } namespace_numedits[""] = 0; for (var i=0; i<history.length; i++) { var h = history[i]; unique_articles[ h["title"] ]++; namespace_numedits[ h["namespace"] ]++; } var unique_articles_keys = keys(unique_articles);
// -- output report var table = document.createElement("table"); table.id = "basic_stats"; document.getElementById("bodyContent").appendChild(table);
add_stats_row("Username", params["username"].replace(/\+/g, " ")); add_stats_row("Total edits", history.length); add_stats_row("Distinct pages edited", unique_articles_keys.length); add_stats_row("Average edits/page", new Number(history.length / unique_articles_keys.length).toFixed(3)); add_stats_row("First edit", history[ history.length-1 ]["date_text"] );
// add a blank row add_stats_row("", "").childNodes[0].style.height = "1em";
add_stats_row("(main)", namespace_numedits[""]); for (var i=0; i<namespaces.length; i++) { var nmspc = namespaces[i]; if (namespace_numedits[nmspc]) { add_stats_row(nmspc, namespace_numedits[nmspc]); } } }
// ===================================== HTML-scraping backend =========================================
function add_loading_notice() {
if (document.getElementById("loading_notice"))
return;
var loading = document.createElement("div");
loading.id = "loading_notice";
loading.innerHTML = "
Retrieving data<blink>...</blink>";
document.getElementById("bodyContent").appendChild(loading);
}
function remove_loading_notice() {
var loading = document.getElementById("loading_notice");
if (!loading) return;
loading.parentNode.removeChild(loading);
}
var offset_regexp = /href="[^"]+:Contributions[^"]+offset=(\d+)/gi; function fetch_data(username, end_date, handler, offset, page_list) { add_loading_notice(); var url = prefix + "Special:Contributions/" + username + "?offset=" + offset + "&limit=5000"; loadXMLDoc(url, function (request) { var next_offset = 0; if (request.readyState != 4) return; if (request.status == 200) { page_list.push(request.responseText); //dump_text(request.responseText);
// see if there's another pageful to get var matches = map( function(p){ return p.match( /(\d+)$/ )[0]; }, request.responseText.match( offset_regexp ) ); for (var i=0; i<matches.length; i++) { var v = matches[i] * 1; if (v != 0 && (offset == 0 || v < offset)) { next_offset = v; break; } } }
//next_offset = 0; // for testing only, retrieve just the first page of results
if (next_offset == 0) { parse_data(page_list, handler); } else { // tail recurse fetch_data(username, end_date, handler, next_offset, page_list); } }); }
// input: a list of strings, each string containing the HTML from a single page
// output: a list, where each individual entry is a specific edit from history
function parse_data(page_list, handler) {
//var total_len = 0;
//for (var i=0; i<page_list.length; i++) total_len += page_list[i].length;
//alert("parsing " + page_list.length + " pages comprising " + total_len + " total bytes");
var last_history_ent = []; last_history_ent["title"] = ""; last_history_ent["oldid"] = "";
var edit_history = new Array(); for (var pagecnt=0; pagecnt<page_list.length; pagecnt++) {
var matches = page_list[pagecnt].match( /^