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(" var TableEndIndex=ProgressText.indexOf(" 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+=" 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();});
",TableStartIndex)+2;",TableStartIndex+1);
Editing page...";