User:Magicpiano/NRBot/NRHPmap.js

/* jshint maxerr: 3000 */

var g_disabled = false;

var bIgnoreTableCount = false; // for testing, is it ok to ignore table miscount

var AuthorizedUsers = ["Magicpiano"]; // users authorized if g_disabled is true

var g_TestInput = "User:Magicpiano/NRBot/NRHPmapTester";

var g_TestOutput = "User:Magicpiano/NRBot/NRHPmapSVG";

var g_NRHPmapInput = "Wikipedia:WikiProject_National_Register_of_Historic_Places/Progress";

var g_NRHPmapOutput = "Wikipedia:WikiProject_National_Register_of_Historic_Places/Progress/SVG";

function NRHPmapbutton() {

var bNotHere = true;

if (mw.config.get('wgPageName')=="Wikipedia:WikiProject_National_Register_of_Historic_Places/Progress") bNotHere = false;

if (mw.config.get('wgPageName')==g_TestInput)

{

bNotHere = false;

bIgnoreTableCount = true;

g_NRHPmapInput = g_TestInput;

g_NRHPmapOutput = g_TestOutput;

}

// the above notwithstanding, if in edit mode we also ignore

if (location.href.indexOf('action')!=-1) bNotHere = true;

if (bNotHere) return;

var button=document.getElementById("NRHPUpdateMapButton");

if (button !== null) return;

button = document.createElement("input");

button.setAttribute("type", "button");

button.setAttribute("value", "Generate SVG Output");

button.setAttribute("onclick", "MapButtonClick()");

button.id = "NRHPUpdateMapButton";

var content=document.getElementById('mw-content-text');

content.parentNode.insertBefore(button, content);

}

function CheckPermission() {

if (!g_disabled) return true;

var username = mw.user.getName(); for (var i=0; i< AuthorizedUsers.length; i++) {

if (username == AuthorizedUsers[i]) {

return true;

}

}

if (g_disabled) {

alert("Script is currently disabled for maintenance.");

return false;

}

return true;

}

function MapButtonClick() {

if (!CheckPermission()) return;

var button = document.getElementById('NRHPUpdateMapButton');

button.disabled = true;

var SVGDiv = document.getElementById('SVGDiv');

if (SVGDiv === null) {

SVGDiv = document.createElement('div');

SVGDiv.setAttribute('id', 'SVGDiv');

SVGDiv.setAttribute("style", "width:500px; border:1px solid black; padding:5px");

button.parentNode.insertBefore(SVGDiv, button);

}

SVGDiv.innerHTML = "Fetching wikitext...";

getSVGtext(g_NRHPmapOutput);

}

function safelyGetRevision(title, output)

{

var result;

var page;

try {

for (page in output.query.pages) {

result=output.query.pages[page].revisions[0]['*'];

return result;

}

}

catch (e) {

result = "error";

console.log("Error fetching "+title+" revision "+page);

console.log("Output",output);

console.log("Exception",e);

}

return result;

}

function getSVGtext(title) { // get SVG code from /SVG page

var SVGtext="";

$.ajax({

dataType: "json",

url: mw.util.wikiScript('api'),

data: {

format: 'json',

action: 'query',

prop: 'revisions',

rvprop: 'content',

titles: title,

indexpageids: true,

redirects: 'true'

},

error: function() {SVGtext="error"},

success: function(output) {

SVGtext = safelyGetRevision(title,output);

},

complete: function() {

if (SVGtext=="error") {

var SVGDiv=document.getElementById("SVGDiv");

SVGDiv.innerHTML+=" Unable to fetch wikitext! Script aborted.";

} else {

getProgressText(SVGtext,g_NRHPmapInput);

}

}

});

}

