mirror of
https://github.com/CHOMPStation2/CHOMPStation2.git
synced 2025-12-10 10:12:45 +00:00
Co-authored-by: Selis <12716288+ItsSelis@users.noreply.github.com> Co-authored-by: Kashargul <144968721+Kashargul@users.noreply.github.com>
1093 lines
30 KiB
JavaScript
1093 lines
30 KiB
JavaScript
// Polyfills and compatibility ------------------------------------------------
|
|
const decoder = decodeURIComponent;
|
|
if (!Array.prototype.includes) {
|
|
Array.prototype.includes = function (thing) {
|
|
for (let i = 0; i < this.length; i++) {
|
|
if (this[i] === thing) return true;
|
|
}
|
|
return false;
|
|
};
|
|
}
|
|
if (!String.prototype.trim) {
|
|
String.prototype.trim = function () {
|
|
return this.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, '');
|
|
};
|
|
}
|
|
|
|
// Status panel implementation ------------------------------------------------
|
|
let status_tab_parts = ['Loading...'];
|
|
let current_tab = null;
|
|
let mc_tab_parts = [['Loading...', '']];
|
|
let href_token = null;
|
|
let spells = [];
|
|
let spell_tabs = [];
|
|
let verb_tabs = [];
|
|
let verbs = [['', '']]; // list with a list inside
|
|
let examine = [];
|
|
let tickets = [];
|
|
const misc = new Map();
|
|
let sdql2 = [];
|
|
const permanent_tabs = []; // tabs that won't be cleared by wipes
|
|
let turfcontents = [];
|
|
let turfname = '';
|
|
const imageRetryDelay = 500;
|
|
const imageRetryLimit = 50;
|
|
const menu = document.getElementById('menu');
|
|
const statcontentdiv = document.getElementById('statcontent');
|
|
const storedimages = [];
|
|
let split_admin_tabs = false;
|
|
|
|
// Any BYOND commands that could result in the client's focus changing go through this
|
|
// to ensure that when we relinquish our focus, we don't do it after the result of
|
|
// a command has already taken focus for itself.
|
|
function run_after_focus(callback) {
|
|
setTimeout(callback, 0);
|
|
}
|
|
|
|
function createStatusTab(name) {
|
|
if (name.indexOf('.') !== -1) {
|
|
const splitName = name.split('.');
|
|
if (split_admin_tabs && splitName[0] === 'Admin') name = splitName[1];
|
|
else name = splitName[0];
|
|
}
|
|
if (document.getElementById(name) || name.trim() === '') {
|
|
return;
|
|
}
|
|
if (!verb_tabs.includes(name) && !permanent_tabs.includes(name)) {
|
|
return;
|
|
}
|
|
const button = document.createElement('DIV');
|
|
button.onclick = function () {
|
|
tab_change(name);
|
|
this.blur();
|
|
statcontentdiv.focus();
|
|
};
|
|
button.id = name;
|
|
button.textContent = name;
|
|
button.className = 'button';
|
|
//ORDERING ALPHABETICALLY
|
|
button.style.order = name.charCodeAt(0);
|
|
if (name === 'Status' || name === 'MC') {
|
|
button.style.order = name === 'Status' ? 1 : 2;
|
|
}
|
|
if (name === 'Tickets') {
|
|
button.style.order = 3;
|
|
}
|
|
//END ORDERING
|
|
menu.appendChild(button);
|
|
SendTabToByond(name);
|
|
}
|
|
|
|
function removeStatusTab(name) {
|
|
if (!document.getElementById(name) || permanent_tabs.includes(name)) {
|
|
return;
|
|
}
|
|
for (let i = verb_tabs.length - 1; i >= 0; --i) {
|
|
if (verb_tabs[i] === name) {
|
|
verb_tabs.splice(i, 1);
|
|
}
|
|
}
|
|
if (current_tab === name) {
|
|
tab_change('Status');
|
|
}
|
|
menu.removeChild(document.getElementById(name));
|
|
TakeTabFromByond(name);
|
|
}
|
|
|
|
function sortVerbs() {
|
|
verbs.sort((a, b) => {
|
|
const selector = a[0] === b[0] ? 1 : 0;
|
|
if (a[selector].toUpperCase() < b[selector].toUpperCase()) {
|
|
return 1;
|
|
} else if (a[selector].toUpperCase() > b[selector].toUpperCase()) {
|
|
return -1;
|
|
}
|
|
return 0;
|
|
});
|
|
}
|
|
|
|
function addPermanentTab(name) {
|
|
if (!permanent_tabs.includes(name)) {
|
|
permanent_tabs.push(name);
|
|
}
|
|
createStatusTab(name);
|
|
}
|
|
|
|
function removePermanentTab(name) {
|
|
for (let i = permanent_tabs.length - 1; i >= 0; --i) {
|
|
if (permanent_tabs[i] === name) {
|
|
permanent_tabs.splice(i, 1);
|
|
}
|
|
}
|
|
removeStatusTab(name);
|
|
}
|
|
|
|
function checkStatusTab() {
|
|
for (let i = 0; i < menu.children.length; i++) {
|
|
if (
|
|
!verb_tabs.includes(menu.children[i].id) &&
|
|
!permanent_tabs.includes(menu.children[i].id)
|
|
) {
|
|
menu.removeChild(menu.children[i]);
|
|
}
|
|
}
|
|
}
|
|
|
|
function remove_verb(v) {
|
|
const verb_to_remove = v; // to_remove = [verb:category, verb:name]
|
|
for (let i = verbs.length - 1; i >= 0; i--) {
|
|
const part_to_remove = verbs[i];
|
|
if (part_to_remove[1] === verb_to_remove[1]) {
|
|
verbs.splice(i, 1);
|
|
}
|
|
}
|
|
}
|
|
|
|
function check_verbs() {
|
|
for (let v = verb_tabs.length - 1; v >= 0; v--) {
|
|
verbs_cat_check(verb_tabs[v]);
|
|
}
|
|
}
|
|
|
|
function verbs_cat_check(cat) {
|
|
let tabCat = cat;
|
|
if (cat.indexOf('.') !== -1) {
|
|
const splitName = cat.split('.');
|
|
if (split_admin_tabs && splitName[0] === 'Admin') tabCat = splitName[1];
|
|
else tabCat = splitName[0];
|
|
}
|
|
let verbs_in_cat = 0;
|
|
let verbcat = '';
|
|
if (!verb_tabs.includes(tabCat)) {
|
|
removeStatusTab(tabCat);
|
|
return;
|
|
}
|
|
for (let v = 0; v < verbs.length; v++) {
|
|
const part = verbs[v];
|
|
verbcat = part[0];
|
|
if (verbcat.indexOf('.') !== -1) {
|
|
const splitName = verbcat.split('.');
|
|
if (split_admin_tabs && splitName[0] === 'Admin') verbcat = splitName[1];
|
|
else verbcat = splitName[0];
|
|
}
|
|
if (verbcat !== tabCat || verbcat.trim() === '') {
|
|
} else {
|
|
verbs_in_cat = 1;
|
|
break; // we only need one
|
|
}
|
|
}
|
|
if (verbs_in_cat !== 1) {
|
|
removeStatusTab(tabCat);
|
|
if (current_tab === tabCat) tab_change('Status');
|
|
}
|
|
}
|
|
|
|
function findVerbindex(name, verblist) {
|
|
for (let i = 0; i < verblist.length; i++) {
|
|
const part = verblist[i];
|
|
if (part[1] === name) return i;
|
|
}
|
|
}
|
|
function wipe_verbs() {
|
|
verbs = [['', '']];
|
|
verb_tabs = [];
|
|
checkStatusTab(); // remove all empty verb tabs
|
|
}
|
|
|
|
function update_verbs() {
|
|
wipe_verbs();
|
|
Byond.sendMessage('Update-Verbs');
|
|
}
|
|
|
|
function SendTabsToByond() {
|
|
let tabstosend = [];
|
|
tabstosend = tabstosend.concat(permanent_tabs, verb_tabs);
|
|
for (let i = 0; i < tabstosend.length; i++) {
|
|
SendTabToByond(tabstosend[i]);
|
|
}
|
|
}
|
|
|
|
function SendTabToByond(tab) {
|
|
Byond.sendMessage('Send-Tabs', { tab: tab });
|
|
}
|
|
|
|
//Byond can't have this tab anymore since we're removing it
|
|
function TakeTabFromByond(tab) {
|
|
Byond.sendMessage('Remove-Tabs', { tab: tab });
|
|
}
|
|
|
|
function spell_cat_check(cat) {
|
|
let spells_in_cat = 0;
|
|
let spellcat = '';
|
|
for (let s = 0; s < spells.length; s++) {
|
|
const spell = spells[s];
|
|
spellcat = spell[0];
|
|
if (spellcat === cat) {
|
|
spells_in_cat++;
|
|
}
|
|
}
|
|
if (spells_in_cat < 1) {
|
|
removeStatusTab(cat);
|
|
}
|
|
}
|
|
|
|
function tab_change(tab) {
|
|
if (tab === current_tab) return;
|
|
if (document.getElementById(current_tab))
|
|
document.getElementById(current_tab).className = 'button'; // disable active on last button
|
|
current_tab = tab;
|
|
set_byond_tab(tab);
|
|
if (document.getElementById(tab))
|
|
document.getElementById(tab).className = 'button active'; // make current button active
|
|
const spell_tabs_thingy = spell_tabs.includes(tab);
|
|
const verb_tabs_thingy = verb_tabs.includes(tab);
|
|
if (tab === 'Status') {
|
|
draw_status();
|
|
} else if (tab === 'MC') {
|
|
draw_mc();
|
|
} else if (spell_tabs_thingy) {
|
|
draw_spells(tab);
|
|
} else if (verb_tabs_thingy) {
|
|
draw_verbs(tab);
|
|
} else if (tab === 'Debug Stat Panel') {
|
|
draw_debug();
|
|
} else if (tab === 'Tickets') {
|
|
draw_tickets();
|
|
} else if (misc.has(tab)) {
|
|
draw_misc(tab);
|
|
} else if (tab === 'Examine') {
|
|
draw_examine();
|
|
} else if (tab === 'SDQL2') {
|
|
draw_sdql2();
|
|
} else if (tab === turfname) {
|
|
draw_listedturf();
|
|
} else {
|
|
statcontentdiv.textContext = 'Loading...';
|
|
}
|
|
Byond.winset(Byond.windowId, {
|
|
'is-visible': true,
|
|
});
|
|
}
|
|
|
|
function set_byond_tab(tab) {
|
|
Byond.sendMessage('Set-Tab', { tab: tab });
|
|
}
|
|
|
|
function draw_examine() {
|
|
statcontentdiv.textContent = '';
|
|
const div_content = document.createElement('div');
|
|
for (let i = 0; i < examine.length; i++) {
|
|
const parameter = document.createElement('p');
|
|
const textList = examine[i].split('||');
|
|
if (textList.length > 1) {
|
|
for (let j = 0; j < textList.length; j++) {
|
|
const spoilerText = document.createElement('span');
|
|
if (j % 2) {
|
|
spoilerText.className = 'spoiler';
|
|
}
|
|
spoilerText.innerHTML = textList[j];
|
|
parameter.appendChild(spoilerText);
|
|
}
|
|
} else {
|
|
parameter.innerHTML = examine[i];
|
|
}
|
|
div_content.appendChild(parameter);
|
|
}
|
|
const images = div_content.querySelectorAll('img');
|
|
for (let i = 0; i < images.length; i++) {
|
|
images[i].addEventListener('error', iconError);
|
|
}
|
|
document.getElementById('statcontent').appendChild(div_content);
|
|
}
|
|
|
|
function draw_debug() {
|
|
statcontentdiv.textContent = '';
|
|
const wipeverbstabs = document.createElement('div');
|
|
const link = document.createElement('a');
|
|
link.onclick = () => {
|
|
wipe_verbs();
|
|
};
|
|
link.textContent = 'Wipe All Verbs';
|
|
wipeverbstabs.appendChild(link);
|
|
document.getElementById('statcontent').appendChild(wipeverbstabs);
|
|
const wipeUpdateVerbsTabs = document.createElement('div');
|
|
const updateLink = document.createElement('a');
|
|
updateLink.onclick = () => {
|
|
update_verbs();
|
|
};
|
|
updateLink.textContent = 'Wipe and Update All Verbs';
|
|
wipeUpdateVerbsTabs.appendChild(updateLink);
|
|
document.getElementById('statcontent').appendChild(wipeUpdateVerbsTabs);
|
|
const text = document.createElement('div');
|
|
text.textContent = 'Verb Tabs:';
|
|
document.getElementById('statcontent').appendChild(text);
|
|
const table1 = document.createElement('table');
|
|
for (let i = 0; i < verb_tabs.length; i++) {
|
|
let part = verb_tabs[i];
|
|
// Hide subgroups except admin subgroups if they are split
|
|
if (verb_tabs[i].lastIndexOf('.') !== -1) {
|
|
const splitName = verb_tabs[i].split('.');
|
|
if (split_admin_tabs && splitName[0] === 'Admin') part = splitName[1];
|
|
else continue;
|
|
}
|
|
const tr = document.createElement('tr');
|
|
const td1 = document.createElement('td');
|
|
td1.textContent = part;
|
|
const a = document.createElement('a');
|
|
a.onclick = ((part) => () => {
|
|
removeStatusTab(part);
|
|
})(part);
|
|
a.textContent = ` Delete Tab ${part}`;
|
|
td1.appendChild(a);
|
|
tr.appendChild(td1);
|
|
table1.appendChild(tr);
|
|
}
|
|
document.getElementById('statcontent').appendChild(table1);
|
|
const header2 = document.createElement('div');
|
|
header2.textContent = 'Verbs:';
|
|
document.getElementById('statcontent').appendChild(header2);
|
|
const table2 = document.createElement('table');
|
|
for (let v = 0; v < verbs.length; v++) {
|
|
const part2 = verbs[v];
|
|
const trr = document.createElement('tr');
|
|
const tdd1 = document.createElement('td');
|
|
tdd1.textContent = part2[0];
|
|
const tdd2 = document.createElement('td');
|
|
tdd2.textContent = part2[1];
|
|
trr.appendChild(tdd1);
|
|
trr.appendChild(tdd2);
|
|
table2.appendChild(trr);
|
|
}
|
|
document.getElementById('statcontent').appendChild(table2);
|
|
const text3 = document.createElement('div');
|
|
text3.textContent = 'Permanent Tabs:';
|
|
document.getElementById('statcontent').appendChild(text3);
|
|
const table3 = document.createElement('table');
|
|
for (let i = 0; i < permanent_tabs.length; i++) {
|
|
const part3 = permanent_tabs[i];
|
|
const trrr = document.createElement('tr');
|
|
const tddd1 = document.createElement('td');
|
|
tddd1.textContent = part3;
|
|
trrr.appendChild(tddd1);
|
|
table3.appendChild(trrr);
|
|
}
|
|
document.getElementById('statcontent').appendChild(table3);
|
|
}
|
|
function draw_status() {
|
|
if (!document.getElementById('Status')) {
|
|
createStatusTab('Status');
|
|
current_tab = 'Status';
|
|
}
|
|
statcontentdiv.textContent = '';
|
|
for (let i = 0; i < status_tab_parts.length; i++) {
|
|
if (status_tab_parts[i].trim() === '') {
|
|
document
|
|
.getElementById('statcontent')
|
|
.appendChild(document.createElement('br'));
|
|
} else {
|
|
const div = document.createElement('div');
|
|
div.textContent = status_tab_parts[i];
|
|
div.className = 'status-info';
|
|
document.getElementById('statcontent').appendChild(div);
|
|
}
|
|
}
|
|
if (verb_tabs.length === 0 || !verbs) {
|
|
Byond.command('Fix-Stat-Panel');
|
|
}
|
|
}
|
|
|
|
function draw_mc() {
|
|
statcontentdiv.textContent = '';
|
|
const table = document.createElement('table');
|
|
for (let i = 0; i < mc_tab_parts.length; i++) {
|
|
const part = mc_tab_parts[i];
|
|
const tr = document.createElement('tr');
|
|
const td1 = document.createElement('td');
|
|
td1.textContent = part[0];
|
|
const td2 = document.createElement('td');
|
|
if (part[2]) {
|
|
const a = document.createElement('a');
|
|
a.href = `byond://?_src_=vars;admin_token=${href_token};Vars=${part[2]}`;
|
|
a.textContent = part[1];
|
|
td2.appendChild(a);
|
|
} else {
|
|
td2.textContent = part[1];
|
|
}
|
|
tr.appendChild(td1);
|
|
tr.appendChild(td2);
|
|
table.appendChild(tr);
|
|
}
|
|
document.getElementById('statcontent').appendChild(table);
|
|
}
|
|
|
|
function remove_tickets() {
|
|
if (tickets) {
|
|
tickets = [];
|
|
removePermanentTab('Tickets');
|
|
if (current_tab === 'Tickets') tab_change('Status');
|
|
}
|
|
checkStatusTab();
|
|
}
|
|
|
|
function remove_sdql2() {
|
|
if (sdql2) {
|
|
sdql2 = [];
|
|
removePermanentTab('SDQL2');
|
|
if (current_tab === 'SDQL2') tab_change('Status');
|
|
}
|
|
checkStatusTab();
|
|
}
|
|
|
|
function iconError(e) {
|
|
setTimeout(() => {
|
|
if (current_tab !== turfname && current_tab !== 'Examine') {
|
|
return;
|
|
}
|
|
const node = e.target;
|
|
const current_attempts = Number(node.getAttribute('data-attempts')) || 0;
|
|
if (current_attempts > imageRetryLimit) {
|
|
return;
|
|
}
|
|
const src = node.src;
|
|
node.src = null;
|
|
node.src = `${src}#${current_attempts}`;
|
|
node.setAttribute('data-attempts', current_attempts + 1);
|
|
}, imageRetryDelay);
|
|
}
|
|
|
|
function draw_listedturf() {
|
|
statcontentdiv.textContent = '';
|
|
const table = document.createElement('table');
|
|
for (let i = 0; i < turfcontents.length; i++) {
|
|
const part = turfcontents[i];
|
|
if (storedimages[part[1]] == null && part[2]) {
|
|
const img = document.createElement('img');
|
|
img.src = part[2];
|
|
img.id = part[1];
|
|
storedimages[part[1]] = part[2];
|
|
img.onerror = iconError;
|
|
table.appendChild(img);
|
|
} else {
|
|
const img = document.createElement('img');
|
|
img.onerror = iconError;
|
|
img.src = storedimages[part[1]];
|
|
img.id = part[1];
|
|
table.appendChild(img);
|
|
}
|
|
const b = document.createElement('div');
|
|
b.className = 'link';
|
|
b.onmousedown = ((part) => {
|
|
// The outer function is used to close over a fresh "part" variable,
|
|
// rather than every onmousedown getting the "part" of the last entry.
|
|
return (e) => {
|
|
e.preventDefault();
|
|
const params = { src: part[1] };
|
|
switch (e.button) {
|
|
case 1:
|
|
params.statpanel_item_click = 'middle';
|
|
break;
|
|
case 2:
|
|
params.statpanel_item_click = 'right';
|
|
break;
|
|
default:
|
|
params.statpanel_item_click = 'left';
|
|
}
|
|
if (e.shiftKey) {
|
|
params.statpanel_item_shiftclick = 1;
|
|
}
|
|
if (e.ctrlKey) {
|
|
params.statpanel_item_ctrlclick = 1;
|
|
}
|
|
if (e.altKey) {
|
|
params.statpanel_item_altclick = 1;
|
|
}
|
|
Byond.topic(params);
|
|
};
|
|
})(part);
|
|
b.textContent = part[0];
|
|
table.appendChild(b);
|
|
table.appendChild(document.createElement('br'));
|
|
}
|
|
statcontentdiv.appendChild(table);
|
|
}
|
|
|
|
function remove_listedturf() {
|
|
removePermanentTab(turfname);
|
|
checkStatusTab();
|
|
if (current_tab === turfname) {
|
|
tab_change('Status');
|
|
}
|
|
}
|
|
|
|
function remove_mc() {
|
|
removePermanentTab('MC');
|
|
if (current_tab === 'MC') {
|
|
tab_change('Status');
|
|
}
|
|
}
|
|
|
|
function draw_sdql2() {
|
|
statcontentdiv.textContent = '';
|
|
const table = document.createElement('table');
|
|
for (let i = 0; i < sdql2.length; i++) {
|
|
const part = sdql2[i];
|
|
const tr = document.createElement('tr');
|
|
const td1 = document.createElement('td');
|
|
td1.textContent = part[0];
|
|
const td2 = document.createElement('td');
|
|
if (part[2]) {
|
|
const a = document.createElement('a');
|
|
a.href = `byond://?src=${part[2]};statpanel_item_click=left`;
|
|
a.textContent = part[1];
|
|
td2.appendChild(a);
|
|
} else {
|
|
td2.textContent = part[1];
|
|
}
|
|
tr.appendChild(td1);
|
|
tr.appendChild(td2);
|
|
table.appendChild(tr);
|
|
}
|
|
document.getElementById('statcontent').appendChild(table);
|
|
}
|
|
|
|
function draw_tickets() {
|
|
statcontentdiv.textContent = '';
|
|
const table = document.createElement('table');
|
|
if (!tickets) {
|
|
return;
|
|
}
|
|
for (let i = 0; i < tickets.length; i++) {
|
|
const part = tickets[i];
|
|
const tr = document.createElement('tr');
|
|
const td1 = document.createElement('td');
|
|
td1.textContent = part[0];
|
|
const td2 = document.createElement('td');
|
|
if (part[2]) {
|
|
const a = document.createElement('a');
|
|
a.href = `byond://?_src_=holder;admin_token=${href_token};ahelp=${part[2]};ahelp_action=ticket;statpanel_item_click=left;action=ticket`;
|
|
a.textContent = part[1];
|
|
td2.appendChild(a);
|
|
} else if (part[3]) {
|
|
const a = document.createElement('a');
|
|
a.href = `byond://?src=${part[3]};statpanel_item_click=left`;
|
|
a.textContent = part[1];
|
|
td2.appendChild(a);
|
|
} else {
|
|
td2.textContent = part[1];
|
|
}
|
|
tr.appendChild(td1);
|
|
tr.appendChild(td2);
|
|
table.appendChild(tr);
|
|
}
|
|
document.getElementById('statcontent').appendChild(table);
|
|
}
|
|
|
|
function draw_misc(tab) {
|
|
statcontentdiv.textContent = '';
|
|
const table = document.createElement('table');
|
|
table.className = 'elemcontainer';
|
|
const data = misc.get(tab);
|
|
if (!data) {
|
|
return;
|
|
}
|
|
for (let i = 0; i < data.length; i++) {
|
|
const tr = document.createElement('tr');
|
|
const part = data[i];
|
|
|
|
const td1 = document.createElement('td');
|
|
if (part[0]) {
|
|
td1.className = 'elem';
|
|
td1.textContent = part[0];
|
|
}
|
|
|
|
let td2 = null;
|
|
if (part[1] && storedimages[part[1]] == null && part[2]) {
|
|
td2 = document.createElement('td');
|
|
const img = document.createElement('img');
|
|
img.src = part[2];
|
|
img.id = part[1];
|
|
storedimages[part[1]] = part[2];
|
|
td2.appendChild(img);
|
|
} else if (part[1]) {
|
|
td2 = document.createElement('td');
|
|
const img = document.createElement('img');
|
|
img.src = storedimages[part[1]];
|
|
img.id = part[1];
|
|
td2.appendChild(img);
|
|
}
|
|
let td3 = null;
|
|
const b = document.createElement('div');
|
|
if (part[4]) {
|
|
b.className = 'linkelem';
|
|
b.onmousedown = ((part) => {
|
|
// The outer function is used to close over a fresh "part" variable,
|
|
// rather than every onmousedown getting the "part" of the last entry.
|
|
return (e) => {
|
|
e.preventDefault();
|
|
const params = { src: part[4] };
|
|
switch (e.button) {
|
|
case 1:
|
|
params.statpanel_item_click = 'middle';
|
|
break;
|
|
case 2:
|
|
params.statpanel_item_click = 'right';
|
|
break;
|
|
default:
|
|
params.statpanel_item_click = 'left';
|
|
}
|
|
if (e.shiftKey) {
|
|
params.statpanel_item_shiftclick = 1;
|
|
}
|
|
if (e.ctrlKey) {
|
|
params.statpanel_item_ctrlclick = 1;
|
|
}
|
|
if (e.altKey) {
|
|
params.statpanel_item_altclick = 1;
|
|
}
|
|
Byond.topic(params);
|
|
};
|
|
})(part);
|
|
}
|
|
if (part[3]) {
|
|
td3 = document.createElement('td');
|
|
b.textContent = part[3];
|
|
td3.appendChild(b);
|
|
}
|
|
if (!td2 && !td3) {
|
|
td1.className = 'elem_span3';
|
|
td1.colSpan += 2;
|
|
} else if (!td2) {
|
|
td1.className = 'elem_span2';
|
|
td1.colSpan += 1;
|
|
} else if (!td3) {
|
|
td2.colSpan += 1;
|
|
}
|
|
tr.appendChild(td1);
|
|
if (td2) {
|
|
tr.appendChild(td2);
|
|
}
|
|
if (td3) {
|
|
tr.appendChild(td3);
|
|
}
|
|
table.appendChild(tr);
|
|
}
|
|
document.getElementById('statcontent').appendChild(table);
|
|
}
|
|
|
|
function draw_spells(cat) {
|
|
statcontentdiv.textContent = '';
|
|
const table = document.createElement('table');
|
|
for (let i = 0; i < spells.length; i++) {
|
|
const part = spells[i];
|
|
if (part[0] !== cat) continue;
|
|
const tr = document.createElement('tr');
|
|
const td1 = document.createElement('td');
|
|
td1.textContent = part[1];
|
|
const td2 = document.createElement('td');
|
|
if (part[3]) {
|
|
const a = document.createElement('a');
|
|
a.href = `byond://?src=${part[3]};statpanel_item_click=left`;
|
|
a.textContent = part[2];
|
|
td2.appendChild(a);
|
|
} else {
|
|
td2.textContent = part[2];
|
|
}
|
|
tr.appendChild(td1);
|
|
tr.appendChild(td2);
|
|
table.appendChild(tr);
|
|
}
|
|
document.getElementById('statcontent').appendChild(table);
|
|
}
|
|
|
|
function make_verb_onclick(command) {
|
|
return () => {
|
|
run_after_focus(() => {
|
|
Byond.command(command);
|
|
});
|
|
};
|
|
}
|
|
|
|
function draw_verbs(cat) {
|
|
statcontentdiv.textContent = '';
|
|
const table = document.createElement('div');
|
|
const additions = {}; // additional sub-categories to be rendered
|
|
table.className = 'grid-container';
|
|
sortVerbs();
|
|
if (split_admin_tabs && cat.lastIndexOf('.') !== -1) {
|
|
const splitName = cat.split('.');
|
|
if (splitName[0] === 'Admin') cat = splitName[1];
|
|
}
|
|
verbs.reverse(); // sort verbs backwards before we draw
|
|
for (let i = 0; i < verbs.length; ++i) {
|
|
const part = verbs[i];
|
|
let name = part[0];
|
|
if (split_admin_tabs && name.lastIndexOf('.') !== -1) {
|
|
const splitName = name.split('.');
|
|
if (splitName[0] === 'Admin') name = splitName[1];
|
|
}
|
|
const command = part[1];
|
|
const desc = part[2];
|
|
|
|
if (
|
|
command &&
|
|
name.lastIndexOf(cat, 0) !== -1 &&
|
|
(name.length === cat.length || name.charAt(cat.length) === '.')
|
|
) {
|
|
const subCat = name.lastIndexOf('.') !== -1 ? name.split('.')[1] : null;
|
|
if (subCat && !additions[subCat]) {
|
|
const newTable = document.createElement('div');
|
|
newTable.className = 'grid-container';
|
|
additions[subCat] = newTable;
|
|
}
|
|
|
|
const a = document.createElement('a');
|
|
a.href = '#';
|
|
a.onclick = make_verb_onclick(command.replace(/\s/g, '-'));
|
|
a.className = 'grid-item';
|
|
a.title = desc || 'No description';
|
|
const t = document.createElement('span');
|
|
t.textContent = command;
|
|
t.className = 'grid-item-text';
|
|
a.appendChild(t);
|
|
(subCat ? additions[subCat] : table).appendChild(a);
|
|
}
|
|
}
|
|
|
|
// Append base table to view
|
|
const content = document.getElementById('statcontent');
|
|
content.appendChild(table);
|
|
|
|
// Append additional sub-categories if relevant
|
|
for (const cat in additions) {
|
|
if (Object.hasOwn(additions, cat)) {
|
|
// do addition here
|
|
const header = document.createElement('h3');
|
|
header.textContent = cat;
|
|
content.appendChild(header);
|
|
content.appendChild(additions[cat]);
|
|
}
|
|
}
|
|
}
|
|
|
|
function set_theme(which) {
|
|
if (which === 'light' || which === 'vchatlight') {
|
|
document.body.className = '';
|
|
document.documentElement.className = 'light';
|
|
} else if (which === 'dark' || which === 'vchatdark') {
|
|
document.body.className = 'dark';
|
|
document.documentElement.className = 'dark';
|
|
}
|
|
}
|
|
|
|
function set_font_size(size) {
|
|
document.body.style.setProperty('font-size', size);
|
|
}
|
|
|
|
function set_tabs_style(style) {
|
|
if (style === 'default') {
|
|
menu.classList.add('menu-wrap');
|
|
menu.classList.remove('tabs-classic');
|
|
} else if (style === 'classic') {
|
|
menu.classList.add('menu-wrap');
|
|
menu.classList.add('tabs-classic');
|
|
} else if (style === 'scrollable') {
|
|
menu.classList.remove('menu-wrap');
|
|
menu.classList.remove('tabs-classic');
|
|
}
|
|
}
|
|
|
|
function restoreFocus() {
|
|
run_after_focus(() => {
|
|
Byond.winset('map', {
|
|
focus: true,
|
|
});
|
|
});
|
|
}
|
|
|
|
function getCookie(cname) {
|
|
const name = `${cname}=`;
|
|
const ca = document.cookie.split(';');
|
|
for (let i = 0; i < ca.length; i++) {
|
|
let c = ca[i];
|
|
while (c.charAt(0) === ' ') c = c.substring(1);
|
|
if (c.indexOf(name) === 0) {
|
|
return decoder(c.substring(name.length, c.length));
|
|
}
|
|
}
|
|
return '';
|
|
}
|
|
|
|
function add_verb_list(payload) {
|
|
const to_add = payload; // list of a list with category and verb inside it
|
|
to_add.sort(); // sort what we're adding
|
|
for (let i = 0; i < to_add.length; i++) {
|
|
const part = to_add[i];
|
|
if (!part[0]) continue;
|
|
let category = part[0];
|
|
if (category.indexOf('.') !== -1) {
|
|
const splitName = category.split('.');
|
|
if (split_admin_tabs && splitName[0] === 'Admin') category = splitName[1];
|
|
else category = splitName[0];
|
|
}
|
|
if (findVerbindex(part[1], verbs)) continue;
|
|
if (verb_tabs.includes(category)) {
|
|
verbs.push(part);
|
|
if (current_tab === category) {
|
|
draw_verbs(category); // redraw if we added a verb to the tab we're currently in
|
|
}
|
|
} else if (category) {
|
|
verb_tabs.push(category);
|
|
verbs.push(part);
|
|
createStatusTab(category);
|
|
}
|
|
}
|
|
}
|
|
|
|
function init_spells() {
|
|
let cat = '';
|
|
for (let i = 0; i < spell_tabs.length; i++) {
|
|
cat = spell_tabs[i];
|
|
if (cat.length > 0) {
|
|
verb_tabs.push(cat);
|
|
createStatusTab(cat);
|
|
}
|
|
}
|
|
}
|
|
|
|
document.addEventListener('mouseup', restoreFocus);
|
|
document.addEventListener('keyup', restoreFocus);
|
|
|
|
if (!current_tab) {
|
|
addPermanentTab('Status');
|
|
tab_change('Status');
|
|
}
|
|
|
|
window.onload = () => {
|
|
Byond.sendMessage('Update-Verbs');
|
|
};
|
|
|
|
Byond.subscribeTo('update_spells', (payload) => {
|
|
spell_tabs = payload.spell_tabs;
|
|
let do_update = false;
|
|
if (spell_tabs.includes(current_tab)) {
|
|
do_update = true;
|
|
}
|
|
init_spells();
|
|
if (payload.actions) {
|
|
spells = payload.actions;
|
|
if (do_update) {
|
|
draw_spells(current_tab);
|
|
}
|
|
} else {
|
|
remove_spells();
|
|
}
|
|
});
|
|
|
|
Byond.subscribeTo('remove_verb_list', (v) => {
|
|
const to_remove = v;
|
|
for (let i = 0; i < to_remove.length; i++) {
|
|
remove_verb(to_remove[i]);
|
|
}
|
|
check_verbs();
|
|
sortVerbs();
|
|
if (verb_tabs.includes(current_tab)) draw_verbs(current_tab);
|
|
});
|
|
|
|
// passes a 2D list of (verbcategory, verbname) creates tabs and adds verbs to respective list
|
|
// example (IC, Say)
|
|
Byond.subscribeTo('init_verbs', (payload) => {
|
|
wipe_verbs(); // remove all verb categories so we can replace them
|
|
checkStatusTab(); // remove all status tabs
|
|
verb_tabs = payload.panel_tabs;
|
|
verb_tabs.sort(); // sort it
|
|
let do_update = false;
|
|
let cat = '';
|
|
for (let i = 0; i < verb_tabs.length; i++) {
|
|
cat = verb_tabs[i];
|
|
createStatusTab(cat); // create a category if the verb doesn't exist yet
|
|
}
|
|
if (verb_tabs.includes(current_tab)) {
|
|
do_update = true;
|
|
}
|
|
if (payload.verblist) {
|
|
add_verb_list(payload.verblist);
|
|
sortVerbs(); // sort them
|
|
if (do_update) {
|
|
draw_verbs(current_tab);
|
|
}
|
|
}
|
|
SendTabsToByond();
|
|
});
|
|
|
|
Byond.subscribeTo('update_stat', (payload) => {
|
|
status_tab_parts = [payload.ping_str];
|
|
let parsed = payload.global_data;
|
|
|
|
for (let i = 0; i < parsed.length; i++)
|
|
if (parsed[i] != null) status_tab_parts.push(parsed[i]);
|
|
|
|
parsed = payload.other_str;
|
|
|
|
for (let i = 0; i < parsed.length; i++)
|
|
if (parsed[i] != null) status_tab_parts.push(parsed[i]);
|
|
|
|
if (current_tab === 'Status') {
|
|
draw_status();
|
|
} else if (current_tab === 'Debug Stat Panel') {
|
|
draw_debug();
|
|
}
|
|
});
|
|
|
|
Byond.subscribeTo('update_mc', (payload) => {
|
|
mc_tab_parts = payload.mc_data;
|
|
mc_tab_parts.splice(0, 0, ['Location:', payload.coord_entry]);
|
|
|
|
if (!verb_tabs.includes('MC')) {
|
|
verb_tabs.push('MC');
|
|
}
|
|
|
|
createStatusTab('MC');
|
|
|
|
if (current_tab === 'MC') {
|
|
draw_mc();
|
|
}
|
|
});
|
|
|
|
Byond.subscribeTo('remove_spells', () => {
|
|
for (let s = 0; s < spell_tabs.length; s++) {
|
|
removeStatusTab(spell_tabs[s]);
|
|
}
|
|
});
|
|
|
|
Byond.subscribeTo('init_spells', () => {
|
|
let cat = '';
|
|
for (let i = 0; i < spell_tabs.length; i++) {
|
|
cat = spell_tabs[i];
|
|
if (cat.length > 0) {
|
|
verb_tabs.push(cat);
|
|
createStatusTab(cat);
|
|
}
|
|
}
|
|
});
|
|
|
|
Byond.subscribeTo('check_spells', () => {
|
|
for (let v = 0; v < spell_tabs.length; v++) {
|
|
spell_cat_check(spell_tabs[v]);
|
|
}
|
|
});
|
|
|
|
Byond.subscribeTo('create_debug', () => {
|
|
if (!document.getElementById('Debug Stat Panel')) {
|
|
addPermanentTab('Debug Stat Panel');
|
|
} else {
|
|
removePermanentTab('Debug Stat Panel');
|
|
}
|
|
});
|
|
|
|
Byond.subscribeTo('create_listedturf', (TN) => {
|
|
remove_listedturf(); // remove the last one if we had one
|
|
turfname = TN;
|
|
addPermanentTab(turfname);
|
|
tab_change(turfname);
|
|
});
|
|
|
|
Byond.subscribeTo('create_misc', (TN) => {
|
|
addPermanentTab(TN);
|
|
});
|
|
|
|
Byond.subscribeTo('remove_misc', (TN) => {
|
|
removePermanentTab(TN);
|
|
});
|
|
|
|
Byond.subscribeTo('remove_admin_tabs', () => {
|
|
href_token = null;
|
|
remove_mc();
|
|
remove_tickets();
|
|
remove_sdql2();
|
|
});
|
|
|
|
Byond.subscribeTo('update_listedturf', (TC) => {
|
|
turfcontents = TC;
|
|
if (current_tab === turfname) {
|
|
draw_listedturf();
|
|
}
|
|
});
|
|
|
|
Byond.subscribeTo('update_misc', (payload) => {
|
|
const TN = payload.TN;
|
|
const TC = payload.TC;
|
|
misc.set(TN, TC);
|
|
if (current_tab === TN) {
|
|
draw_misc(TN);
|
|
}
|
|
});
|
|
|
|
Byond.subscribeTo('update_split_admin_tabs', (status) => {
|
|
status = status === true;
|
|
|
|
if (split_admin_tabs !== status) {
|
|
if (split_admin_tabs === true) {
|
|
removeStatusTab('Events');
|
|
removeStatusTab('Fun');
|
|
removeStatusTab('Game');
|
|
}
|
|
update_verbs();
|
|
}
|
|
split_admin_tabs = status;
|
|
});
|
|
|
|
Byond.subscribeTo('add_admin_tabs', (ht) => {
|
|
href_token = ht;
|
|
addPermanentTab('MC');
|
|
addPermanentTab('Tickets');
|
|
});
|
|
|
|
Byond.subscribeTo('add_tickets_tabs', (ht) => {
|
|
href_token = ht;
|
|
addPermanentTab('Tickets');
|
|
});
|
|
|
|
Byond.subscribeTo('update_examine', (payload) => {
|
|
examine = payload.EX;
|
|
if (examine.length > 0 && !verb_tabs.includes('Examine')) {
|
|
verb_tabs.push('Examine');
|
|
addPermanentTab('Examine');
|
|
}
|
|
if (current_tab === 'Examine') {
|
|
draw_examine();
|
|
}
|
|
if (payload.UPD) {
|
|
tab_change('Examine');
|
|
}
|
|
});
|
|
|
|
Byond.subscribeTo('update_sdql2', (S) => {
|
|
sdql2 = S;
|
|
if (sdql2.length > 0 && !verb_tabs.includes('SDQL2')) {
|
|
verb_tabs.push('SDQL2');
|
|
addPermanentTab('SDQL2');
|
|
}
|
|
if (current_tab === 'SDQL2') {
|
|
draw_sdql2();
|
|
}
|
|
});
|
|
|
|
Byond.subscribeTo('update_tickets', (T) => {
|
|
tickets = T;
|
|
if (!verb_tabs.includes('Tickets')) {
|
|
verb_tabs.push('Tickets');
|
|
addPermanentTab('Tickets');
|
|
}
|
|
if (current_tab === 'Tickets') {
|
|
draw_tickets();
|
|
}
|
|
});
|
|
|
|
Byond.subscribeTo('remove_listedturf', remove_listedturf);
|
|
|
|
Byond.subscribeTo('remove_sdql2', remove_sdql2);
|
|
|
|
Byond.subscribeTo('remove_mc', remove_mc);
|
|
|
|
Byond.subscribeTo('add_verb_list', add_verb_list);
|