Note: After saving, you have to bypass your browser's cache to see the changes. Google Chrome, Firefox, Microsoft Edge and Safari: Hold down the ⇧ Shift key and click the Reload toolbar button. For details and instructions about other browsers, see Wikipedia:Bypass your cache.
/*
== Code ==
{{GPL}} <pre> */
//--------------------------------------------------------------
// GLOBAL VARIABLES
//--------------------------------------------------------------
var vs_data = new Array(3); // persistent data : { users, votes, headings }
//--------------------------------------------------------------
// voteProcessor - process an entire dom, extract users & votes
//--------------------------------------------------------------
function voteProcessor(dom) {
var lists = dom.getElementsByTagName("ol");
var votes = new Array();
var users = new Array();
for (i = 0; list = lists[i]; i++) {
var ret = processList(list, users, votes, (lists.length - i) - 1);
if (ret) { // checksafe
users = ret[0];
votes = ret[1];
}
}
vs_data[0] = users;
vs_data[1] = votes;
}
//--------------------------------------------------------------
// getAllHeadings - Detect all headings in the DOM
//--------------------------------------------------------------
function getAllHeadings(dom, headings) {
for (var i = 0; n = dom.childNodes[i]; i++) {
if (n.nodeName.length == 2
&& !isNaN(n.nodeName.substr(1,1))
&& n.nodeName.toLowerCase().substr(0,1) == "h") {
headings[headings.length] = getHeading(n);
}
if (n.childNodes.length > 0) {
headings = getAllHeadings(n, headings); // recurse
}
}
return headings;
}
//--------------------------------------------------------------
// getHeading - Detect the heading text in a node
//--------------------------------------------------------------
function getHeading(n) {
for (var i = 0; el = n.getElementsByTagName("span")[i]; i++) {
if (el.className == "mw-headline") {
return el.innerHTML;
}
}
return "unknown";
}
//--------------------------------------------------------------
// processList - extract users and votes from an option's list
//--------------------------------------------------------------
function processList(list, users, votes, choice) {
if (!list) { return; } // failsafe
for (var i = 0; el = list.getElementsByTagName("li")[i]; i++) {
var uname = getUserFromLiElement(el);
if (uname == "") {
uname = getUnknownUser(el);
if (uname == "") {
return;
}
}
var uid = wasUserRead(uname, users);
if (uid < 0) {
uid=users.length;
votes[uid] = 0;
}
users[uid] = uname;
votes[uid] += Math.pow(2, choice); // binary store
}
ret = new Array(); // pass back by array
ret[0] = users;
ret[1] = votes;
return ret;
}
//--------------------------------------------------------------
// getUserFromLiElement - auto-magically detect user name
//--------------------------------------------------------------
function getUserFromLiElement(lielem) {
for (var i = 0; link = lielem.getElementsByTagName("a")[i]; i++) {
if (link.title.substr(0, 4) == "User") {
return link.title.substr(5, link.title.length);
}
}
return "";
}
//--------------------------------------------------------------
// getUnknownUser - user intervention for weird entries
//--------------------------------------------------------------
function getUnknownUser(el) {
var text = getInnerText(el);
var msg = "Couldn't identify user. Please extract the user's name from the following text.";
var reply = prompt(msg, text);
if (reply == null) { return ""; }
return reply;
}
//--------------------------------------------------------------
// getInnerText - get innerHTML without the HTML tags
//--------------------------------------------------------------
function getInnerText(el) {
var re, text = el.innerHTML;
// remove XML tags
do {
a = text;
text = text.replace(/<[^>\/]*\/>/gi, "");
} while (a != text);
// strip HTML tags
do {
a = text;
text = text.replace(/<[^>]*>([^<]*)<\/[^>]*>/gi, "$1");
} while (a != text);
// remove leading and trailing spaces
text = text.replace(/^\s/gi, "");
text = text.replace(/\s$/gi, "");
return text;
}
//--------------------------------------------------------------
// wasUserRead - O(n) search for user name presence
//--------------------------------------------------------------
function wasUserRead(username, users) {
for (var i = 0; i < users.length; i++) {
if (users[i] == username) { return i; }
}
return -1;
}
//--------------------------------------------------------------
// gen_table - make HTML table preview of results
//--------------------------------------------------------------
function gen_table() {
var users = vs_data[0];
var votes = vs_data[1];
var headings = vs_data[2];
var totals = new Array();
var str = '<table class="wikitable"><tr><th>User</th>';
var i, j, k;
for (i = 0; i < headings.length; i++) {
str += "<th>" + headings[i] + "</th>";
totals[i] = 0;
}
str += "</tr>";
for (i = 0; i < users.length; i++) {
str += "<tr><td>" + users[i] + "</td>";
k = votes[i];
for (j = headings.length-1; j >= 0; j--) { // MSB to LSB
if (k - Math.pow(2, j) >= 0) { // is bit set?
k -= Math.pow(2, j); // turn it off
str += "<td>X</td>";
totals[j]++;
} else {
str += "<td>-</td>";
}
}
str += "</tr>";
}
str += "<tr><th>Total</th>";
for (i = headings.length-1; i >= 0; i--) { // Reverse order
str += "<th>" + totals[i] + "</th>";
}
str += "</table>";
str += "<p><i>" + users.length + " editors voted in this survey.</i></p>"
return str;
}
//--------------------------------------------------------------
// gen_wiki - generate results as wikicode
//--------------------------------------------------------------
function gen_wiki() {
var users = vs_data[0];
var votes = vs_data[1];
var headings = vs_data[2];
var totals = new Array();
var str = '<' + 'pre style="border-style: none; padding: 0; margin: 0"' + '>{|class="wikitable"\n!Users';
var i, j, k;
for (i = 0; i < headings.length; i++) {
str += "!!" + headings[i];
totals[i] = 0;
}
for (i = 0; i < users.length; i++) {
str += "\n|-\n|" + users[i];
k = votes[i];
for (j = headings.length-1; j >= 0; j--) { // MSB to LSB
if (k - Math.pow(2, j) >= 0) { // is bit set?
k -= Math.pow(2, j); // turn it off
str += "|| X ";
totals[j]++;
} else {
str += "|| - ";
}
}
}
str += "\n|-\n!Total";
for (i = headings.length-1; i >= 0; i--) { // Reverse order
str += "!!" + totals[i];
}
str += "\n|}";
str += "\n\n''" + users.length + " editors voted in this survey.''<" + "/pre" + ">";
return str;
}
//--------------------------------------------------------------
// Adapt code for MediaWiki use
//--------------------------------------------------------------
var votescript_url = "User:DavidHOzAu/votescript/ui";
var vs_path_len = document.location.pathname.length;
if (document.location.pathname.substring(vs_path_len - votescript_url.length, vs_path_len) == votescript_url) {
hookDOMEvent(window, "load", uiSetup);
}
//--------------------------------------------------------------
// hookDOMEvent - useful for hooking events in any element
//--------------------------------------------------------------
function hookDOMEvent(dom, hookName, hookFunct) {
if (dom.addEventListener)
dom.addEventListener(hookName, hookFunct, false);
else if (dom.attachEvent)
dom.attachEvent("on" + hookName, hookFunct);
}
//--------------------------------------------------------------
// uiHandler - UI setup code
//--------------------------------------------------------------
function uiSetup() {
// blank the inner contents of the page
var bodyContent = document.getElementById("bodyContent");
while (bodyContent.childNodes.length > 0) bodyContent.removeChild(bodyContent.lastChild);
bodyContent.innerHTML = '<div id="vs-dialog" style="margin: 1em auto 0; padding: 1em; width: 40em; background-color: #eef; border: 1px solid #cbf; position: relative; font-size: medium; -moz-border-radius: 1em; ">'
+ uiLabel("Survey page") + uiWrap("2em", uiButton("fetch", "Fetch", "button") + uiInput("page", "Wikipedia:Village_pump_(proposals)/Sidebar_redesign/Final_draft_vote"))
+ uiLabel("Headers") + uiTextArea("headers", "")
+ uiLabel("Preview") + uiOutput("preview", "")
+ uiLabel("Wikitable") + uiOutput("wiki", "")
+ '</div>' + uiHiddenText("hidden");
document.getElementById("vs-page").style.position = "absolute";
document.getElementById("vs-page").style.left = "0em";
document.getElementById("vs-page").style.width = "32em";
document.getElementById("vs-fetch").style.position = "absolute";
document.getElementById("vs-fetch").style.right = "0em";
document.getElementById("vs-fetch").style.width = "5.5em";
hookDOMEvent(document.getElementById("vs-fetch"), "click", fetchVotes);
hookDOMEvent(document.getElementById("vs-headers"), "change", uiUpdater);
}
//--------------------------------------------------------------
// UI Helper functions
//--------------------------------------------------------------
function uiLabel(label) {
return('<div id="vs-label" style="height: 2em; background-color: #eef; cursor: default; position: relative">'
+ '<div id="vs-label-text" style="position: absolute; bottom: 0; left: 0; background-color: #eef; z-index: 3">' + label
+ ' </div><div id="vs-label-rule" style="position: absolute; bottom: 0.7em; right: 0; width: 100%; z-index: 2; height: 2px; border-bottom: 2px groove white"></div></div>');
}
function uiWrap(h, text) {
return('<div id="vs-wrap" style="margin: 0.5em 1em; height: ' + h + '; position: relative">' + text + '</div>');
}
function uiInput(id, text) {
return('<input name="' + id + '" value="' + text + '" id="vs-' + id + '" title="' + id + '" style="font-size: 100%"/>');
}
function uiButton(id, text, type) {
return('<input type="' + type + '" value="' + text + '" id="vs-' + id + '" title="' + id + '" style="font-size: 100%"/>');
}
function uiTextArea(id, text) {
return uiWrap("auto", '<textarea name="' + id + '" id="vs-' + id + '" style="cursor: text; width: 100%; height: 10em">' + text + '</textarea>');
}
function uiOutput(id, text) {
return uiWrap("auto", '<div id="vs-' + id + '" style="overflow: auto; cursor: text; background-color: #f8f8ff; border: 1px solid #b8b8b8; height: 10em">' + text + '</div>');
}
function uiHiddenText(id) {
return('<div id="vs-' + id + '" style="display: none; speak: none"></div>');
}
//--------------------------------------------------------------
// uiUpdater - update contents when heading text changes
//--------------------------------------------------------------
function uiUpdater() {
vs_data[2] = document.getElementById("vs-headers").value.split(/[\n\r]+/);
document.getElementById("vs-preview").innerHTML = gen_table();
document.getElementById("vs-wiki").innerHTML = gen_wiki();
}
//--------------------------------------------------------------
// fetchVotes - fetch DOM of requested page
//--------------------------------------------------------------
function fetchVotes(event) {
document.getElementById("vs-preview").innerHTML = "<i>Loading...</i>";
x = sajax_init_object();
if (!x) {
alert("AJAX not supported");
return false;
}
var url = document.getElementById("vs-page").value;
x.onreadystatechange = function () { voteFetcher(x); };
url = wgScriptPath + "/index.php?title=" + escape(url) + "&action=render";
x.open("GET", url, true);
x.send(null);
}
//--------------------------------------------------------------
// voteFetcher - handle XMLHttpRequest messages
//--------------------------------------------------------------
function voteFetcher(x) {
if (x.readyState == 3) { /* document.write(x.getAllResponseHeaders()); */ }
if (x.readyState != 4) { return; }
if (x.status != 200) {
document.getElementById("vs-preview").innerHTML = "<i>Page not found or network error</i>";
return;
}
if (x.responseText) {
var dom = document.createElement("div"); // placeholder
dom.innerHTML = x.responseText; // hack
vs_data[2] = getAllHeadings(dom, new Array()); // get _ALL_ headings
voteProcessor(dom); // process dom for votes
for (head in vs_data[2]) {
document.getElementById("vs-headers").value += vs_data[2][head] + '\r\n';
}
uiUpdater();
} else {
document.getElementById("vs-preview").innerHTML = "<i>Response empty</i>";
}
}
/* </pre> */