(function () {
"use strict";
window.CO_ServerList = {
pingClass: function (ping) {
if (ping <= 50) return "co-ping-good";
if (ping <= 100) return "co-ping-mid";
return "co-ping-bad";
},
isLocalHost: function (host) {
if (!host) return false;
return /^(127\.0\.0\.1|localhost|::1)$/i.test(String(host).trim());
},
displayName: function (server) {
if (!server) return "";
var host = server.host || server.address || "";
var port = server.port > 0 ? server.port : 7777;
var name = String(server.name || "").trim();
var isLocal = server.region === "Local" || CO_ServerList.isLocalHost(host);
var isDirect = server.id === "direct" || name === "Direct Connect";
if (!name || isLocal || isDirect) {
return (host || "127.0.0.1") + ":" + port;
}
return name;
},
render: function (root, state) {
var wrap = root.querySelector(".co-server-list-wrap");
var list = root.querySelector(".co-server-list");
if (!wrap || !list) return;
wrap.className = "co-server-list-wrap" + (state.focusZone === "server-list" ? " focused" : "");
var isRecent = state.activeTab === "recent";
var isLocal = state.activeTab === "local";
if (!state.servers.length) {
var emptyText = "No servers found";
if (isRecent) emptyText = "No recent servers";
else if (isLocal) {
emptyText = state.isScanningLocal ?
"Scanning local network..." :
"No local servers found. Check the host PC is running server.py and firewall allows UDP 7778 / TCP 7777.";
}
list.innerHTML = '
' + emptyText + "
";
CO_ServerList.updateScrollIndicator(wrap, list);
return;
}
list.innerHTML = state.servers.map(function (server, index) {
var selected = index === state.selectedServerIndex ? " selected" : "";
var label = CO_ServerList.displayName(server);
if (isRecent) {
return (
'' +
'
' +
'' + escapeHtml(label) + "" +
"
" +
"
"
);
}
if (isLocal) {
var pingCls = CO_ServerList.pingClass(server.ping || 0);
return (
'' +
'
' +
'' + escapeHtml(label) + "" +
"
" +
'
' +
"" + (server.players || 0) + "/" + (server.maxPlayers || 16) + "" +
'' + (server.ping || 0) + " ms" +
"
" +
"
"
);
}
var fav = server.favorite ? " on" : "";
var pingCls = CO_ServerList.pingClass(server.ping);
return (
'' +
'
' +
'' + (server.favorite ? "\u2605" : "\u2606") + "" +
'' + escapeHtml(label) + "" +
"
" +
'
' +
"" + server.players + "/" + server.maxPlayers + "" +
'' + server.ping + " ms" +
"
" +
"
"
);
}).join("");
CO_ServerList.updateScrollIndicator(wrap, list);
},
updateScrollIndicator: function (wrap, list) {
var indicator = wrap && wrap.querySelector(".co-scroll-indicator");
if (!indicator || !list) return;
var hasOverflow = list.scrollHeight > list.clientHeight + 2;
indicator.classList.toggle("hidden", !hasOverflow);
},
bind: function (root, onSelect) {
var list = root.querySelector(".co-server-list");
if (!list) return;
list.addEventListener("click", function (e) {
var row = e.target.closest(".co-server-row");
if (!row) return;
onSelect(parseInt(row.getAttribute("data-index"), 10));
});
list.addEventListener("dblclick", function (e) {
var row = e.target.closest(".co-server-row");
if (!row) return;
onSelect(parseInt(row.getAttribute("data-index"), 10));
if (window.CO_App && window.CO_App.joinSelected) {
window.CO_App.joinSelected();
}
});
},
scrollToSelected: function (root, index) {
var list = root.querySelector(".co-server-list");
var row = list && list.querySelector('.co-server-row[data-index="' + index + '"]');
if (row) {
row.scrollIntoView({ block: "nearest" });
}
var wrap = root.querySelector(".co-server-list-wrap");
if (wrap && list) {
CO_ServerList.updateScrollIndicator(wrap, list);
}
}
};
function escapeHtml(value) {
return String(value)
.replace(/&/g, "&")
.replace(//g, ">");
}
function escapeAttr(value) {
return String(value).replace(/"/g, """);
}
})();