function getProgressText(SVGtext,title) { // get progress page wikitext

var ProgressText="";

$.ajax({

dataType: "json",

url: mw.util.wikiScript('api'),

data: {

format: 'json',

action: 'query',

prop: 'revisions',

rvprop: 'content',

titles: title,

indexpageids: true,

redirects: 'true'

},

error: function() {ProgressText="error"},

success: function(output) {

for (var page in output.query.pages) {

ProgressText=output.query.pages[page].revisions[0]['*'];

}

},

complete: function() {

if (ProgressText=="error") {

var SVGDiv=document.getElementById("SVGDiv");

SVGDiv.innerHTML+=" Unable to fetch wikitext! Script aborted.";

} else {

ExtractMapInfo(SVGtext,ProgressText);

}

}

});

}

function ExtractMapInfo(SVGtext,ProgressText) {

var SVGDiv=document.getElementById("SVGDiv");

SVGDiv.innerHTML+=" Done!";

ProgressText=ProgressText.split("==State totals==")[1]; // get rid of header

var StateNames= ["OVERALL STATE PERCENTAGES","ALABAMA","ALASKA","ARIZONA","ARKANSAS","CALIFORNIA","COLORADO","CONNECTICUT","DELAWARE"];

StateNames.push("D.C.","FLORIDA","GEORGIA","HAWAII","IDAHO","ILLINOIS","INDIANA","IOWA","KANSAS","KENTUCKY","LOUISIANA","MAINE");

StateNames.push("MARYLAND","MASSACHUSETTS","MICHIGAN","MINNESOTA","MISSISSIPPI","MISSOURI","MONTANA","NEBRASKA","NEVADA");

StateNames.push("NEW HAMPSHIRE","NEW JERSEY","NEW MEXICO","NEW YORK","NORTH CAROLINA","NORTH DAKOTA","OHIO","OKLAHOMA","OREGON");

StateNames.push("PENNSYLVANIA","RHODE ISLAND","SOUTH CAROLINA","SOUTH DAKOTA","TENNESSEE","TEXAS","UTAH","VERMONT");

StateNames.push("VIRGINIA","WASHINGTON","WEST VIRGINIA","WISCONSIN","WYOMING");

var StateAbbrs= ['XX','AL','AK','AZ','AR','CA','CO','CT','DE','DC','FL','GA','HI','ID','IL','IN','IA','KS','KY','LA','ME','MD'];

StateAbbrs.push('MA','MI','MN','MS','MO','MT','NE','NV','NH','NJ','NM','NY','NC','ND','OH','OK','OR','PA','RI','SC','SD');

StateAbbrs.push('TN','TX','UT','VT','VA','WA','WV','WI','WY','PR','GU','VI','MP','AS');

var TempStartIndex;

var TempEndIndex;

var i,j,k;

var nextID;

var nextRowText;

var StatsToCheck=["Illustrated","Articled","Start+","Net Quality"];

for (var currentStat=0; currentStat

var ThisStatText="";

var OverallStatePercentagesText="";

var NoListings=[];

var total;

var illustrated;

var stubs;

var NRISonly;

var startPlus;

var unassessed;

var untagged;

var articled;

var Percentage=0;

var TableStartIndex=0;

for (i=0; i

var StateTable={"100Percent":[], "90Percent":[], "80Percent":[], "70Percent":[], "60Percent":[], "50Percent":[], "40Percent":[], "30Percent":[], "20Percent":[], "10Percent":[], "00Percent":[]};

TableStartIndex=ProgressText.indexOf("

",TableStartIndex+1);

var TableEndIndex=ProgressText.indexOf("

",TableStartIndex)+2;

var TableText=ProgressText.substr(TableStartIndex,TableEndIndex-TableStartIndex);

var RowStartIndex=0;

var RowNumber=0;

var DCdone=false;

while (RowStartIndex!=-1) { // loop until no more rows

RowStartIndex=TableText.indexOf("\n|-",RowStartIndex+1); // find next row in table

var RowEndIndex=TableText.indexOf("\n|-",RowStartIndex+1);

if (RowEndIndex==-1) RowEndIndex=TableText.length; // last row ends at end of table

var RowText=TableText.substr(RowStartIndex,RowEndIndex-RowStartIndex);

RowNumber++;

if (i===0&&RowNumber==StateAbbrs.length) break; // manual break for national table since some rows aren't on the map

var ID=RowText.match(/(\d{5}|-----|ddddd)/g);

if (i===0) ID=StateAbbrs[RowNumber];

if (ID===null||ID[0]=="ddddd"||ID[0]=="-----") continue; // skip duplicate rows, sublists, and state total row

if (i!==0) ID=ID[0];

/*

if (ID=="02230"||ID=="02275"||ID=="02063") continue; // skip special cases in Alaska, taken care of below

if (ID=="02105") { // special case for Hoonah–Angoon Census Area, Alaska

TempStartIndex=RowStartIndex;

nextID="00000";

while (nextID!="02230") { // look for Skagway

TempStartIndex=TableText.indexOf("\n|-",TempStartIndex+1);

TempEndIndex=TableText.indexOf("\n|-",TempStartIndex+1);

if (TempEndIndex==-1) TempEndIndex=TableText.length;

nextRowText=TableText.substr(TempStartIndex,TempEndIndex-TempStartIndex);

nextID=nextRowText.match(/(\d{5}|-----|ddddd)/g);

if (nextID!==null) nextID=nextID[0];

}

var HoonahStats=RowText.match(/[^\d](\d{1,3},)*\d{1,3}(?!(%|\.|\d))/g);

var SkagwayStats=nextRowText.match(/[^\d](\d{1,3},)*\d{1,3}(?!(%|\.|\d))/g);

switch(currentStat) {

case 0: // Illustrated

total=parseFloat(HoonahStats[0])+parseFloat(SkagwayStats[0]);

illustrated=parseFloat(HoonahStats[1])+parseFloat(SkagwayStats[1]);

Percentage=Math.round(illustrated/total*1000)/10;

break;

case 1: // Articled

total=parseFloat(HoonahStats[0])+parseFloat(SkagwayStats[0]);

articled=parseFloat(HoonahStats[2])+parseFloat(SkagwayStats[2]);

Percentage=Math.round(articled/total*1000)/10;

break;

case 2: // Start+

total=parseFloat(HoonahStats[0])+parseFloat(SkagwayStats[0]);

startPlus=parseFloat(HoonahStats[5])+parseFloat(SkagwayStats[5]);

Percentage=Math.round(startPlus/total*1000)/10;

break;

case 3: // Net Quality

total=parseFloat(HoonahStats[0])+parseFloat(SkagwayStats[0]);

illustrated=parseFloat(HoonahStats[1])+parseFloat(SkagwayStats[1]);

stubs=parseFloat(HoonahStats[3])+parseFloat(SkagwayStats[3]);

NRISonly=parseFloat(HoonahStats[4])+parseFloat(SkagwayStats[4]);

startPlus=parseFloat(HoonahStats[5])+parseFloat(SkagwayStats[5]);

unassessed=parseFloat(HoonahStats[6])+parseFloat(SkagwayStats[6]);

untagged=parseFloat(HoonahStats[7])+parseFloat(SkagwayStats[7]);

Percentage=startPlus+0.5*stubs+0.5*unassessed-0.5*untagged-0.75*NRISonly;

Percentage=Math.round((0.75*Percentage/total+0.25*illustrated/total)*1000)/10;

if (Percentage<0) Percentage = 0;

break;

}

ID="02232"; // set special ID for map

} else if (ID=="02280") { // special case for Petersburg Census Area, Alaska

TempStartIndex=RowStartIndex;

nextID="00000";

while (nextID!="02275") { // look for Wrangell

TempStartIndex=TableText.indexOf("\n|-",TempStartIndex+1);

TempEndIndex=TableText.indexOf("\n|-",TempStartIndex+1);

if (TempEndIndex==-1) TempEndIndex=TableText.length;

nextRowText=TableText.substr(TempStartIndex,TempEndIndex-TempStartIndex);

nextID=nextRowText.match(/(\d{5}|-----|ddddd)/g);

if (nextID!==null) nextID=nextID[0];

}

var PetersburgStats=RowText.match(/[^\d](\d{1,3},)*\d{1,3}(?!(%|\.|\d))/g);

var WrangellStats=nextRowText.match(/[^\d](\d{1,3},)*\d{1,3}(?!(%|\.|\d))/g);

Percentage=0;

switch(currentStat) {

case 0: // Illustrated

total=parseFloat(PetersburgStats[0])+parseFloat(WrangellStats[0]);

illustrated=parseFloat(PetersburgStats[1])+parseFloat(WrangellStats[1]);

Percentage=Math.round(illustrated/total*1000)/10;

break;

case 1: // Articled

total=parseFloat(PetersburgStats[0])+parseFloat(WrangellStats[0]);

articled=parseFloat(PetersburgStats[2])+parseFloat(WrangellStats[2]);

Percentage=Math.round(articled/total*1000)/10;

break;

case 2: // Start+

total=parseFloat(PetersburgStats[0])+parseFloat(WrangellStats[0]);

startPlus=parseFloat(PetersburgStats[5])+parseFloat(WrangellStats[5]);

Percentage=Math.round(startPlus/total*1000)/10;

break;

case 3: // Net Quality

total=parseFloat(PetersburgStats[0])+parseFloat(WrangellStats[0]);

illustrated=parseFloat(PetersburgStats[1])+parseFloat(WrangellStats[1]);

stubs=parseFloat(PetersburgStats[3])+parseFloat(WrangellStats[3]);

NRISonly=parseFloat(PetersburgStats[4])+parseFloat(WrangellStats[4]);

startPlus=parseFloat(PetersburgStats[5])+parseFloat(WrangellStats[5]);

unassessed=parseFloat(PetersburgStats[6])+parseFloat(WrangellStats[6]);

untagged=parseFloat(PetersburgStats[7])+parseFloat(WrangellStats[7]);

Percentage=startPlus+0.5*stubs+0.5*unassessed-0.5*untagged-0.75*NRISonly;

Percentage=Math.round((0.75*Percentage/total+0.25*illustrated/total)*1000)/10;

if (Percentage<0) Percentage = 0;

break;

}

} else if (ID == "02061") { // former Valdez-Cordova Census Area, now placeholder for Copper River

TempStartIndex=RowStartIndex;

nextID="00000";

while (nextID!="02063") { // look for Chugach Census Area

TempStartIndex=TableText.indexOf("\n|-",TempStartIndex+1);

TempEndIndex=TableText.indexOf("\n|-",TempStartIndex+1);

if (TempEndIndex==-1) TempEndIndex=TableText.length;

nextRowText=TableText.substr(TempStartIndex,TempEndIndex-TempStartIndex);

nextID=nextRowText.match(/(\d{5}|-----|ddddd)/g);

if (nextID!==null) nextID=nextID[0];

}

var CopperRiverStats=RowText.match(/[^\d](\d{1,3},)*\d{1,3}(?!(%|\.|\d))/g);

var ChugachStats=nextRowText.match(/[^\d](\d{1,3},)*\d{1,3}(?!(%|\.|\d))/g);

Percentage=0;

switch(currentStat) {

case 0: // Illustrated

total=parseFloat(CopperRiverStats[0])+parseFloat(ChugachStats[0]);

illustrated=parseFloat(CopperRiverStats[1])+parseFloat(ChugachStats[1]);

Percentage=Math.round(illustrated/total*1000)/10;

break;

case 1: // Articled

total=parseFloat(CopperRiverStats[0])+parseFloat(ChugachStats[0]);

articled=parseFloat(CopperRiverStats[2])+parseFloat(ChugachStats[2]);

Percentage=Math.round(articled/total*1000)/10;

break;

case 2: // Start+

total=parseFloat(CopperRiverStats[0])+parseFloat(ChugachStats[0]);

startPlus=parseFloat(CopperRiverStats[5])+parseFloat(ChugachStats[5]);

Percentage=Math.round(startPlus/total*1000)/10;

break;

case 3: // Net Quality

total=parseFloat(CopperRiverStats[0])+parseFloat(ChugachStats[0]);

illustrated=parseFloat(CopperRiverStats[1])+parseFloat(ChugachStats[1]);

stubs=parseFloat(CopperRiverStats[3])+parseFloat(ChugachStats[3]);

NRISonly=parseFloat(CopperRiverStats[4])+parseFloat(ChugachStats[4]);

startPlus=parseFloat(CopperRiverStats[5])+parseFloat(ChugachStats[5]);

unassessed=parseFloat(CopperRiverStats[6])+parseFloat(ChugachStats[6]);

untagged=parseFloat(CopperRiverStats[7])+parseFloat(ChugachStats[7]);

Percentage=startPlus+0.5*stubs+0.5*unassessed-0.5*untagged-0.75*NRISonly;

Percentage=Math.round((0.75*Percentage/total+0.25*illustrated/total)*1000)/10;

if (Percentage<0) Percentage = 0;

break;

}

} else */ if (ID=="11001") { // special case for DC

if (DCdone) continue; // only record DC once

DCdone=true;

TempStartIndex=RowStartIndex;

var matched=false;

while (!matched) { // look for total row

TempStartIndex=TableText.indexOf("\n|-",TempStartIndex+1);

TempEndIndex=TableText.indexOf("\n|-",TempStartIndex+1);

if (TempEndIndex==-1) TempEndIndex=TableText.length;

nextRowText=TableText.substr(TempStartIndex,TempEndIndex-TempStartIndex);

var test=nextRowText.match("State Total");

if (test!==null) matched=true;

}

Percentage=nextRowText.match(/(\d|\.)+(?=%)/g);

Percentage=parseFloat(Percentage[currentStat]);

} else {

Percentage=RowText.match(/(\d|\.)+(?=%)/g); // extract percentages from row text

if (Percentage===null) {NoListings.push(ID); continue} // if no percentages, must be no listings

Percentage=parseFloat(Percentage[currentStat]); // get relevant percentage for this stat

}

if (Percentage==100) {StateTable["100Percent"].push(ID)}

else if (Percentage>=90) {StateTable["90Percent"].push(ID)}

else if (Percentage>=80) {StateTable["80Percent"].push(ID)}

else if (Percentage>=70) {StateTable["70Percent"].push(ID)}

else if (Percentage>=60) {StateTable["60Percent"].push(ID)}

else if (Percentage>=50) {StateTable["50Percent"].push(ID)}

else if (Percentage>=40) {StateTable["40Percent"].push(ID)}

else if (Percentage>=30) {StateTable["30Percent"].push(ID)}

else if (Percentage>=20) {StateTable["20Percent"].push(ID)}

else if (Percentage>=10) {StateTable["10Percent"].push(ID)}

else {StateTable["00Percent"].push(ID)}

}

ThisStatText+="/* *******************************************************************\n";

ThisStatText+=" " + StateNames[i] + "\n";

ThisStatText+="******************************************************************** */\n";

var colors=["313695","4575B4","74ADD1","ABD9E9","E0F3F8","FFFFBF","FEE090","FDAE61","F46D43","D73027","A50026"];

for (j=10; j>-1; j--) { // loop through each percentage

ThisStatText+="/* ";

if (j!==0) ThisStatText+=j;

ThisStatText+="0% "+StatsToCheck[currentStat]+" */\n ";

for (k=0; k

if (i===0) {

ThisStatText+="."+StateTable[j+"0Percent"][k]+", ";

} else {

ThisStatText+="#c"+StateTable[j+"0Percent"][k]+", ";

}

}

if (StateTable[j+"0Percent"].length>0) ThisStatText=ThisStatText.substr(0,ThisStatText.length-2)+" ";

ThisStatText+="{fill: #"+colors[j]+"; }\n";

}

ThisStatText+="\n";

if (i===0) { // wait to add state totals to end of list

OverallStatePercentagesText=ThisStatText.substr(0,ThisStatText.length-2); // remove final line breaks

ThisStatText="";

}

}

// now add no listings text

ThisStatText+="/* *******************************************************************\n";

ThisStatText+=" NO LISTINGS IN COUNTY\n";

ThisStatText+="******************************************************************** */\n ";

for (k=0; k

ThisStatText+=".c"+NoListings[k]+", ";

}

if (NoListings.length>0) ThisStatText=ThisStatText.substr(0,ThisStatText.length-2)+" ";

ThisStatText+="{fill: #000000; }\n\n";

// finally add state totals text

ThisStatText+=OverallStatePercentagesText;

// now update SVG text

var StartIndex = 0;

var InsertLocations = [];

var SearchStr = 'overflow:scroll">';

for (i=0; i

InsertLocations[i] = SVGtext.indexOf(SearchStr, StartIndex) + SearchStr.length + 1;

StartIndex = InsertLocations[i];

}

StartIndex = 0;

var EndInsertLocations = [];

SearchStr = '';

for (i=0; i

EndInsertLocations[i] = SVGtext.indexOf(SearchStr, StartIndex) - 1;

StartIndex = EndInsertLocations[i] + SearchStr.length + 1;

}

var oldStatText=SVGtext.substr(InsertLocations[currentStat],EndInsertLocations[currentStat]-InsertLocations[currentStat]);

SVGtext=SVGtext.replace(oldStatText,ThisStatText);

}

// now edit page with updated SVG text

var d=new Date();

var months = ['January','February','March','April','May','June','July','August','September','October'];

months.push('November','December');

var year=d.getYear();

if (year < 1000) year += 1900;

var DateStr = months[d.getMonth()]+" "+d.getDate()+", "+year;

var summary="Updating SVG output as of "+DateStr+" using script.";

SVGDiv.innerHTML+="
Editing page...";

editMapPage(g_NRHPmapOutput,SVGtext,summary);

}

function editMapPage(title,text,summary) { // edit page when done

$.ajax({

dataType: 'json',

url: mw.util.wikiScript( 'api' ),

type: 'POST',

data: {

format: 'json',

action: 'edit',

title: title,

text: text,

summary: summary,

token: mw.user.tokens.get( 'csrfToken' )

},

success: function( data ) {

if (data && data.edit && data.edit.result && data.edit.result == 'Success') {

console.log('Page edit succeeded');

} else {

console.log('Page edit failed',data);

var msg;

if (data && data.error) {

msg = "Error editing page: ";

msg += " code=" + data.error.code;

msg += " info=" + data.error.info;

} else {

msg = "Error editing page (no data or error)";

}

alert(msg);

}

},

error: function(ajaxResponse,status,errorThrown) {ajaxResponse.errorThrown=errorThrown},

complete: function(ajaxResponse,status) {MapPageEdited(title,ajaxResponse,status)}

});

}

function MapPageEdited(title,ajaxResponse,status) {

var SVGDiv=document.getElementById("SVGDiv");

if (status!="success") {

console.log("Edit of map page failed",title,ajaxResponse,status);

SVGDiv.innerHTML+="Edit failed!";

return;

}

var responseText=JSON.parse(ajaxResponse.responseText);

var diff=responseText.edit.newrevid;

var linkStr="//en.wikipedia.org/w/index.php?diff="+diff;

SVGDiv.innerHTML+="Page edited! Click here for diff.";

}

function MakePreCopyable() {

var curpage = mw.config.get('wgPageName');

//console.log('MakePreCopyable', curpage, g_NRHPmapOutput);

if (curpage != g_NRHPmapOutput) return;

var pres = document.getElementsByTagName('pre');

//console.log('Number of pre tags',pres.length);

while (pres.length>0) {

var textarea = document.createElement('textarea');

textarea.innerHTML = pres[0].innerHTML;

pres[0].parentNode.insertBefore(textarea,pres[0].nextSibling);

pres[0].parentNode.removeChild(pres[0]);

textarea.setAttribute('style', 'width: 580px; height: 300px');

textarea.setAttribute('onclick', 'this.focus();this.select()');

}

}

$.when($.ready).then(function () { NRHPmapbutton(); MakePreCopyable();});