Last active
December 16, 2018 06:14
-
-
Save Klaster1/320ef4110b3ea34766710301c66882af to your computer and use it in GitHub Desktop.
MobyGames Credits Tool userscript
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ==UserScript== | |
// @name MobyGames Credits Tool | |
// @author Klaster_1 | |
// @version 0.5 | |
// @include http://www.mobygames.com/game/sheet/contribute/credits | |
// @include https://www.mobygames.com/game/sheet/contribute/credits | |
// @include http://www.mobygames.com/approval/game/edit_developer | |
// @include https://www.mobygames.com/approval/game/edit_developer | |
// @match http://www.mobygames.com/game/sheet/contribute/credits | |
// @match https://www.mobygames.com/game/sheet/contribute/credits | |
// @match http://www.mobygames.com/approval/game/edit_developer | |
// @match https://www.mobygames.com/approval/game/edit_developer | |
// @icon https://raw.github.com/klaster1/mobytools/master/images/icon.png | |
// @downloadURL https://gist.github.com/Klaster1/320ef4110b3ea34766710301c66882af/raw/MobyGames%2520Credits%2520Tool.user.js | |
// @updateURL https://gist.github.com/Klaster1/320ef4110b3ea34766710301c66882af/raw/MobyGames%2520Credits%2520Tool.user.js | |
// @run-at document-end | |
// ==/UserScript== | |
/*jslint browser:true,devel:true,es5:true*/ | |
(function(){ | |
"use strict"; | |
console.log("Loading Credits Tool"); | |
// Prototype.js is evil | |
delete Array.prototype.toJSON; | |
// Important objects | |
var credits={ | |
get value(){ | |
return JSON.parse(sessionStorage.getItem("credits")); | |
}, | |
set value(data){ | |
sessionStorage.setItem("credits",JSON.stringify(data)); | |
} | |
}; | |
var step=parseInt(document.querySelector("input[name='step']").value,10); | |
// Input and output of data | |
var exportJSON=function(data){ | |
window.open("data:text/json;charset=utf-8,"+ | |
encodeURIComponent(JSON.stringify(data,null,"\t")),"credits","width=600,height=600"); | |
}; | |
var importJSON=function(){ | |
var fr=new FileReader(), | |
u=document.querySelector("#upload"); | |
if(typeof fr.onload!=="function" && typeof u.onchange!=="function"){ | |
u.onchange=function(e){ | |
fr.readAsText(e.target.files[0]); | |
}; | |
fr.onload=function(){ | |
credits.value=JSON.parse(this.result); | |
u.value=""; | |
}; | |
} | |
u.click(); | |
}; | |
var removeCredits=function(){ | |
sessionStorage.removeItem("credits"); | |
}; | |
// Step 2 | |
var fillGroups=function(){ | |
var names=credits.value.map(function(e){return e.name;}), | |
fields=document.querySelectorAll("#addgroup .FormLt1"), | |
i=0,nl=names.length,fl=fields.length; | |
for(;i<nl&&i<fl;i++){ | |
fields[i].value=names[i]; | |
} | |
document.querySelector("input[type=submit][name=update]").focus(); | |
}; | |
var padGroups=function(){ | |
var g=document.querySelectorAll("input.FormLt1"); | |
for(var i=0;i<g.length-5;i++){ | |
g[0].value+=new Array(i+1).join(" "); | |
} | |
}; | |
// Step 3 | |
var createRoleLine=function(groupId,index,role,devIndex){ | |
var tr=document.createElement("tr"); | |
tr.setAttribute("class","cEntry"); | |
tr.setAttribute("id","entryLine"+index); | |
tr.setAttribute("valign","top"); | |
tr.innerHTML= | |
"<tr class=cEntry id=entryLine"+index+" valign=top>"+ | |
" <td width=33%>"+ | |
" <input type=hidden name=groupId-"+index+" value="+groupId+">"+ | |
" <input type=hidden name=chkl-"+index+" value=1>"+ | |
" <input type=text class=FormLtCredit id=titleEntry"+index+ | |
" name=newCreditTitle_"+index+" value size=25"+ | |
" onkeypress=showAddCreditsEntry("+(1+index)+")>"+ | |
" </td>"+ | |
" <td width=67%>"+ | |
" <textarea class=FormLtCredit id=creditEntry"+index+".inp"+ | |
" name=developerName_"+index+" cols=60 rows=1 onchange=parseNames("+index+",1)"+ | |
" onkeyup=expandCreditsEntry(creditEntry"+index+".inp)></textarea>"+ | |
" <div id=creditEntry"+index+".dsp></div>"+ | |
" </td>"+ | |
"</tr>"; | |
tr.querySelector("input.FormLtCredit").value=role.name; | |
tr.querySelector("div").innerHTML=(function(){ | |
var out=""; | |
role.devs.forEach(function(dev,devIndexAtRole){ | |
out+=createDev(index,dev,devIndexAtRole,devIndex); | |
devIndex+1; | |
}); | |
return out; | |
}()); | |
return tr; | |
}; | |
var createDev=function(roleIndex,dev,devIndexAtRole,devIndexTotal){ | |
var content=(function(){ | |
var print; | |
if(dev.type==="person"){ | |
if(dev.id===0||dev.id==="0"){ | |
print= dev.name+ | |
"<input type=hidden name='newPerson-"+roleIndex+"~"+devIndexAtRole+"' value=\""+dev.name+"\">"; | |
}else{ | |
print="<input type=hidden name=developerId-"+roleIndex+"~"+devIndexAtRole+" value="+dev.id+">"+ | |
"<a href=/developer/sheet/view/developerId,"+dev.id+" target=_blank>"+dev.name+"</a>"; | |
} | |
if(typeof dev.alt!=="undefined"&&dev.alt!==""){ | |
print+=" ("+dev.alt+")<input type=hidden name=rn-"+roleIndex+"-"+dev.id+" value='"+dev.alt.replace(/^\(|\)$/gi,"")+"'/>"; | |
} | |
return print; | |
}else if(dev.type==="text"){ | |
return dev.name+ | |
"<input type=hidden name=newEntity-"+roleIndex+"~"+devIndexAtRole+" value=\""+dev.name+"\">"; | |
}else{ | |
throw{ | |
name:"Error", | |
message:"Unknown entity type "+dev.type | |
}; | |
} | |
}())+ | |
"--"+ | |
"<a href=javascript:removeName("+devIndexTotal+")>remove</a>"+ | |
"<br>"; | |
return content; | |
}; | |
var fillRoles=function(){ | |
var groupRows=document.querySelectorAll("#addt .cEntry:not([id])"), | |
start,end, | |
i=0,j=1,k=0; | |
if(credits.value.length===groupRows.length){ | |
start=groupRows; | |
end=document.querySelectorAll("#addt .cEntry:not([id])~tr:not([class])"); | |
(function(){ | |
var range,rolesLength,groupId; | |
for(;i<credits.value.length;i++){ | |
range=document.createRange(); | |
rolesLength=credits.value[i].roles.length; | |
groupId=start[i].nextElementSibling.querySelector("input[name^='groupId']").value; | |
range.setStartAfter(start[i]); | |
range.setEndBefore(end[i]); | |
range.deleteContents(); | |
credits.value[i].roles.forEach(function(role){ | |
range.collapse(false); | |
range.insertNode(createRoleLine(groupId,j,role,k)); | |
j+=1; | |
}); | |
} | |
})(); | |
}else{ | |
throw{ | |
name:"Error", | |
message:"Groups quantity mismatch. Data: "+credits.value.length+"; page: "+groupRows.length | |
}; | |
} | |
}; | |
var grabDevs=function(){ | |
if(document.querySelectorAll("a[href^='javascript:remove']").length){ | |
console.log("Remove links found, aborting."); | |
alert("Finish adding new developers first and press 'Update' button. Then try again."); | |
return; | |
} | |
var entries=document.querySelectorAll("#addt tr:not(:first-of-type):not(:last-of-type):not([class]),"+ | |
"#addt tr.cEntry[valign]:not([id])"), | |
isApproved=document.querySelectorAll(".mb1").length, | |
creditsOut=[], | |
hasClass, | |
addGroup, | |
addRole; | |
hasClass=function(el){ | |
return el.hasAttribute("class"); | |
}; | |
addGroup=function(el){ | |
creditsOut.push({ | |
name:el.querySelector("td").textContent, | |
roles:[] | |
}); | |
}; | |
if(isApproved){ | |
addRole=function(el){ | |
var name=el.querySelector(".FormLtCredit").value, | |
devs=el.querySelectorAll(".mb1"), | |
role={ | |
name:name, | |
devs:[] | |
}; | |
Array.prototype.forEach.call(devs,function(dev){ | |
var out={}; | |
switch(dev.childNodes.length){ | |
case 1: | |
var node=dev.childNodes[0]; | |
out.name=node.textContent; | |
if(node.nodeType===1&&node.nodeName==="A"){ | |
out.id=+node.getAttribute("href").match(/\d+/)[0]; | |
out.type="person"; | |
}else if(node.nodeType===3){ | |
out.type="text"; | |
} | |
break; | |
case 2: | |
out.name=dev.childNodes[0].textContent; | |
out.id=+dev.childNodes[0].getAttribute("href").match(/\d+/)[0]; | |
out.alt=dev.childNodes[1].textContent.trim().replace(/^\(|\)$/g,""); | |
out.type="person"; | |
break; | |
} | |
role.devs.push(out); | |
}); | |
creditsOut[creditsOut.length-1].roles.push(role); | |
}; | |
}else{ | |
addRole=function(el){ | |
var name=el.querySelector(".FormLtCredit").value, | |
nodes=el.children[1].childNodes, | |
role={ | |
name:name, | |
devs:[] | |
}; | |
(function(length){ | |
var i; | |
for(i=0;i<length;i++){ | |
var node=nodes[i], | |
out={}; | |
if(node.nodeName!=="BR"){ | |
if(node.nodeType===1 && node.nodeName==="A"){ | |
out.type="person"; | |
out.name=node.textContent; | |
out.id=+node.getAttribute("href").match(/\d+/)[0]; | |
if(nodes[i+1].nodeType===3 && nodes[i+1].textContent===" ("){ | |
out.alt=nodes[i+2].value; | |
i+=4; | |
}else{ | |
i+=1; | |
} | |
}else if(node.nodeType===3){ | |
out.type="text"; | |
out.name=node.textContent; | |
i+=1; | |
} | |
role.devs.push(out); | |
} | |
} | |
})(nodes.length); | |
creditsOut[creditsOut.length-1].roles.push(role); | |
}; | |
} | |
Array.prototype.forEach.call(entries,function(entry,index){ | |
switch(hasClass(entry)){ | |
case false: | |
addGroup(entry); | |
break; | |
case true: | |
addRole(entry); | |
break; | |
default: | |
console.log("Something went wrong"); | |
break; | |
} | |
}); | |
credits.value=creditsOut; | |
}; | |
var handleCheckboxes=function(){ | |
var prev={ | |
index:-1, | |
checked:false | |
}, | |
parent=document.querySelector("#delt"), | |
cboxes=parent.querySelectorAll("input[type='checkbox']"), | |
handle; | |
handle=function(e){ | |
var el=e.target, | |
index=Array.prototype.indexOf.call(cboxes,el), | |
reverse=(function(){ | |
if((index+1)<prev.index) return true; | |
if(index>(prev.index+1)) return false; | |
}()), | |
i; | |
if(el.nodeName==="INPUT"&&el.type==="checkbox"&&index!==-1){ | |
if(e.shiftKey&&prev.index!==-1&&reverse!==undefined){ | |
for(i=reverse?index:prev.index;i<(reverse?prev.index:index);i++){ | |
cboxes[i].checked=prev.checked; | |
} | |
} | |
} | |
prev={ | |
index:index, | |
checked:el.checked | |
}; | |
}; | |
parent.addEventListener("click",function(e){ | |
handle(e); | |
},false); | |
}; | |
// Step 5 | |
var setClassification=function(){ | |
var selects=document.querySelectorAll("select.FormLt2"), | |
i=0; | |
credits.value.forEach(function(group){ | |
group.roles.forEach(function(role){ | |
selects[i].value=role.clas; | |
i+=1; | |
}); | |
}); | |
}; | |
var grabClassification=function(){ | |
var selects=document.querySelectorAll("select"), | |
c=credits.value, | |
i=0; | |
credits.value=credits.value.map(function(group){ | |
group.roles.forEach(function(role){ | |
role.clas=+selects[i].value; | |
i+=1; | |
}); | |
return group; | |
}); | |
}; | |
// Interface initialization | |
(function(){ | |
var u=document.createElement("input"); | |
u.setAttribute("type","file"); | |
u.setAttribute("id","upload"); | |
u.style.visibility="hidden"; | |
document.body.appendChild(u); | |
})(); | |
(function(){ | |
var addButton=function(text,binding){ | |
var out=document.createElement("button"); | |
out.innerHTML=text; | |
out.addEventListener("click",binding); | |
return out; | |
}; | |
var panel=document.createElement("span"); | |
panel.id="CT"; | |
panel.setAttribute("style","position:fixed;right:0;bottom:0;"); | |
panel.appendChild(document.createTextNode(credits.value?"Credits are loaded":"Credits aren't loaded")); | |
if(credits.value){ | |
panel.appendChild(addButton("Remove credits",removeCredits)); | |
panel.appendChild(addButton("Export JSON",function(){exportJSON(credits.value);})); | |
} | |
panel.appendChild(addButton("Import JSON",importJSON)); | |
switch(step){ | |
case 2: | |
panel.appendChild(addButton("Insert groups",fillGroups)); | |
panel.appendChild(addButton("Add spaces",padGroups)); | |
break; | |
case 3: | |
handleCheckboxes(); | |
if(credits.value)panel.appendChild(addButton("Insert developers",fillRoles)); | |
panel.appendChild(addButton("Grab developers",grabDevs)); | |
break; | |
case 5: | |
if(credits.value)panel.appendChild(addButton("Classify roles",setClassification)); | |
panel.appendChild(addButton("Grab roles",grabClassification)); | |
break; | |
} | |
document.querySelector("body").appendChild(panel); | |
}()); | |
console.log("Credits Tool loaded"); | |
})(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment