From 35b3a76176839edb31c8866401c491e4bf0d8d94 Mon Sep 17 00:00:00 2001
From: Kashargul <144968721+Kashargul@users.noreply.github.com>
Date: Wed, 2 Apr 2025 21:40:51 +0200
Subject: [PATCH] some fixes (#17468)
---
code/datums/browser.dm | 268 ++++++++----------
.../assets/spritesheets/vending.dm | 18 +-
code/modules/casino/casino_prize_vendor.dm | 2 +-
code/modules/economy/vending.dm | 2 +-
code/modules/telesci/gps_advanced.dm | 1 -
tgui/packages/tgui-panel/chat/renderer.tsx | 17 ++
6 files changed, 155 insertions(+), 153 deletions(-)
diff --git a/code/datums/browser.dm b/code/datums/browser.dm
index 7f68c185c6f..f15363958f6 100644
--- a/code/datums/browser.dm
+++ b/code/datums/browser.dm
@@ -4,19 +4,18 @@
var/window_id // window_id is used as the window name for browse and onclose
var/width = 0
var/height = 0
- var/atom/ref = null
- var/window_options = "focus=0;can_close=1;can_minimize=1;can_maximize=0;can_resize=1;titlebar=1;" // window option is set using window_id
+ var/datum/weakref/ref = null
+ var/window_options = "can_close=1;can_minimize=1;can_maximize=0;can_resize=1;titlebar=1;" // window option is set using window_id
var/stylesheets[0]
var/scripts[0]
- var/title_image
var/head_elements
var/body_elements
var/head_content = ""
var/content = ""
- var/title_buttons = ""
-/datum/browser/New(nuser, nwindow_id, ntitle = 0, nwidth = 0, nheight = 0, var/atom/nref = null)
+/datum/browser/New(nuser, nwindow_id, ntitle = 0, nwidth = 0, nheight = 0, atom/nref = null)
user = nuser
+ RegisterSignal(user, COMSIG_PARENT_QDELETING, PROC_REF(user_deleted))
window_id = nwindow_id
if (ntitle)
title = format_text(ntitle)
@@ -25,40 +24,36 @@
if (nheight)
height = nheight
if (nref)
- ref = nref
- // If a client exists, but they have disabled fancy windowing, disable it!
- if(!user?.client?.prefs?.read_preference(/datum/preference/toggle/browser_style))
- return
- add_stylesheet("common", 'html/browser/common.css') // this CSS sheet is common to all UIs
+ ref = WEAKREF(nref)
-//VOREStation Edit - Allow browser datums to be garbage collected
-/datum/browser/Destroy()
- close()
- ref = null
+/datum/browser/proc/user_deleted(datum/source)
+ SIGNAL_HANDLER
user = null
- . = ..()
-//VOREStation Edit End - Allow browser datums to be garbage collected
-
-/datum/browser/proc/set_title(ntitle)
- title = format_text(ntitle)
/datum/browser/proc/add_head_content(nhead_content)
head_content = nhead_content
-/datum/browser/proc/set_title_buttons(ntitle_buttons)
- title_buttons = ntitle_buttons
-
/datum/browser/proc/set_window_options(nwindow_options)
window_options = nwindow_options
-/datum/browser/proc/set_title_image(ntitle_image)
- //title_image = ntitle_image
-
/datum/browser/proc/add_stylesheet(name, file)
- stylesheets[name] = file
+ if (istype(name, /datum/asset/spritesheet))
+ var/datum/asset/spritesheet/sheet = name
+ stylesheets["spritesheet_[sheet.name].css"] = "data/spritesheets/[sheet.name]"
+ else if (istype(name, /datum/asset/spritesheet_batched))
+ var/datum/asset/spritesheet_batched/sheet = name
+ stylesheets["spritesheet_[sheet.name].css"] = "data/spritesheets/[sheet.name]"
+ else
+ var/asset_name = "[name].css"
+
+ stylesheets[asset_name] = file
+
+ if (!SSassets.cache[asset_name])
+ SSassets.transport.register_asset(asset_name, file)
/datum/browser/proc/add_script(name, file)
- scripts[name] = file
+ scripts["[ckey(name)].js"] = file
+ SSassets.transport.register_asset("[ckey(name)].js", file)
/datum/browser/proc/set_content(ncontent)
content = ncontent
@@ -67,25 +62,21 @@
content += ncontent
/datum/browser/proc/get_header()
- var/key
- var/filename
- for (key in stylesheets)
- filename = "[ckey(key)].css"
- user << browse_rsc(stylesheets[key], filename)
- head_content += ""
+ var/datum/asset/simple/namespaced/common/common_asset = get_asset_datum(/datum/asset/simple/namespaced/common)
+ var/file
- for (key in scripts)
- filename = "[ckey(key)].js"
- user << browse_rsc(scripts[key], filename)
- head_content += ""
+ // If a client exists, but they have disabled fancy windowing, disable it!
+ if(user?.client?.prefs?.read_preference(/datum/preference/toggle/browser_style))
+ head_content += ""
+ for (file in stylesheets)
+ head_content += ""
- var/title_attributes = "class='uiTitle'"
- if (title_image)
- title_attributes = "class='uiTitle icon' style='background-image: url([title_image]);'"
- return {"
+ for (file in scripts)
+ head_content += ""
+
+ return {"
-
@@ -93,10 +84,10 @@
- [title ? "
[title]
[title_buttons]
" : ""]
+ [title ? "
[title]
" : ""]
"}
-
+//" This is here because else the rest of the file looks like a string in notepad++.
/datum/browser/proc/get_footer()
return {"
@@ -111,85 +102,35 @@
[get_footer()]
"}
-/datum/browser/proc/open(var/use_onclose = 1)
- if(isnull(window_id)) //null check because this can potentially nuke goonchat
+/datum/browser/proc/open(use_onclose = TRUE)
+ if(isnull(window_id)) //null check because this can potentially nuke goonchat
WARNING("Browser [title] tried to open with a null ID")
- to_chat(user, span_userdanger("The [title] browser you tried to open failed a sanity check! Please report this on github!"))
+ to_chat(user, span_userdanger("The [title] browser you tried to open failed a sanity check! Please report this on GitHub!"))
return
var/window_size = ""
if (width && height)
window_size = "size=[width]x[height];"
+ var/datum/asset/simple/namespaced/common/common_asset = get_asset_datum(/datum/asset/simple/namespaced/common)
+ common_asset.send(user)
+ if (stylesheets.len)
+ SSassets.transport.send_assets(user, stylesheets)
+ if (scripts.len)
+ SSassets.transport.send_assets(user, scripts)
user << browse(get_content(), "window=[window_id];[window_size][window_options]")
if (use_onclose)
- onclose(user, window_id, ref)
+ setup_onclose()
-// This will allow you to show an icon in the browse window
-// This is added to mob so that it can be used without a reference to the browser object
-// There is probably a better place for this...
-/mob/proc/browse_rsc_icon(icon, icon_state, dir = -1)
- /*
- var/icon/I
- if (dir >= 0)
- I = new /icon(icon, icon_state, dir)
- else
- I = new /icon(icon, icon_state)
- dir = "default"
-
- var/filename = "[ckey("[icon]_[icon_state]_[dir]")].png"
- src << browse_rsc(I, filename)
- return filename
- */
-
-
-// Registers the on-close verb for a browse window (client/verb/.windowclose)
-// this will be called when the close-button of a window is pressed.
-//
-// This is usually only needed for devices that regularly update the browse window,
-// e.g. canisters, timers, etc.
-//
-// windowid should be the specified window name
-// e.g. code is : user << browse(text, "window=fred")
-// then use : onclose(user, "fred")
-//
-// Optionally, specify the "ref" parameter as the controlled atom (usually src)
-// to pass a "close=1" parameter to the atom's Topic() proc for special handling.
-// Otherwise, the user mob's machine var will be reset directly.
-//
-/proc/onclose(mob/user, windowid, var/atom/ref=null)
- if(!user || !user.client) return
- var/param = "null"
- if(ref)
- param = "\ref[ref]"
-
- winset(user, windowid, "on-close=\".windowclose [param]\"")
-
- //to_world("OnClose [user]: [windowid] : ["on-close=\".windowclose [param]\""]")
-
-// the on-close client verb
-// called when a browser popup window is closed after registering with proc/onclose()
-// if a valid atom reference is supplied, call the atom's Topic() with "close=1"
-// otherwise, just reset the client mob's machine var.
-//
-
-/client/verb/windowclose(var/atomref as text)
- set hidden = 1 // hide this verb from the user's panel
- set name = ".windowclose" // no autocomplete on cmd line
-
- //to_world("windowclose: [atomref]")
- if(atomref!="null") // if passed a real atomref
- var/hsrc = locate(atomref) // find the reffed atom
- if(hsrc)
- //to_world("[src] Topic [href] [hsrc]")
- usr = src.mob
- src.Topic("close=1", list("close"="1"), hsrc) // this will direct to the atom's
- return // Topic() proc via client.Topic()
-
- // no atomref specified (or not found)
- // so just reset the user mob's machine var
- if(src && src.mob)
- //to_world("[src] was [src.mob.machine], setting to null")
- src.mob.unset_machine()
- return
+/datum/browser/proc/setup_onclose()
+ set waitfor = 0 //winexists sleeps, so we don't need to.
+ for (var/i in 1 to 10)
+ if (user?.client && winexists(user, window_id))
+ var/atom/send_ref
+ if(ref)
+ send_ref = ref.resolve()
+ if(!send_ref)
+ ref = null
+ onclose(user, window_id, send_ref)
+ break
/datum/browser/proc/close()
if(!isnull(window_id))//null check because this can potentially nuke goonchat
@@ -201,15 +142,15 @@
if (!User)
return
- var/output = {"
"}
@@ -227,11 +168,35 @@
opentime = 0
close()
-//designed as a drop in replacement for alert(); functions the same. (outside of needing User specified)
-/proc/tgalert(var/mob/User, Message, Title, Button1="Ok", Button2, Button3, StealFocus = 1, Timeout = 6000)
+/**
+ * **DEPRECATED: USE tgui_alert(...) INSTEAD**
+ *
+ * Designed as a drop in replacement for alert(); functions the same. (outside of needing User specified)
+ * Arguments:
+ * * User - The user to show the alert to.
+ * * Message - The textual body of the alert.
+ * * Title - The title of the alert's window.
+ * * Button1 - The first button option.
+ * * Button2 - The second button option.
+ * * Button3 - The third button option.
+ * * StealFocus - Boolean operator controlling if the alert will steal the user's window focus.
+ * * Timeout - The timeout of the window, after which no responses will be valid.
+ */
+/proc/tgalert(mob/User, Message, Title, Button1="Ok", Button2, Button3, StealFocus = TRUE, Timeout = 6000)
if (!User)
User = usr
- switch(askuser(User, Message, Title, Button1, Button2, Button3, StealFocus, Timeout))
+ if (!istype(User))
+ if (istype(User, /client))
+ var/client/client = User
+ User = client.mob
+ else
+ return
+
+ // Get user's response using a modal
+ var/datum/browser/modal/alert/A = new(User, Message, Title, Button1, Button2, Button3, StealFocus, Timeout)
+ A.open()
+ A.wait()
+ switch(A.selectedbutton)
if (1)
return Button1
if (2)
@@ -239,27 +204,13 @@
if (3)
return Button3
-//Same shit, but it returns the button number, could at some point support unlimited button amounts.
-/proc/askuser(var/mob/User,Message, Title, Button1="Ok", Button2, Button3, StealFocus = 1, Timeout = 6000)
- if (!istype(User))
- if (istype(User, /client/))
- var/client/C = User
- User = C.mob
- else
- return
- var/datum/browser/modal/alert/A = new(User, Message, Title, Button1, Button2, Button3, StealFocus, Timeout)
- A.open()
- A.wait()
- if (A.selectedbutton)
- return A.selectedbutton
-
/datum/browser/modal
var/opentime = 0
var/timeout
var/selectedbutton = 0
var/stealfocus
-/datum/browser/modal/New(nuser, nwindow_id, ntitle = 0, nwidth = 0, nheight = 0, var/atom/nref = null, StealFocus = 1, Timeout = 6000)
+/datum/browser/modal/New(nuser, nwindow_id, ntitle = 0, nwidth = 0, nheight = 0, atom/nref = null, StealFocus = 1, Timeout = 6000)
..()
stealfocus = StealFocus
if (!StealFocus)
@@ -271,8 +222,8 @@
.=..()
opentime = 0
-/datum/browser/modal/open()
- set waitfor = 0
+/datum/browser/modal/open(use_onclose)
+ set waitfor = FALSE
opentime = world.time
if (stealfocus)
@@ -304,12 +255,16 @@
if (!User)
return
- var/output = {"