Skip to content

Instantly share code, notes, and snippets.

@rajdakin
Last active July 18, 2024 06:37
Show Gist options
  • Save rajdakin/35142f25be1a92660a6eb656a59286f6 to your computer and use it in GitHub Desktop.
Save rajdakin/35142f25be1a92660a6eb656a59286f6 to your computer and use it in GitHub Desktop.
box86.org compatibility list code
<style>
#table_stats {
width: 100%;
height: 1em;
background: #808080;
}
#table_stats > div {
height: 100%;
float: left;
}
#table_fail { background: #ff8080; } #table_most { background: #ffff40; } #table_pass { background: #80ff80; }
#pagination {
height: 34px;
}
#paginationlist {
float: left;
margin: 0;
padding: 0;
}
#paginationlist li {
list-style-type: none;
float: left;
margin: 0;
border: 1px solid #aaaaaa;
border-right: none;
padding: 0;
width: 34px;
height: 34px;
text-align: center;
line-height: 34px;
}
#paginationlist li.selected {
background: #888888;
}
#paginationlist li:hover:not(.selected) {
background: #00ffff80;
}
#paginationlist li:first-child {
border-top-left-radius: 3px;
border-bottom-left-radius: 3px;
}
#paginationlist li.last-child-pag {
border-top-right-radius: 3px;
border-bottom-right-radius: 3px;
border-right: 1px solid #aaaaaa;
}
#paginationlist li a {
user-select: none;
color: #000000;
text-decoration: none;
text-align: center;
}
#statusfilter ul {
margin: 0;
display: inline-flex;
}
#statusfilter li {
list-style-type: none;
float: left;
margin: 0;
border: 1px solid #aaaaaa;
border-right: none;
padding: 0 5px;
text-align: center;
line-height: 34px;
}
#statusfilter li.selected {
background: #888888;
}
#statusfilter li:hover:not(.selected) {
background: #00ffff80;
}
#statusfilter li:first-child {
border-top-left-radius: 3px;
border-bottom-left-radius: 3px;
}
#statusfilter li:last-child {
border-top-right-radius: 3px;
border-bottom-right-radius: 3px;
border-right: 1px solid #aaaaaa;
}
#statusfilter li a {
user-select: none;
color: #000000;
text-decoration: none;
text-align: center;
vertical-align: middle;
}
#boxfilter ul {
margin: 0;
display: inline-flex;
}
#boxfilter li {
list-style-type: none;
float: left;
margin: 0;
border: 1px solid #aaaaaa;
border-right: none;
padding: 0 5px;
text-align: center;
line-height: 34px;
}
#boxfilter li.selected {
background: #888888;
}
#boxfilter li:hover:not(.selected) {
background: #00ffff80;
}
#boxfilter li:first-child {
border-top-left-radius: 3px;
border-bottom-left-radius: 3px;
}
#boxfilter li:last-child {
border-top-right-radius: 3px;
border-bottom-right-radius: 3px;
border-right: 1px solid #aaaaaa;
}
#boxfilter li a {
user-select: none;
color: #000000;
text-decoration: none;
text-align: center;
vertical-align: middle;
}
#table_here {
width: 100%;
text-align: center;
vertical-align: middle;
}
#table_here > .entry-1 { background-color: #ff0000; } #table_here > .entry0 { background-color: #d8d8d8; }
#table_here > .entry1 { background-color: #ff8080; } #table_here > .entry2 { background-color: #ffff40; }
#table_here > .entry3 { background-color: #80ff80; }
#table_here > .entry > td {
overflow-x: hidden;
padding: 5px;
}
.entrytitle { width: 30%; } .entryuser { width: 15%; } .entrybox { width: 7%; } .entrytype { width: 15%; } .entrypic { width: 30%; }
.entrypic > img { max-width: 100%; max-height: 100%; }
</style>
<div id="table_stats"><div id="table_fail"></div><div id="table_most"></div><div id="table_pass"></div></div>
<div>Red: not working; Yellow: partially working; Green: working; Gray: unknown.</div>
<div><input type="text" placeholder="Search for a game..." onchange="search_changed(this.value);" onkeypress="this.onchange();" onpaste="this.onchange();" oninput="this.onchange();"></div>
<div id="statusfilter">Filter on status:&nbsp;&nbsp;<ul><li onclick="statusButtonClick(null, this)"><a>Any</a></li><li onclick="statusButtonClick(1, this)"><a>Not working</a></li><li onclick="statusButtonClick(2, this)"><a>Partially working</a></li><li onclick="statusButtonClick(3, this)"><a>Working</a></li><li onclick="statusButtonClick(0, this)"><a>Unknown</a></li></ul></div>
<div id="boxfilter">Filter on box version:&nbsp;&nbsp;<ul style="margin: 0; display: inline-flex;"><li onclick="boxButtonClick(null, this)"><a>Any</a></li><li onclick="boxButtonClick(['box86', 'Both'], this)"><a>box86</a></li><li onclick="boxButtonClick(['box64', 'Both'], this)"><a>box64</a></li><li onclick="boxButtonClick(['Unknown'], this)"><a>Unknown</a></li></ul></div>
<div id="pagination"><ul id="paginationlist"></ul></div>
<table id="table_here"><tbody><tr><th>Title</th><th>Original poster</th><th>box86/box64</th><th>Status</th><th>Picture (if available)</th></tr></tbody></table>
<div id="please_wait_loading">Please wait, loading...</div>
<script>
function maybe_convert_element(id) {
elem = window.trcompatibilitylist[id];
if (elem.constructor === Object) {
newdiv = document.createElement("tr");
newdiv.className = "entry entry" + elem.ttype;
title = document.createElement("td");
title.className = "entrytitle";
title.innerHTML = "<a href=" + elem.html_url + ">" + elem.title + "</a>";
user = document.createElement("td");
user.className = "entryuser";
user.innerText = elem.user;
boxd = document.createElement("td");
boxd.className = "entrybox";
boxd.innerText = elem.boxtxt;
type = document.createElement("td");
type.className = "entrytype";
type.innerText = elem.typetxt;
pic = document.createElement("td");
pic.className = "entrypic";
if (elem.picsrc === null) { pic.innerText = "Picture unavailable"; }
else { pic.innerHTML = "<img src=\"" + elem.picsrc + "\">"; }
newdiv.appendChild(title);
newdiv.appendChild(user);
newdiv.appendChild(boxd);
newdiv.appendChild(type);
newdiv.appendChild(pic);
window.trcompatibilitylist[id] = newdiv;
}
}
document.addEventListener("DOMContentLoaded", function(){
reqstr = "https://api.github.com/repos/ptitSeb/box86-compatibility-list/issues?accept=application/vnd.github.v3+json&state=open&per_page=100&page=";
failcnt = 0; mostcnt = 0; passcnt = 0; unkncnt = 0;
window.trcompatibilitylist = []; window.trcompatibilitynos = []; window.curtbl = 0; window.itemsppage = 15; window.tablerowdummies = [];
window.title_filter = ""; window.type_filter = null; window.boxtxt_filter = null; window.lastButton = 0;
window.finished_load = false;
window.sel_type = document.getElementById("statusfilter").children[0].children[0]; window.sel_type.className = "selected";
window.sel_box = document.getElementById("boxfilter").children[0].children[0]; window.sel_box.className = "selected";
for (i = 0; i < window.itemsppage; ++i) {
window.tablerowdummies[i] = document.createElement("div");
document.getElementById("table_here").appendChild(window.tablerowdummies[i]);
}
function addfailedstr(msg) {
faileddiv = document.createElement("div");
failedtxt = document.createTextDiv(msg);
faileddiv.style.color = "red";
faileddiv.appendChild(failedtxt);
document.getElementById("table_here").appendChild(faileddiv);
console.error(msg);
}
function addtr(tablerow) {
window.trcompatibilitynos.push(window.trcompatibilitylist.length);
window.trcompatibilitylist.push(tablerow);
if (window.curtbl === 0) {
window.curtbl = 1;
window.itemcount = 0;
}
if (window.itemcount % window.itemsppage === 0) {
paglst = document.getElementById("paginationlist");
if (paglst.childElementCount >= 0) {
// TODO: change this to not add infinitely many pages and update the buttons later
newPage = document.createElement("li");
if (paglst.childElementCount === 0) {
window.selectedPage = 0;
} else {
remove_class(paglst.children[window.lastButton], "last-child-pag");
}
window.lastButton = paglst.childElementCount;
paglst.appendChild(newPage);
newPage.outerHTML = "<li class=\"" + ((paglst.childElementCount === 1) ? "selected last-child-pag" : "last-child-pag") + "\" onclick=\"paginationButtonClick(" + (paglst.childElementCount-1) + ")\"><a>" + paglst.childElementCount + "</a></li>";
}
}
if (window.itemcount < window.itemsppage) {
maybe_convert_element(window.itemcount);
document.getElementById("table_here").replaceChild(window.trcompatibilitylist[window.itemcount], document.getElementById("table_here").children[window.itemcount+1]);
}
++window.itemcount;
}
function nextPage(page) {
req = new XMLHttpRequest();
req.open("GET", reqstr + page);
req.onerror = function(){
addfailedstr("Failed to fetch the GitHub issues");
};
req.onload = function(){
if (req.responseType !== "") {
addfailedstr("Unknown response type " + req.responseType);
} else {
var resp = JSON.parse(req.response);
for (const issueID in resp) {
const issue = resp[issueID];
ttype = 0; // -1 = conflict, 0 = unknown, 1 = Not-working, 2 = Partially-working, 3 = Working
boxs = 0; // 1 = box86, 2 = box64 (bitfield)
for (const labelID in issue["labels"]) {
otype = ttype;
switch (issue["labels"][labelID].id) {
case 2018095883: // Not-working
ttype = 1;
break;
case 2018095900: // Partly-working
ttype = 2;
break;
case 2024688036: // Working
ttype = 3;
break;
case 3486241431: // Box86
boxs |= 1;
continue;
case 3486242986: // Box64
boxs |= 2;
continue;
default:
continue;
}
if (otype !== 0) if (otype !== ttype) { // Apparently && gets transformed into `&038;&038;'...
console.error("Conflicting types for " + issue["title"] + ": " + otype + " and " + ttype);
ttype = -1;
break;
}
}
if (ttype === 1) ++failcnt;
else if (ttype === 2) ++mostcnt;
else if (ttype === 3) ++passcnt;
else ++unkncnt;
newrow = { ttype: ttype, html_url: issue.html_url, title: issue.title, user: issue.user.login,
boxtxt: (boxs === 0) ? "Unknown" :
((boxs === 1) ? "box86" :
((boxs === 2) ? "box64" : "Both")),
typetxt: (ttype === -1) ? "Unknown*" :
((ttype === 0) ? "Unknown" :
((ttype === 1) ? "Not working" :
((ttype === 2) ? "Partially working" : "Working")))
};
picsrcregexp = /(https?:\/\/[^:<>"']+\/[^:<>"'\/]+\.(png(!thumbnail)?|jpe?g))/gi;
picsrc = picsrcregexp.exec(issue.body);
if (picsrc === null) {
fallbackregexp = /]\((https:\/\/github.com\/(ptitSeb\/box86-compatibility-list|user-attachments)\/assets\/[^)]+)/gi;
picsrc = fallbackregexp.exec(issue.body);
}
if (picsrc === null) { newrow.picsrc = null; }
else { newrow.picsrc = picsrc[1]; }
addtr(newrow);
}
totcnt = failcnt + mostcnt + passcnt + unkncnt;
document.getElementById("table_fail").style.width = (100*failcnt / totcnt) + "%";
document.getElementById("table_most").style.width = (100*mostcnt / totcnt) + "%";
document.getElementById("table_pass").style.width = (100*passcnt / totcnt) + "%";
if (resp.length === 100) {
nextPage(page + 1);
} else {
please_wait = document.getElementById("please_wait_loading");
please_wait.parentElement.removeChild(please_wait);
window.finished_load = true;
refilter();
}
}
};
req.send();
}
nextPage(1);
});
function add_class(elem, cname) {
elem.className = (elem.className.length === 0) ? cname : (elem.className + " " + cname);
}
function remove_class(elem, cname) {
elem.className = elem.className.startsWith(cname + " ") ? elem.className.substr(cname.length + 1) :
((elem.className.startsWith(cname) && (elem.className.length === cname.length)) ? "" :
elem.className.replace(" " + cname, ""));
}
function paginationButtonClick(pageno) {
tab = document.getElementById("table_here");
offset = pageno*window.itemsppage;
for (i = 0; i < window.itemsppage; ++i) {
id = offset + i;
if (id < window.trcompatibilitynos.length) {
id = window.trcompatibilitynos[id];
maybe_convert_element(id);
tab.replaceChild(window.trcompatibilitylist[id], tab.children[i+1]);
} else {
tab.replaceChild(window.tablerowdummies[i], tab.children[i+1]);
}
}
paglst = document.getElementById("paginationlist");
remove_class(paglst.children[window.selectedPage], "selected");
window.selectedPage = pageno;
add_class(paglst.children[window.selectedPage], "selected");
}
function refilter() {
if (!window.finished_load) return; // Wait until the requests are done; filtering will be done at the end
trcompatibilitynos = [];
for (i = 0; i < window.trcompatibilitylist.length; ++i) {
elem = window.trcompatibilitylist[i];
if (elem.constructor === Object) {
title = elem.title;
ttype = elem.ttype;
boxtxt = elem.boxtxt;
} else {
title = elem.children[0].children[0].firstChild.textContent;
ttype = parseInt(elem.classList[1].substr("entry".length));
boxtxt = elem.children[2].textContent;
}
if (((window.title_filter === "") || (title.toUpperCase().replace(/\s+/g, "").indexOf(window.title_filter) > -1))
&& ((window.type_filter === null) || (ttype === window.type_filter))
&& ((window.boxtxt_filter === null) || (window.boxtxt_filter.indexOf(boxtxt) >= 0))) {
trcompatibilitynos.push(i);
}
}
// We may end up replacing a visible child by another one, which is *bad*
tab = document.getElementById("table_here");
for (i = 0; i < window.itemsppage; ++i) {
tab.replaceChild(window.tablerowdummies[i], tab.children[i+1]);
}
paglst = document.getElementById("paginationlist");
remove_class(paglst.children[window.lastButton], "last-child-pag");
window.lastButton = (trcompatibilitynos.length === 0) ? 0 : (((trcompatibilitynos.length - 1) / window.itemsppage) >> 0);
add_class(paglst.children[window.lastButton], "last-child-pag");
for (i = 0; i <= window.lastButton; ++i) {
paglst.children[i].style.display = '';
}
for (i = window.lastButton + 1; i < paglst.childElementCount; ++i) {
paglst.children[i].style.display = 'none';
}
window.trcompatibilitynos = trcompatibilitynos;
paginationButtonClick(0);
}
function search_changed(new_search) {
window.title_filter = new_search.toUpperCase().replace(/\s+/g, "");
refilter();
}
function statusButtonClick(buttonid, button) {
window.type_filter = buttonid;
window.sel_type.className = "";
window.sel_type = button;
window.sel_type.className = "selected";
refilter();
}
function boxButtonClick(buttonid, button) {
window.boxtxt_filter = buttonid;
window.sel_box.className = "";
window.sel_box = button;
window.sel_box.className = "selected";
refilter();
}
</script>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment