tgui say update (#17273)

* tgui say update

* .

* also fix the tgui say limit

* handle batching

* max chunks

* enable~
This commit is contained in:
Kashargul
2025-03-06 22:47:56 +01:00
committed by GitHub
parent bb5c988555
commit 5d1a3923aa
11 changed files with 118 additions and 33 deletions
+2
View File
@@ -11,3 +11,5 @@
/// Simply removes the < and > characters, and limits the length of the message.
#define STRIP_HTML_SIMPLE(text, limit) (GLOB.angular_brackets.Replace(copytext(text, 1, limit), ""))
#define MAX_MESSAGE_CHUNKS 130
+24
View File
@@ -45,6 +45,8 @@
var/datum/tgui/parent_ui
/// Children of this UI
var/list/children = list()
/// Any partial packets that we have received from TGUI, waiting to be sent
var/partial_packets
/**
* public
@@ -349,6 +351,28 @@
// Pass act type messages to tgui_act
if(type && copytext(type, 1, 5) == "act/")
var/act_type = copytext(type, 5)
var/id = href_list["packetId"]
if(!isnull(id))
id = text2num(id)
var/total = text2num(href_list["totalPackets"])
if(id == 1)
if(total > MAX_MESSAGE_CHUNKS)
return
partial_packets = new /list(total)
partial_packets[id] = href_list["packet"]
if(id != total)
return
var/assembled_payload = ""
for(var/packet in partial_packets)
assembled_payload += packet
payload = json_decode(assembled_payload)
partial_packets = null
#ifdef TGUI_DEBUGGING
log_tgui(user, "Action: [act_type] [href_list["payload"]], Window: [window.id], Source: [src_object]")
#endif
+28 -4
View File
@@ -31,6 +31,8 @@
var/datum/tgui_window/window
/// Boolean for whether the tgui_say was opened by the user.
var/window_open
/// Any partial packets that we have received from TGUI, waiting to be sent
var/partial_packets
/** Creates the new input window to exist in the background. */
/datum/tgui_say/New(client/client, id)
@@ -64,14 +66,14 @@
/datum/tgui_say/proc/load()
window_open = FALSE
var/minimum_height = client?.prefs?.read_preference(/datum/preference/numeric/tgui_say_height) || 1
var/minimu_width = client?.prefs?.read_preference(/datum/preference/numeric/tgui_say_width) || 1
var/minimum_width = client?.prefs?.read_preference(/datum/preference/numeric/tgui_say_width) || 1
var/minimum_height = (client?.prefs?.read_preference(/datum/preference/numeric/tgui_say_height) || 1) * 20 + 10
winset(client, "tgui_say", "pos=410,400;size=360,30;is-visible=0;")
window.send_message("props", list(
lightMode = client?.prefs?.read_preference(/datum/preference/toggle/tgui_say_light),
minimumWidth = minimum_width,
minimumHeight = minimum_height,
minimumWidth = minimu_width,
maxLength = max_length,
))
@@ -106,7 +108,7 @@
* The equivalent of ui_act, this waits on messages from the window
* and delegates actions.
*/
/datum/tgui_say/proc/on_message(type, payload)
/datum/tgui_say/proc/on_message(type, payload, href_list)
if(type == "ready")
load()
return TRUE
@@ -128,6 +130,28 @@
start_typing(payload["channel"])
return TRUE
if(type == "entry" || type == "force")
var/id = href_list["packetId"]
if(!isnull(id))
id = text2num(id)
var/total = text2num(href_list["totalPackets"])
if(id == 1)
if(total > MAX_MESSAGE_CHUNKS)
return
partial_packets = new /list(total)
partial_packets[id] = href_list["packet"]
if(id != total)
return
var/assembled_payload = ""
for(var/packet in partial_packets)
assembled_payload += packet
payload = json_decode(assembled_payload)
partial_packets = null
handle_entry(type, payload)
return TRUE
if(type == "lenwarn")
+1 -1
View File
@@ -15,7 +15,7 @@
* * encode - Toggling this determines if input is filtered via html_encode. Setting this to FALSE gives raw input.
* * timeout - The timeout of the textbox, after which the modal will close and qdel itself. Set to zero for no timeout.
*/
/proc/tgui_input_text(mob/user, message = "", title = "Text Input", default, max_length = INFINITY, multiline = FALSE, encode = FALSE, timeout = 0, prevent_enter = FALSE)
/proc/tgui_input_text(mob/user, message = "", title = "Text Input", default, max_length = 130000, multiline = FALSE, encode = FALSE, timeout = 0, prevent_enter = FALSE) // 130k limit due to chunking limit... if we need longer that needs fixing
if (!user)
user = usr
if (!istype(user))
@@ -14,6 +14,7 @@ $border-color: rgba(140, 140, 140, 0.5) !default;
border-radius: 0.25em;
width: 3.75em;
text-align: right;
user-select: 'none';
}
.Ping__indicator {
+14 -4
View File
@@ -20,6 +20,8 @@ import { byondMessages } from './timers';
type ByondOpen = {
channel: Channel;
minimumWidth: number;
minimumHeight: number;
};
type ByondProps = {
@@ -287,8 +289,8 @@ export function TguiSay() {
function handleOpen(data: ByondOpen): void {
setTimeout(() => {
innerRef.current?.focus();
windowSet(WindowSize.Width, WindowSize.Small);
setSize(WindowSize.Width);
setSize(minimumHeight);
windowSet(minimumWidth, minimumHeight);
}, 1);
const { channel } = data;
@@ -339,7 +341,7 @@ export function TguiSay() {
} else {
newSize = WindowSize.Small;
}
newSize = clamp(newSize, minimumHeight * 20 + 10, WindowSize.Max);
newSize = clamp(newSize, minimumHeight, WindowSize.Max);
if (size !== newSize) {
setSize(newSize);
@@ -370,16 +372,24 @@ export function TguiSay() {
{buttonContent}
</button>
<textarea
spellCheck
autoCorrect="off"
className={`textarea textarea-${theme}`}
maxLength={maxLength}
onInput={handleInput}
onKeyDown={handleKeyDown}
ref={innerRef}
spellCheck={false}
rows={ROWS[size] || 1}
value={value}
/>
<button
key="escape"
className={`button button-${theme}`}
onClick={handleClose}
type="submit"
>
X
</button>
</div>
</>
);
+1 -1
View File
@@ -118,7 +118,7 @@
background-color: black;
display: grid;
font: 'tgfont';
grid-template-columns: 3.5rem 1fr;
grid-template-columns: 7rem 1fr 2rem;
inset: 2px;
overflow: hidden;
padding: 2px;
+20 -15
View File
@@ -33,6 +33,7 @@ export const COLORS = {
science: '#9b59b6',
engineering: '#f1c40f',
cargo: '#f39c12',
service: '#7cc46a',
centcom: '#00c100',
other: '#c38312',
},
@@ -66,24 +67,28 @@ export const COLORS = {
// Colors defined in CSS
export const CSS_COLORS = [
'black',
'white',
'red',
'orange',
'yellow',
'olive',
'green',
'teal',
'blue',
'violet',
'purple',
'pink',
'brown',
'grey',
'good',
'average',
'bad',
'black',
'blue',
'brown',
'darkgray',
'darkgreen',
'maroon',
'good',
'green',
'grey',
'label',
'olive',
'orange',
'pink',
'purple',
'red',
'teal',
'transparent',
'violet',
'white',
'yellow',
];
// VOREStation Edit Start
@@ -591,10 +591,10 @@ const rank2color = {
'Off-duty Explorer': 'white',
'Off-duty Worker': 'white',
// AI / Robot
AI: 'darkgrey',
Cyborg: 'darkgrey',
Robot: 'darkgrey',
Drone: 'darkgrey',
AI: 'maroon',
Cyborg: 'maroon',
Robot: 'maroon',
Drone: 'maroon',
// Clown / Mime
Clown: 'green',
Jester: 'green',
@@ -627,11 +627,11 @@ const rank2color = {
Security: 'red',
Combat: 'yellow',
Engineering: 'orange',
Gravekeeper: 'dark-grey',
Gravekeeper: 'maroon',
Lost: 'grey',
Protector: 'darkred',
Mechanist: 'darkred',
'Combat Medic': 'darkred',
Protector: 'maroon',
Mechanist: 'maroon',
'Combat Medic': 'maroon',
};
type rank_icon = { rank: string; color: string };
+18
View File
@@ -204,7 +204,25 @@
// JSON-encode the payload
if (message.payload !== null && message.payload !== undefined) {
message.payload = JSON.stringify(message.payload);
if(!Byond.TRIDENT && message.payload.length > 1024) {
var chunks = [];
for(var i = 0, charsLength = message.payload.length; i < charsLength; i += 1024) {
chunks.push(message.payload.substring(i, i + 1024))
}
for(var i = 0; i < chunks.length; i++) {
var to_send = chunks[i]
message = { type: type, packet: to_send, packetId: i + 1, totalPackets: chunks.length, tgui: 1, window_id: Byond.windowId };
Byond.topic(message);
}
return;
}
}
// Append an identifying header
assign(message, {
tgui: 1,
+1
View File
@@ -157,6 +157,7 @@ export const IconCutterTarget = new Juke.Target({
`icons/**/*.png.toml`,
`icons/**/*.dmi.toml`,
`cutter_templates/**/*.toml`,
"tgui/public/tgui.html",
cutter_path,
]
// Alright we're gonna search out any existing toml files and convert