mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2025-12-09 16:05:07 +00:00
[MIRROR] refactors statpanel to use tgui API [MDB IGNORE] (#13646)
* refactors statpanel to use tgui API * fix Co-authored-by: magatsuchi <88991542+magatsuchi@users.noreply.github.com> Co-authored-by: Tom <8881105+tf-4@users.noreply.github.com>
This commit is contained in:
@@ -1,8 +0,0 @@
|
||||
/// Bare minimum required verbs for stat panel operation
|
||||
GLOBAL_LIST_INIT(stat_panel_verbs, list(
|
||||
/client/verb/set_tab,
|
||||
/client/verb/send_tabs,
|
||||
/client/verb/remove_tabs,
|
||||
/client/verb/reset_tabs,
|
||||
/client/verb/panel_ready
|
||||
))
|
||||
@@ -43,9 +43,8 @@
|
||||
for(var/thing in verbs_list)
|
||||
var/procpath/verb_to_add = thing
|
||||
output_list[++output_list.len] = list(verb_to_add.category, verb_to_add.name)
|
||||
output_list = url_encode(json_encode(output_list))
|
||||
|
||||
target << output("[output_list];", "statbrowser:add_verb_list")
|
||||
target.stat_panel.send_message("add_verb_list", output_list)
|
||||
|
||||
/**
|
||||
* handles removing verb and sending it to browser to update, use this for removing verbs
|
||||
@@ -91,6 +90,5 @@
|
||||
for(var/thing in verbs_list)
|
||||
var/procpath/verb_to_remove = thing
|
||||
output_list[++output_list.len] = list(verb_to_remove.category, verb_to_remove.name)
|
||||
output_list = url_encode(json_encode(output_list))
|
||||
|
||||
target << output("[output_list];", "statbrowser:remove_verb_list")
|
||||
target.stat_panel.send_message("remove_verb_list", output_list)
|
||||
|
||||
@@ -412,7 +412,7 @@
|
||||
var/turf/T = get_turf(src)
|
||||
if(T && (isturf(loc) || isturf(src)) && user.TurfAdjacent(T))
|
||||
user.listed_turf = T
|
||||
user.client << output("[url_encode(json_encode(T.name))];", "statbrowser:create_listedturf")
|
||||
user.client.stat_panel.send_message("create_listedturf", T.name)
|
||||
|
||||
///The base proc of when something is right clicked on when alt is held - generally use alt_click_secondary instead
|
||||
/atom/proc/alt_click_on_secondary(atom/A)
|
||||
@@ -436,7 +436,7 @@
|
||||
var/turf/T = get_turf(A)
|
||||
if(T && user.TurfAdjacent(T))
|
||||
user.listed_turf = T
|
||||
user.client << output("[url_encode(json_encode(T.name))];", "statbrowser:create_listedturf")
|
||||
user.client.stat_panel.send_message("create_listedturf", T.name)
|
||||
|
||||
/mob/proc/TurfAdjacent(turf/T)
|
||||
return T.Adjacent(src)
|
||||
|
||||
@@ -6,14 +6,14 @@ SUBSYSTEM_DEF(statpanels)
|
||||
priority = FIRE_PRIORITY_STATPANEL
|
||||
runlevels = RUNLEVELS_DEFAULT | RUNLEVEL_LOBBY
|
||||
var/list/currentrun = list()
|
||||
var/encoded_global_data
|
||||
var/mc_data_encoded
|
||||
var/list/global_data
|
||||
var/list/mc_data
|
||||
var/list/cached_images = list()
|
||||
|
||||
///how many subsystem fires between most tab updates
|
||||
var/default_wait = 10
|
||||
///how many subsystem fires between updates of the status tab
|
||||
var/status_wait = 12
|
||||
var/status_wait = 6
|
||||
///how many subsystem fires between updates of the MC tab
|
||||
var/mc_wait = 5
|
||||
///how many full runs this subsystem has completed. used for variable rate refreshes.
|
||||
@@ -24,7 +24,7 @@ SUBSYSTEM_DEF(statpanels)
|
||||
num_fires++
|
||||
var/datum/map_config/cached = SSmapping.next_map_config
|
||||
/* SKYRAT EDIT CHANGE
|
||||
var/list/global_data = list(
|
||||
global_data = list(
|
||||
"Map: [SSmapping.config?.map_name || "Loading..."]",
|
||||
cached ? "Next Map: [cached.map_name]" : null,
|
||||
"Round ID: [GLOB.round_id ? GLOB.round_id : "NULL"]",
|
||||
@@ -56,28 +56,27 @@ SUBSYSTEM_DEF(statpanels)
|
||||
var/ETA = SSshuttle.emergency.getModeStr()
|
||||
if(ETA)
|
||||
global_data += "[ETA] [SSshuttle.emergency.getTimerStr()]"
|
||||
encoded_global_data = url_encode(json_encode(global_data))
|
||||
src.currentrun = GLOB.clients.Copy()
|
||||
mc_data_encoded = null
|
||||
mc_data = null
|
||||
|
||||
var/list/currentrun = src.currentrun
|
||||
while(length(currentrun))
|
||||
var/client/target = currentrun[length(currentrun)]
|
||||
currentrun.len--
|
||||
|
||||
if(!target.statbrowser_ready)
|
||||
if(!target.stat_panel.is_ready())
|
||||
continue
|
||||
|
||||
if(target.stat_tab == "Status" && num_fires % status_wait == 0)
|
||||
set_status_tab(target)
|
||||
|
||||
if(!target.holder)
|
||||
target << output("", "statbrowser:remove_admin_tabs")
|
||||
target.stat_panel.send_message("remove_admin_tabs")
|
||||
else
|
||||
target << output("[!!(target.prefs.toggles & SPLIT_ADMIN_TABS)]", "statbrowser:update_split_admin_tabs")
|
||||
target.stat_panel.send_message("update_split_admin_tabs", !!(target.prefs.toggles & SPLIT_ADMIN_TABS))
|
||||
|
||||
if(!("MC" in target.panel_tabs) || !("Tickets" in target.panel_tabs))
|
||||
target << output("[url_encode(target.holder.href_token)]", "statbrowser:add_admin_tabs")
|
||||
target.stat_panel.send_message("add_admin_tabs", target.holder.href_token)
|
||||
|
||||
if(target.stat_tab == "MC" && ((num_fires % mc_wait == 0) || target?.prefs.read_preference(/datum/preference/toggle/fast_mc_refresh)))
|
||||
set_MC_tab(target)
|
||||
@@ -86,7 +85,7 @@ SUBSYSTEM_DEF(statpanels)
|
||||
set_tickets_tab(target)
|
||||
|
||||
if(!length(GLOB.sdql2_queries) && ("SDQL2" in target.panel_tabs))
|
||||
target << output("", "statbrowser:remove_sdql2")
|
||||
target.stat_panel.send_message("remove_sdql2")
|
||||
|
||||
else if(length(GLOB.sdql2_queries) && (target.stat_tab == "SDQL2" || !("SDQL2" in target.panel_tabs)) && num_fires % default_wait == 0)
|
||||
set_SDQL2_tab(target)
|
||||
@@ -97,9 +96,10 @@ SUBSYSTEM_DEF(statpanels)
|
||||
if(num_fires % default_wait == 0)
|
||||
set_spells_tab(target, target_mob)
|
||||
|
||||
|
||||
if(target_mob?.listed_turf && num_fires % default_wait == 0)
|
||||
if(!target_mob.TurfAdjacent(target_mob.listed_turf))
|
||||
target << output("", "statbrowser:remove_listedturf")
|
||||
if(!target_mob.TurfAdjacent(target_mob.listed_turf) || isnull(target_mob.listed_turf))
|
||||
target.stat_panel.send_message("remove_listedturf")
|
||||
target_mob.listed_turf = null
|
||||
|
||||
else if(target.stat_tab == target_mob?.listed_turf.name || !(target_mob?.listed_turf.name in target.panel_tabs))
|
||||
@@ -109,23 +109,25 @@ SUBSYSTEM_DEF(statpanels)
|
||||
return
|
||||
|
||||
/datum/controller/subsystem/statpanels/proc/set_status_tab(client/target)
|
||||
if(!encoded_global_data)//statbrowser hasnt fired yet and we were called from immediate_send_stat_data()
|
||||
if(!global_data)//statbrowser hasnt fired yet and we were called from immediate_send_stat_data()
|
||||
return
|
||||
|
||||
var/ping_str = url_encode("Ping: [round(target.lastping, 1)]ms (Average: [round(target.avgping, 1)]ms)")
|
||||
var/other_str = url_encode(json_encode(target.mob?.get_status_tab_items()))
|
||||
target << output("[encoded_global_data];[ping_str];[other_str]", "statbrowser:update")
|
||||
target.stat_panel.send_message("update_stat", list(
|
||||
global_data = global_data,
|
||||
ping_str = "Ping: [round(target.lastping, 1)]ms (Average: [round(target.avgping, 1)]ms)",
|
||||
other_str = target.mob?.get_status_tab_items(),
|
||||
))
|
||||
|
||||
/datum/controller/subsystem/statpanels/proc/set_MC_tab(client/target)
|
||||
var/turf/eye_turf = get_turf(target.eye)
|
||||
var/coord_entry = url_encode(COORD(eye_turf))
|
||||
if(!mc_data_encoded)
|
||||
var/coord_entry = COORD(eye_turf)
|
||||
if(!mc_data)
|
||||
generate_mc_data()
|
||||
target << output("[mc_data_encoded];[coord_entry]", "statbrowser:update_mc")
|
||||
target.stat_panel.send_message("update_mc", list(mc_data = mc_data, coord_entry = coord_entry))
|
||||
|
||||
/datum/controller/subsystem/statpanels/proc/set_tickets_tab(client/target)
|
||||
var/list/ahelp_tickets = GLOB.ahelp_tickets.stat_entry()
|
||||
target << output("[url_encode(json_encode(ahelp_tickets))];", "statbrowser:update_tickets")
|
||||
target.stat_panel.send_message("update_tickets", ahelp_tickets)
|
||||
var/datum/interview_manager/m = GLOB.interviews
|
||||
|
||||
// get open interview count
|
||||
@@ -153,7 +155,7 @@ SUBSYSTEM_DEF(statpanels)
|
||||
)
|
||||
|
||||
// Push update
|
||||
target << output("[url_encode(json_encode(data))];", "statbrowser:update_interviews")
|
||||
target.stat_panel.send_message("update_interviews", data)
|
||||
|
||||
/datum/controller/subsystem/statpanels/proc/set_SDQL2_tab(client/target)
|
||||
var/list/sdql2A = list()
|
||||
@@ -163,7 +165,7 @@ SUBSYSTEM_DEF(statpanels)
|
||||
sdql2B = query.generate_stat()
|
||||
|
||||
sdql2A += sdql2B
|
||||
target << output(url_encode(json_encode(sdql2A)), "statbrowser:update_sdql2")
|
||||
target.stat_panel.send_message("update_sdql2", sdql2A)
|
||||
|
||||
/datum/controller/subsystem/statpanels/proc/set_spells_tab(client/target, mob/target_mob)
|
||||
var/list/proc_holders = target_mob.get_proc_holders()
|
||||
@@ -172,11 +174,7 @@ SUBSYSTEM_DEF(statpanels)
|
||||
for(var/proc_holder_list as anything in proc_holders)
|
||||
target.spell_tabs |= proc_holder_list[1]
|
||||
|
||||
var/proc_holders_encoded = ""
|
||||
if(length(proc_holders))
|
||||
proc_holders_encoded = url_encode(json_encode(proc_holders))
|
||||
|
||||
target << output("[url_encode(json_encode(target.spell_tabs))];[proc_holders_encoded]", "statbrowser:update_spells")
|
||||
target.stat_panel.send_message("update_spells", list(spell_tabs = target.spell_tabs, proc_holders_encoded = proc_holders))
|
||||
|
||||
/datum/controller/subsystem/statpanels/proc/set_turf_examine_tab(client/target, mob/target_mob)
|
||||
var/list/overrides = list()
|
||||
@@ -213,11 +211,11 @@ SUBSYSTEM_DEF(statpanels)
|
||||
else
|
||||
turfitems[++turfitems.len] = list("[turf_content.name]", REF(turf_content))
|
||||
|
||||
turfitems = url_encode(json_encode(turfitems))
|
||||
target << output("[turfitems];", "statbrowser:update_listedturf")
|
||||
turfitems = turfitems
|
||||
target.stat_panel.send_message("update_listedturf", turfitems)
|
||||
|
||||
/datum/controller/subsystem/statpanels/proc/generate_mc_data()
|
||||
var/list/mc_data = list(
|
||||
mc_data = list(
|
||||
list("CPU:", world.cpu),
|
||||
list("Instances:", "[num2text(world.contents.len, 10)]"),
|
||||
list("World Time:", "[world.time]"),
|
||||
@@ -231,11 +229,10 @@ SUBSYSTEM_DEF(statpanels)
|
||||
for(var/datum/controller/subsystem/sub_system as anything in Master.subsystems)
|
||||
mc_data[++mc_data.len] = list("\[[sub_system.state_letter()]][sub_system.name]", sub_system.stat_entry(), "\ref[sub_system]")
|
||||
mc_data[++mc_data.len] = list("Camera Net", "Cameras: [GLOB.cameranet.cameras.len] | Chunks: [GLOB.cameranet.chunks.len]", "\ref[GLOB.cameranet]")
|
||||
mc_data_encoded = url_encode(json_encode(mc_data))
|
||||
|
||||
///immediately update the active statpanel tab of the target client
|
||||
/datum/controller/subsystem/statpanels/proc/immediate_send_stat_data(client/target)
|
||||
if(!target.statbrowser_ready)
|
||||
if(!target.stat_panel.is_ready())
|
||||
return FALSE
|
||||
|
||||
if(target.stat_tab == "Status")
|
||||
@@ -249,7 +246,7 @@ SUBSYSTEM_DEF(statpanels)
|
||||
|
||||
if(target_mob?.listed_turf)
|
||||
if(!target_mob.TurfAdjacent(target_mob.listed_turf))
|
||||
target << output("", "statbrowser:remove_listedturf")
|
||||
target.stat_panel.send_message("removed_listedturf")
|
||||
target_mob.listed_turf = null
|
||||
|
||||
else if(target.stat_tab == target_mob?.listed_turf.name || !(target_mob?.listed_turf.name in target.panel_tabs))
|
||||
@@ -268,7 +265,7 @@ SUBSYSTEM_DEF(statpanels)
|
||||
return TRUE
|
||||
|
||||
if(!length(GLOB.sdql2_queries) && ("SDQL2" in target.panel_tabs))
|
||||
target << output("", "statbrowser:remove_sdql2")
|
||||
target.stat_panel.send_message("remove_sdql2")
|
||||
|
||||
else if(length(GLOB.sdql2_queries) && target.stat_tab == "SDQL2")
|
||||
set_SDQL2_tab(target)
|
||||
@@ -277,41 +274,5 @@ SUBSYSTEM_DEF(statpanels)
|
||||
SIGNAL_HANDLER
|
||||
SSstatpanels.cached_images -= REF(src)
|
||||
|
||||
/// verbs that send information from the browser UI
|
||||
/client/verb/set_tab(tab as text|null)
|
||||
set name = "Set Tab"
|
||||
set hidden = TRUE
|
||||
|
||||
stat_tab = tab
|
||||
SSstatpanels.immediate_send_stat_data(src)
|
||||
|
||||
/client/verb/send_tabs(tabs as text|null)
|
||||
set name = "Send Tabs"
|
||||
set hidden = TRUE
|
||||
|
||||
panel_tabs |= tabs
|
||||
|
||||
/client/verb/remove_tabs(tabs as text|null)
|
||||
set name = "Remove Tabs"
|
||||
set hidden = TRUE
|
||||
|
||||
panel_tabs -= tabs
|
||||
|
||||
/client/verb/reset_tabs()
|
||||
set name = "Reset Tabs"
|
||||
set hidden = TRUE
|
||||
|
||||
panel_tabs = list()
|
||||
|
||||
/client/verb/panel_ready()
|
||||
set name = "Panel Ready"
|
||||
set hidden = TRUE
|
||||
|
||||
statbrowser_ready = TRUE
|
||||
init_verbs()
|
||||
|
||||
/client/verb/update_verbs()
|
||||
set name = "Update Verbs"
|
||||
set hidden = TRUE
|
||||
|
||||
init_verbs()
|
||||
/// Stat panel window declaration
|
||||
/client/var/datum/tgui_window/stat_panel
|
||||
|
||||
@@ -819,7 +819,7 @@
|
||||
if(istype(S, spell))
|
||||
spell_list -= S
|
||||
qdel(S)
|
||||
current?.client << output(null, "statbrowser:check_spells")
|
||||
current?.client.stat_panel.send_message("check_spells")
|
||||
|
||||
/datum/mind/proc/RemoveAllSpells()
|
||||
for(var/obj/effect/proc_holder/S in spell_list)
|
||||
|
||||
@@ -862,7 +862,7 @@ GLOBAL_PROTECT(admin_verbs_hideable)
|
||||
set name = "Debug Stat Panel"
|
||||
set category = "Debug"
|
||||
|
||||
src << output("", "statbrowser:create_debug")
|
||||
src.stat_panel.send_message("create_debug")
|
||||
|
||||
/client/proc/admin_2fa_verify()
|
||||
set name = "Verify Admin"
|
||||
|
||||
@@ -181,9 +181,6 @@
|
||||
/// our current tab
|
||||
var/stat_tab
|
||||
|
||||
/// whether our browser is ready or not yet
|
||||
var/statbrowser_ready = FALSE
|
||||
|
||||
/// list of all tabs
|
||||
var/list/panel_tabs = list()
|
||||
/// list of tabs containing spells and abilities
|
||||
|
||||
@@ -87,7 +87,7 @@ GLOBAL_LIST_INIT(blacklisted_builds, list(
|
||||
if(href_list["reload_tguipanel"])
|
||||
nuke_chat()
|
||||
if(href_list["reload_statbrowser"])
|
||||
src << browse(file('html/statbrowser.html'), "window=statbrowser")
|
||||
stat_panel.reinitialize()
|
||||
// Log all hrefs
|
||||
log_href("[src] (usr:[usr]\[[COORD(usr)]\]) : [hsrc ? "[hsrc] " : ""][href]")
|
||||
|
||||
@@ -213,8 +213,12 @@ GLOBAL_LIST_INIT(blacklisted_builds, list(
|
||||
GLOB.clients += src
|
||||
GLOB.directory[ckey] = src
|
||||
|
||||
// Instantiate stat panel
|
||||
stat_panel = new(src, "statbrowser")
|
||||
stat_panel.subscribe(src, .proc/on_stat_panel_message)
|
||||
|
||||
// Instantiate tgui panel
|
||||
tgui_panel = new(src)
|
||||
tgui_panel = new(src, "browseroutput")
|
||||
|
||||
set_right_click_menu_mode(TRUE)
|
||||
|
||||
@@ -344,9 +348,15 @@ GLOBAL_LIST_INIT(blacklisted_builds, list(
|
||||
if(SSinput.initialized)
|
||||
set_macros()
|
||||
|
||||
// Initialize tgui panel
|
||||
src << browse(file('html/statbrowser.html'), "window=statbrowser")
|
||||
// Initialize stat panel
|
||||
stat_panel.initialize(
|
||||
inline_html = file2text('html/statbrowser.html'),
|
||||
inline_js = file2text('html/statbrowser.js'),
|
||||
inline_css = file2text('html/statbrowser.css'),
|
||||
)
|
||||
addtimer(CALLBACK(src, .proc/check_panel_loaded), 30 SECONDS)
|
||||
|
||||
// Initialize tgui panel
|
||||
tgui_panel.initialize()
|
||||
|
||||
if(alert_mob_dupe_login && !holder)
|
||||
@@ -1129,10 +1139,10 @@ GLOBAL_LIST_INIT(blacklisted_builds, list(
|
||||
continue
|
||||
panel_tabs |= verb_to_init.category
|
||||
verblist[++verblist.len] = list(verb_to_init.category, verb_to_init.name)
|
||||
src << output("[url_encode(json_encode(panel_tabs))];[url_encode(json_encode(verblist))]", "statbrowser:init_verbs")
|
||||
src.stat_panel.send_message("init_verbs", list(panel_tabs = panel_tabs, verblist = verblist))
|
||||
|
||||
/client/proc/check_panel_loaded()
|
||||
if(statbrowser_ready)
|
||||
if(stat_panel.is_ready())
|
||||
return
|
||||
to_chat(src, span_userdanger("Statpanel failed to load, click <a href='?src=[REF(src)];reload_statbrowser=1'>here</a> to reload the panel "))
|
||||
|
||||
@@ -1182,6 +1192,23 @@ GLOBAL_LIST_INIT(blacklisted_builds, list(
|
||||
else
|
||||
SSambience.remove_ambience_client(src)
|
||||
|
||||
/**
|
||||
* Handles incoming messages from the stat-panel TGUI.
|
||||
*/
|
||||
/client/proc/on_stat_panel_message(type, payload)
|
||||
switch(type)
|
||||
if("Update-Verbs")
|
||||
init_verbs()
|
||||
if("Remove-Tabs")
|
||||
panel_tabs -= payload["tab"]
|
||||
if("Send-Tabs")
|
||||
panel_tabs |= payload["tab"]
|
||||
if("Reset-Tabs")
|
||||
panel_tabs = list()
|
||||
if("Set-Tab")
|
||||
stat_tab = payload["tab"]
|
||||
SSstatpanels.immediate_send_stat_data(src)
|
||||
|
||||
/// Checks if this client has met the days requirement passed in, or if
|
||||
/// they are exempt from it.
|
||||
/// Returns the number of days left, or 0.
|
||||
|
||||
@@ -472,14 +472,12 @@
|
||||
// First we detain them by removing all the verbs they have on client
|
||||
for (var/v in client.verbs)
|
||||
var/procpath/verb_path = v
|
||||
if (!(verb_path in GLOB.stat_panel_verbs))
|
||||
remove_verb(client, verb_path)
|
||||
remove_verb(client, verb_path)
|
||||
|
||||
// Then remove those on their mob as well
|
||||
for (var/v in verbs)
|
||||
var/procpath/verb_path = v
|
||||
if (!(verb_path in GLOB.stat_panel_verbs))
|
||||
remove_verb(src, verb_path)
|
||||
remove_verb(src, verb_path)
|
||||
|
||||
// Then we create the interview form and show it to the client
|
||||
var/datum/interview/I = GLOB.interviews.interview_for_client(client)
|
||||
|
||||
@@ -924,7 +924,7 @@
|
||||
LAZYREMOVE(mob_spell_list, S)
|
||||
qdel(S)
|
||||
if(client)
|
||||
client << output(null, "statbrowser:check_spells")
|
||||
client.stat_panel.send_message("check_spells")
|
||||
|
||||
/**
|
||||
* Checks to see if the mob can cast normal magic spells.
|
||||
|
||||
@@ -94,6 +94,7 @@
|
||||
window.acquire_lock(src)
|
||||
if(!window.is_ready())
|
||||
window.initialize(
|
||||
strict_mode = TRUE,
|
||||
fancy = user.client.prefs.read_preference(/datum/preference/toggle/tgui_fancy),
|
||||
assets = list(
|
||||
get_asset_datum(/datum/asset/simple/tgui),
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
var/message_queue
|
||||
var/sent_assets = list()
|
||||
// Vars passed to initialize proc (and saved for later)
|
||||
var/initial_strict_mode
|
||||
var/initial_fancy
|
||||
var/initial_assets
|
||||
var/initial_inline_html
|
||||
@@ -47,11 +48,15 @@
|
||||
* state. You can begin sending messages right after initializing. Messages
|
||||
* will be put into the queue until the window finishes loading.
|
||||
*
|
||||
* optional assets list List of assets to inline into the html.
|
||||
* optional inline_html string Custom HTML to inject.
|
||||
* optional fancy bool If TRUE, will hide the window titlebar.
|
||||
* optional strict_mode bool - Enables strict error handling and BSOD.
|
||||
* optional fancy bool - If TRUE and if this is NOT a panel, will hide the window titlebar.
|
||||
* optional assets list - List of assets to load during initialization.
|
||||
* optional inline_html string - Custom HTML to inject.
|
||||
* optional inline_js string - Custom JS to inject.
|
||||
* optional inline_css string - Custom CSS to inject.
|
||||
*/
|
||||
/datum/tgui_window/proc/initialize(
|
||||
strict_mode = FALSE,
|
||||
fancy = FALSE,
|
||||
assets = list(),
|
||||
inline_html = "",
|
||||
@@ -79,6 +84,7 @@
|
||||
// Generate page html
|
||||
var/html = SStgui.basehtml
|
||||
html = replacetextEx(html, "\[tgui:windowId]", id)
|
||||
html = replacetextEx(html, "\[tgui:strictMode]", strict_mode)
|
||||
// Inject assets
|
||||
var/inline_assets_str = ""
|
||||
for(var/datum/asset/asset in assets)
|
||||
@@ -99,7 +105,7 @@
|
||||
html = replacetextEx(html, "<!-- tgui:inline-html -->", inline_html)
|
||||
// Inject inline JS
|
||||
if (inline_js)
|
||||
inline_js = "<script>\n[inline_js]\n</script>"
|
||||
inline_js = "<script>\n'use strict';\n[inline_js]\n</script>"
|
||||
html = replacetextEx(html, "<!-- tgui:inline-js -->", inline_js)
|
||||
// Inject inline CSS
|
||||
if (inline_css)
|
||||
@@ -113,6 +119,20 @@
|
||||
if(!is_browser)
|
||||
winset(client, id, "on-close=\"uiclose [id]\"")
|
||||
|
||||
/**
|
||||
* public
|
||||
*
|
||||
* Reinitializes the panel with previous data used for initialization.
|
||||
*/
|
||||
/datum/tgui_window/proc/reinitialize()
|
||||
initialize(
|
||||
strict_mode = initial_strict_mode,
|
||||
fancy = initial_fancy,
|
||||
assets = initial_assets,
|
||||
inline_html = initial_inline_html,
|
||||
inline_js = initial_inline_js,
|
||||
inline_css = initial_inline_css)
|
||||
|
||||
/**
|
||||
* public
|
||||
*
|
||||
@@ -346,12 +366,7 @@
|
||||
client << link(href_list["url"])
|
||||
if("cacheReloaded")
|
||||
// Reinitialize
|
||||
initialize(
|
||||
fancy = initial_fancy,
|
||||
assets = initial_assets,
|
||||
inline_html = initial_inline_html,
|
||||
inline_js = initial_inline_js,
|
||||
inline_css = initial_inline_css)
|
||||
reinitialize()
|
||||
// Resend the assets
|
||||
for(var/asset in sent_assets)
|
||||
send_asset(asset)
|
||||
|
||||
@@ -13,9 +13,9 @@
|
||||
var/broken = FALSE
|
||||
var/initialized_at
|
||||
|
||||
/datum/tgui_panel/New(client/client)
|
||||
/datum/tgui_panel/New(client/client, id)
|
||||
src.client = client
|
||||
window = new(client, "browseroutput")
|
||||
window = new(client, id)
|
||||
window.subscribe(src, .proc/on_message)
|
||||
|
||||
/datum/tgui_panel/Del()
|
||||
@@ -42,9 +42,11 @@
|
||||
sleep(1)
|
||||
initialized_at = world.time
|
||||
// Perform a clean initialization
|
||||
window.initialize(assets = list(
|
||||
get_asset_datum(/datum/asset/simple/tgui_panel),
|
||||
))
|
||||
window.initialize(
|
||||
strict_mode = TRUE,
|
||||
assets = list(
|
||||
get_asset_datum(/datum/asset/simple/tgui_panel),
|
||||
))
|
||||
window.send_asset(get_asset_datum(/datum/asset/simple/namespaced/fontawesome))
|
||||
window.send_asset(get_asset_datum(/datum/asset/spritesheet/chat))
|
||||
// Other setup
|
||||
|
||||
227
html/statbrowser.css
Normal file
227
html/statbrowser.css
Normal file
@@ -0,0 +1,227 @@
|
||||
body {
|
||||
font-family: Verdana, Geneva, Tahoma, sans-serif;
|
||||
font-size: 12px !important;
|
||||
margin: 0 !important;
|
||||
padding: 0 !important;
|
||||
overflow-x: hidden;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
body.dark {
|
||||
background-color: #131313;
|
||||
color: #b2c4dd;
|
||||
scrollbar-base-color: #1c1c1c;
|
||||
scrollbar-face-color: #3b3b3b;
|
||||
scrollbar-3dlight-color: #252525;
|
||||
scrollbar-highlight-color: #252525;
|
||||
scrollbar-track-color: #1c1c1c;
|
||||
scrollbar-arrow-color: #929292;
|
||||
scrollbar-shadow-color: #3b3b3b;
|
||||
}
|
||||
|
||||
#menu {
|
||||
background-color: #F0F0F0;
|
||||
position: fixed;
|
||||
width: 100%;
|
||||
z-index: 100;
|
||||
}
|
||||
|
||||
.dark #menu {
|
||||
background-color: #202020;
|
||||
}
|
||||
|
||||
#statcontent {
|
||||
padding: 7px 7px 7px 7px;
|
||||
}
|
||||
|
||||
a {
|
||||
color: black;
|
||||
text-decoration: none
|
||||
}
|
||||
|
||||
.dark a {
|
||||
color: #b2c4dd;
|
||||
}
|
||||
|
||||
a:hover,
|
||||
.dark a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
ul {
|
||||
list-style-type: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
background-color: #333;
|
||||
}
|
||||
|
||||
li {
|
||||
float: left;
|
||||
}
|
||||
|
||||
li a {
|
||||
display: block;
|
||||
color: white;
|
||||
text-align: center;
|
||||
padding: 14px 16px;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
li a:hover:not(.active) {
|
||||
background-color: #111;
|
||||
}
|
||||
|
||||
.button-container {
|
||||
display: inline-flex;
|
||||
flex-wrap: wrap-reverse;
|
||||
flex-direction: row;
|
||||
align-items: flex-start;
|
||||
overflow-x: hidden;
|
||||
white-space: pre-wrap;
|
||||
padding: 0 4px;
|
||||
}
|
||||
|
||||
.button {
|
||||
background-color: #dfdfdf;
|
||||
border: 1px solid #cecece;
|
||||
border-bottom-width: 2px;
|
||||
color: rgba(0, 0, 0, 0.7);
|
||||
padding: 6px 4px 4px;
|
||||
text-align: center;
|
||||
text-decoration: none;
|
||||
font-size: 12px;
|
||||
margin: 0;
|
||||
cursor: pointer;
|
||||
transition-duration: 100ms;
|
||||
order: 3;
|
||||
min-width: 40px;
|
||||
}
|
||||
|
||||
.dark button {
|
||||
background-color: #222222;
|
||||
border-color: #343434;
|
||||
color: rgba(255, 255, 255, 0.5);
|
||||
}
|
||||
|
||||
.button:hover {
|
||||
background-color: #ececec;
|
||||
transition-duration: 0;
|
||||
}
|
||||
|
||||
.dark button:hover {
|
||||
background-color: #2e2e2e;
|
||||
}
|
||||
|
||||
.button:active,
|
||||
.button.active {
|
||||
background-color: #ffffff;
|
||||
color: black;
|
||||
border-top-color: #cecece;
|
||||
border-left-color: #cecece;
|
||||
border-right-color: #cecece;
|
||||
border-bottom-color: #ffffff;
|
||||
}
|
||||
|
||||
.dark .button:active,
|
||||
.dark .button.active {
|
||||
background-color: #444444;
|
||||
color: white;
|
||||
border-top-color: #343434;
|
||||
border-left-color: #343434;
|
||||
border-right-color: #343434;
|
||||
border-bottom-color: #ffffff;
|
||||
}
|
||||
|
||||
.grid-container {
|
||||
margin: -2px;
|
||||
margin-right: -15px;
|
||||
}
|
||||
|
||||
.grid-item {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
overflow: visible;
|
||||
padding: 3px 2px;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
@media only screen and (min-width: 300px) {
|
||||
.grid-item {
|
||||
width: 50%;
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (min-width: 430px) {
|
||||
.grid-item {
|
||||
width: 33%;
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (min-width: 560px) {
|
||||
.grid-item {
|
||||
width: 25%;
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (min-width: 770px) {
|
||||
.grid-item {
|
||||
width: 20%;
|
||||
}
|
||||
}
|
||||
|
||||
.grid-item:hover {
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.grid-item:hover .grid-item-text {
|
||||
width: auto;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.grid-item-text {
|
||||
display: inline-block;
|
||||
width: 100%;
|
||||
background-color: #ffffff;
|
||||
margin: 0 -6px;
|
||||
padding: 0 6px;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.dark .grid-item-text {
|
||||
background-color: #131313;
|
||||
}
|
||||
|
||||
.link {
|
||||
display: inline;
|
||||
background: none;
|
||||
border: none;
|
||||
padding: 7px 14px;
|
||||
color: black;
|
||||
text-decoration: none;
|
||||
cursor: pointer;
|
||||
font-size: 13px;
|
||||
margin: 2px 2px;
|
||||
}
|
||||
|
||||
.dark .link {
|
||||
color: #abc6ec;
|
||||
}
|
||||
|
||||
.link:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
img {
|
||||
-ms-interpolation-mode: nearest-neighbor;
|
||||
image-rendering: pixelated;
|
||||
}
|
||||
|
||||
.interview_panel_controls,
|
||||
.interview_panel_stats {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
1003
html/statbrowser.js
Normal file
1003
html/statbrowser.js
Normal file
File diff suppressed because it is too large
Load Diff
@@ -165,7 +165,6 @@
|
||||
#include "code\__DEFINES\stat.dm"
|
||||
#include "code\__DEFINES\stat_tracking.dm"
|
||||
#include "code\__DEFINES\station.dm"
|
||||
#include "code\__DEFINES\statpanel.dm"
|
||||
#include "code\__DEFINES\status_effects.dm"
|
||||
#include "code\__DEFINES\storage.dm"
|
||||
#include "code\__DEFINES\strippable.dm"
|
||||
|
||||
@@ -261,3 +261,21 @@ Byond.winget(null, 'url').then((serverUrl) => {
|
||||
Byond.command('.quit');
|
||||
});
|
||||
```
|
||||
|
||||
## Strict Mode
|
||||
|
||||
Strict mode is a flag that you can set on tgui window.
|
||||
|
||||
```dm
|
||||
window.initialize(strict_mode = TRUE)
|
||||
```
|
||||
|
||||
If `TRUE`, unhandled errors and common mistakes result in a blue screen of death with a stack trace of the error, which you can use to debug it. Bluescreened window stops handling incoming messages and closes the active instance of tgui datum if there was one, to avoid a massive spam of errors and help to deal with them one by one.
|
||||
|
||||
It can be defined in `window.initialize()` in DM, as shown above, or changed in runtime at runtime via `Byond.strictMode` to `true` or `false`.
|
||||
|
||||
```js
|
||||
Byond.strictMode = true;
|
||||
```
|
||||
|
||||
It is recommended that you keep this **ON** to detect hard to find bugs.
|
||||
|
||||
12
tgui/global.d.ts
vendored
12
tgui/global.d.ts
vendored
@@ -71,6 +71,18 @@ type ByondType = {
|
||||
*/
|
||||
IS_LTE_IE11: boolean;
|
||||
|
||||
/**
|
||||
* If `true`, unhandled errors and common mistakes result in a blue screen
|
||||
* of death, which stops this window from handling incoming messages and
|
||||
* closes the active instance of tgui datum if there was one.
|
||||
*
|
||||
* It can be defined in window.initialize() in DM, or changed in runtime
|
||||
* here via this property to `true` or `false`.
|
||||
*
|
||||
* It is recommended that you keep this ON to detect hard to find bugs.
|
||||
*/
|
||||
strictMode: boolean;
|
||||
|
||||
/**
|
||||
* Makes a BYOND call.
|
||||
*
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
<!-- Inlined metadata -->
|
||||
<meta id="tgui:windowId" content="[tgui:windowId]">
|
||||
<meta id="tgui:strictMode" content="[tgui:strictMode]">
|
||||
|
||||
<!-- Early setup -->
|
||||
<script type="text/javascript">
|
||||
@@ -64,6 +65,9 @@
|
||||
Byond.IS_LTE_IE10 = Byond.TRIDENT !== null && Byond.TRIDENT <= 6;
|
||||
Byond.IS_LTE_IE11 = Byond.TRIDENT !== null && Byond.TRIDENT <= 7;
|
||||
|
||||
// Strict mode flag
|
||||
Byond.strictMode = Boolean(Number(parseMetaTag('tgui:strictMode')));
|
||||
|
||||
// Callbacks for asynchronous calls
|
||||
Byond.__callbacks__ = [];
|
||||
|
||||
@@ -220,13 +224,13 @@
|
||||
};
|
||||
|
||||
Byond.subscribeTo = function (type, listener) {
|
||||
listener = function (_type, payload) {
|
||||
var _listener = function (_type, payload) {
|
||||
if (_type === type) {
|
||||
listener(payload);
|
||||
}
|
||||
};
|
||||
window.update.listeners.push(listener);
|
||||
window.update.flushQueue(listener);
|
||||
window.update.flushQueue(_listener);
|
||||
window.update.listeners.push(_listener);
|
||||
};
|
||||
|
||||
// Asset loaders
|
||||
@@ -363,6 +367,7 @@
|
||||
// ------------------------------------------------------
|
||||
|
||||
window.onerror = function (msg, url, line, col, error) {
|
||||
window.onerror.errorCount = (window.onerror.errorCount || 0) + 1;
|
||||
// Proper stacktrace
|
||||
var stack = error && error.stack;
|
||||
// Ghetto stacktrace
|
||||
@@ -375,39 +380,51 @@ window.onerror = function (msg, url, line, col, error) {
|
||||
// Augment the stack
|
||||
stack = window.__augmentStack__(stack, error);
|
||||
// Print error to the page
|
||||
var errorRoot = document.getElementById('FatalError');
|
||||
var errorStack = document.getElementById('FatalError__stack');
|
||||
if (errorRoot) {
|
||||
errorRoot.className = 'FatalError FatalError--visible';
|
||||
if (window.onerror.__stack__) {
|
||||
window.onerror.__stack__ += '\n\n' + stack;
|
||||
if (Byond.strictMode) {
|
||||
var errorRoot = document.getElementById('FatalError');
|
||||
var errorStack = document.getElementById('FatalError__stack');
|
||||
if (errorRoot) {
|
||||
errorRoot.className = 'FatalError FatalError--visible';
|
||||
if (window.onerror.__stack__) {
|
||||
window.onerror.__stack__ += '\n\n' + stack;
|
||||
}
|
||||
else {
|
||||
window.onerror.__stack__ = stack;
|
||||
}
|
||||
var textProp = Byond.IS_LTE_IE8 ? 'innerText' : 'textContent';
|
||||
errorStack[textProp] = window.onerror.__stack__;
|
||||
}
|
||||
else {
|
||||
window.onerror.__stack__ = stack;
|
||||
}
|
||||
var textProp = Byond.IS_LTE_IE8 ? 'innerText' : 'textContent';
|
||||
errorStack[textProp] = window.onerror.__stack__;
|
||||
// Set window geometry
|
||||
var setFatalErrorGeometry = function () {
|
||||
Byond.winset(Byond.windowId, {
|
||||
titlebar: true,
|
||||
'is-visible': true,
|
||||
'can-resize': true,
|
||||
});
|
||||
};
|
||||
setFatalErrorGeometry();
|
||||
setInterval(setFatalErrorGeometry, 1000);
|
||||
}
|
||||
// Set window geometry
|
||||
var setFatalErrorGeometry = function () {
|
||||
Byond.winset(Byond.windowId, {
|
||||
titlebar: true,
|
||||
size: '600x600',
|
||||
'is-visible': true,
|
||||
'can-resize': true,
|
||||
});
|
||||
};
|
||||
setFatalErrorGeometry();
|
||||
setInterval(setFatalErrorGeometry, 1000);
|
||||
// Send logs to the game server
|
||||
Byond.sendMessage({
|
||||
type: 'log',
|
||||
fatal: 1,
|
||||
message: stack,
|
||||
});
|
||||
if (Byond.strictMode) {
|
||||
Byond.sendMessage({
|
||||
type: 'log',
|
||||
fatal: 1,
|
||||
message: stack,
|
||||
});
|
||||
}
|
||||
else if (window.onerror.errorCount <= 1) {
|
||||
stack += '\nWindow is in non-strict mode, future errors are suppressed.';
|
||||
Byond.sendMessage({
|
||||
type: 'log',
|
||||
message: stack,
|
||||
});
|
||||
}
|
||||
// Short-circuit further updates
|
||||
window.__updateQueue__ = [];
|
||||
window.update = function () {};
|
||||
if (Byond.strictMode) {
|
||||
window.update = function () {};
|
||||
window.update.queue = [];
|
||||
}
|
||||
// Prevent default action
|
||||
return true;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user