mirror of
https://github.com/ParadiseSS13/Paradise.git
synced 2026-08-30 15:37:36 +01:00
TGUI say: Upgrades chat input with modern features (#23907)
* initial stuff (broken) * initial stuff (works) * fix most other things * fix thinking indicator * file name moment * contra review * better logs * snowball feedback * expanded drag handles * Update code/modules/tgui_input/say_modal/tgui_say_modal.dm Co-authored-by: Contrabang <91113370+Contrabang@users.noreply.github.com> * Update code/modules/tgui_input/say_modal/tgui_say_modal.dm Co-authored-by: Contrabang <91113370+Contrabang@users.noreply.github.com> * Drag handle * fix missing colours * TGUI rebuild (im clever) * Make msay useable by admins again (i hope) * fixed blacklist channel leaks due to lack of user eyes * clear old TGUIsay macros on keybind update * TGUI say tweaks * Update code/modules/tgui_input/say_modal/tgui_say_modal.dm * whisper is now a channel * remove placeholder, shorten width * tidies prefs, fix lightmode, refactor typing/thinking indicators * clarify more prefs * TG Typing Indicators and increace layer * modifiers? * makes the TGUI say macros serverside * add checks for muted stuff * dgamer review * fix talk and type issue * Update code/datums/keybindings/communication_keybinds.dm Co-authored-by: Luc <89928798+lewcc@users.noreply.github.com> * review and binary stuff * Removes force say from TGUI say * updated * Apply suggestions from code review Co-authored-by: Aylong <69762909+AyIong@users.noreply.github.com> * remove verb * le rebuild * better behaviour on illegal entries --------- Co-authored-by: Aylong <alexanderkitsa@gmail.com> Co-authored-by: Contrabang <91113370+Contrabang@users.noreply.github.com> Co-authored-by: GDN <Roanrichards1@Gmail.com> Co-authored-by: Luc <89928798+lewcc@users.noreply.github.com> Co-authored-by: Aylong <69762909+AyIong@users.noreply.github.com>
This commit is contained in:
co-authored by
Contrabang
Luc
Aylong
Aylong
GDN
parent
c120721cde
commit
3be2d5f8b6
@@ -660,6 +660,7 @@ GLOBAL_LIST_INIT(view_runtimes_verbs, list(
|
||||
GLOB.de_mentors += ckey
|
||||
deadmin()
|
||||
verbs += /client/proc/readmin
|
||||
update_active_keybindings()
|
||||
to_chat(src, "<span class='interface'>You are now a normal player.</span>")
|
||||
SSblackbox.record_feedback("tally", "admin_verb", 1, "De-admin") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
|
||||
@@ -749,6 +750,7 @@ GLOBAL_LIST_INIT(view_runtimes_verbs, list(
|
||||
|
||||
var/client/C = GLOB.directory[ckey]
|
||||
D.associate(C)
|
||||
update_active_keybindings()
|
||||
message_admins("[key_name_admin(usr)] re-adminned themselves.")
|
||||
log_admin("[key_name(usr)] re-adminned themselves.")
|
||||
GLOB.de_admins -= ckey
|
||||
|
||||
@@ -124,12 +124,15 @@
|
||||
/// The client's movement keybindings to directions, which work regardless of modifiers.
|
||||
var/list/movement_kb_dirs = list()
|
||||
|
||||
///A lazy list of atoms we've examined in the last RECENT_EXAMINE_MAX_WINDOW (default 2) seconds, so that we will call [/atom/proc/examine_more] instead of [/atom/proc/examine] on them when examining
|
||||
/// A lazy list of atoms we've examined in the last RECENT_EXAMINE_MAX_WINDOW (default 2) seconds, so that we will call [/atom/proc/examine_more] instead of [/atom/proc/examine] on them when examining
|
||||
var/list/recent_examines
|
||||
|
||||
/// When to next alert admins that mouse macro use was attempted
|
||||
var/next_mouse_macro_warning
|
||||
|
||||
/// Assigned say modal of the client
|
||||
var/datum/tgui_say/tgui_say
|
||||
|
||||
/client/vv_edit_var(var_name, var_value)
|
||||
switch(var_name)
|
||||
// I know we will never be in a world where admins are editing client vars to let people bypass TOS
|
||||
|
||||
@@ -254,7 +254,10 @@
|
||||
///////////
|
||||
/client/New(TopicData)
|
||||
var/tdata = TopicData //save this for later use
|
||||
tgui_panel = new(src)
|
||||
|
||||
tgui_panel = new(src, "browseroutput")
|
||||
tgui_say = new(src, "tgui_say")
|
||||
|
||||
TopicData = null //Prevent calls to client.Topic from connect
|
||||
|
||||
if(connection != "seeker") //Invalid connection type.
|
||||
@@ -392,6 +395,9 @@
|
||||
// Initialize tgui panel
|
||||
tgui_panel.initialize()
|
||||
|
||||
// Initialize tgui say
|
||||
tgui_say.initialize()
|
||||
|
||||
check_ip_intel()
|
||||
send_resources()
|
||||
SSchangelog.UpdatePlayerChangelogButton(src)
|
||||
@@ -955,31 +961,6 @@
|
||||
|
||||
#undef SSD_WARNING_TIMER
|
||||
|
||||
|
||||
//
|
||||
/client/verb/resend_ui_resources()
|
||||
set name = "Reload UI Resources"
|
||||
set desc = "Reload your UI assets if they are not working"
|
||||
set category = "Special Verbs"
|
||||
|
||||
if(last_ui_resource_send > world.time)
|
||||
to_chat(usr, "<span class='warning'>You requested your UI resource files too quickly. Please try again in [(last_ui_resource_send - world.time)/10] seconds.</span>")
|
||||
return
|
||||
|
||||
var/choice = alert(usr, "This will reload your TGUI resources. If you have any open UIs, they will be closed. Are you sure?", "Resource Reloading", "Yes", "No")
|
||||
if(choice == "Yes")
|
||||
// 600 deciseconds = 1 minute
|
||||
last_ui_resource_send = world.time + 60 SECONDS
|
||||
|
||||
// Close their open UIs
|
||||
SStgui.close_user_uis(usr)
|
||||
|
||||
// Clear the user's cache so they get resent.
|
||||
// This is not fully clearing their BYOND cache, just their assets sent from the server this round
|
||||
sent_assets = list()
|
||||
to_chat(usr, "<span class='notice'>UI resource files resent successfully. If you are still having issues, please try manually clearing your BYOND cache. <b>This can be achieved by opening your BYOND launcher, pressing the cog in the top right, selecting preferences, going to the Games tab, and pressing 'Clear Cache'.</b></span>")
|
||||
|
||||
|
||||
/**
|
||||
* Retrieves the BYOND accounts data from the BYOND servers
|
||||
*
|
||||
|
||||
@@ -946,6 +946,10 @@
|
||||
if("input_lists")
|
||||
toggles2 ^= PREFTOGGLE_2_DISABLE_TGUI_LISTS
|
||||
|
||||
if("tgui_say_light_mode")
|
||||
toggles2 ^= PREFTOGGLE_2_ENABLE_TGUI_SAY_LIGHT_MODE
|
||||
user?.client?.tgui_say?.load()
|
||||
|
||||
if("ghost_att_anim")
|
||||
toggles2 ^= PREFTOGGLE_2_ITEMATTACK
|
||||
|
||||
|
||||
@@ -439,7 +439,7 @@ GLOBAL_LIST_INIT(special_role_times, list( //minimum age (in days) for accounts
|
||||
dat += "<h2>Interface Settings</h2>"
|
||||
dat += "<b>Set screentip mode:</b> <a href='?_src_=prefs;preference=screentip_mode'>[(screentip_mode == 0) ? "Disabled" : "[screentip_mode]px"]</a><br>"
|
||||
dat += "<b>Screentip color:</b> <span style='border: 1px solid #161616; background-color: [screentip_color];'> </span> <a href='?_src_=prefs;preference=screentip_color'><b>Change</b></a><br>"
|
||||
dat += "<b>Thought Bubble:</b> <a href='?_src_=prefs;preference=thought_bubble'>[(toggles2 & PREFTOGGLE_2_THOUGHT_BUBBLE) ? "Yes" : "No"]</a><br>"
|
||||
dat += "<b>Thought Bubble when pointing:</b> <a href='?_src_=prefs;preference=thought_bubble'>[(toggles2 & PREFTOGGLE_2_THOUGHT_BUBBLE) ? "Yes" : "No"]</a><br>"
|
||||
dat += "<b>Custom UI settings:</b><br>"
|
||||
dat += " - <b>Alpha (transparency):</b> <a href='?_src_=prefs;preference=UIalpha'><b>[UI_style_alpha]</b></a><br>"
|
||||
dat += " - <b>Color:</b> <a href='?_src_=prefs;preference=UIcolor'><b>[UI_style_color]</b></a> <span style='border: 1px solid #161616; background-color: [UI_style_color];'> </span><br>"
|
||||
@@ -447,6 +447,7 @@ GLOBAL_LIST_INIT(special_role_times, list( //minimum age (in days) for accounts
|
||||
dat += "<b>TGUI settings:</b><br>"
|
||||
dat += "<b> - Fancy TGUI:</b> <a href='?_src_=prefs;preference=tgui'>[(toggles2 & PREFTOGGLE_2_FANCYUI) ? "Yes" : "No"]</a><br>"
|
||||
dat += "<b> - Input Lists:</b> <a href='?_src_=prefs;preference=input_lists'>[(toggles2 & PREFTOGGLE_2_DISABLE_TGUI_LISTS) ? "Default" : "TGUI"]</a><br>"
|
||||
dat += "<b> - TGUI Say Theme:</b> <a href='?_src_=prefs;preference=tgui_say_light_mode'>[(toggles2 & PREFTOGGLE_2_ENABLE_TGUI_SAY_LIGHT_MODE) ? "Light" : "Dark"]</a><br>"
|
||||
dat += "</td></tr></table>"
|
||||
|
||||
if(TAB_ANTAG) // Antagonist's Preferences
|
||||
|
||||
@@ -254,18 +254,6 @@
|
||||
prefs.current_tab = 1
|
||||
prefs.ShowChoices(usr)
|
||||
|
||||
/client/verb/toggle_popup_limiter()
|
||||
set name = "Toggle Text Popup Limiter"
|
||||
set category = "Preferences"
|
||||
set desc = "Will let you limit the text input popups to one at a time."
|
||||
prefs.toggles ^= PREFTOGGLE_TYPING_ONCE
|
||||
prefs.save_preferences(src)
|
||||
if(prefs.toggles & PREFTOGGLE_TYPING_ONCE)
|
||||
to_chat(usr, "<span class='notice'>You have enabled text popup limiting.")
|
||||
else
|
||||
to_chat(usr, "<span class='notice'>You have disabled text popup limiting.")
|
||||
return
|
||||
|
||||
/client/verb/toggle_ghost_pda()
|
||||
set name = "Show/Hide GhostPDA"
|
||||
set category = "Preferences"
|
||||
|
||||
@@ -1031,6 +1031,7 @@ It'll return null if the organ doesn't correspond, so include null checks when u
|
||||
return
|
||||
|
||||
/datum/species/proc/spec_attacked_by(obj/item/I, mob/living/user, obj/item/organ/external/affecting, intent, mob/living/carbon/human/H)
|
||||
return
|
||||
|
||||
/proc/get_random_species(species_name = FALSE) // Returns a random non black-listed or hazardous species, either as a string or datum
|
||||
var/static/list/random_species = list()
|
||||
|
||||
@@ -1611,6 +1611,8 @@ GLOBAL_LIST_INIT(holy_areas, typecacheof(list(
|
||||
. = stat
|
||||
stat = new_stat
|
||||
SEND_SIGNAL(src, COMSIG_MOB_STATCHANGE, new_stat, .)
|
||||
if(.)
|
||||
set_typing_indicator(FALSE)
|
||||
|
||||
///Makes a call in the context of a different usr. Use sparingly
|
||||
/world/proc/invoke_callback_with_usr(mob/user_mob, datum/callback/invoked_callback, ...)
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
/mob/Logout()
|
||||
set_typing_indicator(FALSE)
|
||||
SStgui.on_logout(src) // Cleanup any TGUIs the user has open
|
||||
unset_machine()
|
||||
GLOB.player_list -= src
|
||||
|
||||
@@ -227,10 +227,10 @@
|
||||
var/blood_state = BLOOD_STATE_NOT_BLOODY
|
||||
/// Assoc list for tracking how "bloody" a mobs feet are, used for creating bloody foot/shoeprints on turfs when moving
|
||||
var/list/bloody_feet = list(BLOOD_STATE_HUMAN = 0, BLOOD_STATE_XENO = 0, BLOOD_STATE_NOT_BLOODY = 0, BLOOD_BASE_ALPHA = BLOODY_FOOTPRINT_BASE_ALPHA)
|
||||
/// set when typing in an input window instead of chatline, this var could probably be removed soon enough
|
||||
var/hud_typing = 0
|
||||
/// Affects if you have a typing indicator
|
||||
var/typing
|
||||
/// Affects if you have a thinking indicator
|
||||
var/thinking
|
||||
/// Last thing we typed in to the typing indicator, probably does not need to exist
|
||||
var/last_typed
|
||||
/// Last time we typed something in to the typing popup
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
#define TYPING_INDICATOR_LIFETIME 30 * 10 //grace period after which typing indicator disappears regardless of text in chatbar
|
||||
|
||||
GLOBAL_LIST_EMPTY(typing_indicator)
|
||||
GLOBAL_LIST_EMPTY(thinking_indicator)
|
||||
|
||||
/**
|
||||
* Toggles the floating chat bubble above a players head.
|
||||
@@ -10,9 +9,8 @@ GLOBAL_LIST_EMPTY(typing_indicator)
|
||||
* * me - Is the bubble being caused by the 'me' emote command
|
||||
*/
|
||||
/mob/proc/set_typing_indicator(state, me)
|
||||
|
||||
if(!GLOB.typing_indicator[bubble_icon])
|
||||
GLOB.typing_indicator[bubble_icon] = image('icons/mob/talk.dmi', null, "[bubble_icon]typing", FLY_LAYER)
|
||||
GLOB.typing_indicator[bubble_icon] = image('icons/mob/talk.dmi', null, "[bubble_icon]_typing", ABOVE_HUD_LAYER)
|
||||
var/image/I = GLOB.typing_indicator[bubble_icon]
|
||||
I.appearance_flags = APPEARANCE_UI_IGNORE_ALPHA
|
||||
|
||||
@@ -20,91 +18,93 @@ GLOBAL_LIST_EMPTY(typing_indicator)
|
||||
var/mob/living/carbon/human/H = src
|
||||
if(HAS_TRAIT(H, TRAIT_MUTE))
|
||||
overlays -= GLOB.typing_indicator[bubble_icon]
|
||||
return
|
||||
typing = FALSE
|
||||
return FALSE
|
||||
|
||||
if(client)
|
||||
if(stat != CONSCIOUS || is_muzzled() || (client.prefs.toggles & PREFTOGGLE_SHOW_TYPING) || (me && (client.prefs.toggles2 & PREFTOGGLE_2_EMOTE_BUBBLE)))
|
||||
overlays -= GLOB.typing_indicator[bubble_icon]
|
||||
else
|
||||
if(state)
|
||||
if(!typing)
|
||||
overlays += GLOB.typing_indicator[bubble_icon]
|
||||
typing = TRUE
|
||||
else
|
||||
if(typing)
|
||||
overlays -= GLOB.typing_indicator[bubble_icon]
|
||||
typing = FALSE
|
||||
return state
|
||||
if(!client)
|
||||
return FALSE
|
||||
|
||||
if(stat != CONSCIOUS || is_muzzled() || (client.prefs.toggles & PREFTOGGLE_SHOW_TYPING))
|
||||
overlays -= GLOB.typing_indicator[bubble_icon]
|
||||
typing = FALSE
|
||||
return FALSE
|
||||
|
||||
if(state && !typing)
|
||||
overlays += GLOB.typing_indicator[bubble_icon]
|
||||
typing = TRUE
|
||||
|
||||
if(!state && typing)
|
||||
overlays -= GLOB.typing_indicator[bubble_icon]
|
||||
typing = FALSE
|
||||
|
||||
return state
|
||||
|
||||
/**
|
||||
* Toggles the floating thought bubble above a players head.
|
||||
*
|
||||
* Arguments:
|
||||
* * state - Should a thought bubble be shown or hidden
|
||||
*/
|
||||
/mob/proc/set_thinking_indicator(state)
|
||||
if(!GLOB.thinking_indicator[bubble_icon])
|
||||
GLOB.thinking_indicator[bubble_icon] = image('icons/mob/talk.dmi', null, "[bubble_icon]_thinking", ABOVE_HUD_LAYER)
|
||||
var/image/I = GLOB.thinking_indicator[bubble_icon]
|
||||
I.appearance_flags = APPEARANCE_UI_IGNORE_ALPHA
|
||||
|
||||
if(!client && !isliving(src))
|
||||
return FALSE
|
||||
|
||||
if(stat != CONSCIOUS || (client.prefs.toggles & PREFTOGGLE_SHOW_TYPING))
|
||||
overlays -= GLOB.thinking_indicator[bubble_icon]
|
||||
thinking = FALSE
|
||||
return FALSE
|
||||
|
||||
if(!state && thinking)
|
||||
overlays -= GLOB.thinking_indicator[bubble_icon]
|
||||
thinking = FALSE
|
||||
|
||||
if(state && !thinking)
|
||||
overlays += GLOB.thinking_indicator[bubble_icon]
|
||||
thinking = TRUE
|
||||
|
||||
return state
|
||||
|
||||
/mob/verb/say_wrapper()
|
||||
set name = ".Say"
|
||||
set hidden = 1
|
||||
set hidden = TRUE
|
||||
|
||||
set_typing_indicator(TRUE)
|
||||
hud_typing = 1
|
||||
typing = TRUE
|
||||
var/message = typing_input(src, "", "say (text)")
|
||||
hud_typing = 0
|
||||
typing = FALSE
|
||||
set_typing_indicator(FALSE)
|
||||
if(message)
|
||||
say_verb(message)
|
||||
|
||||
/mob/verb/me_wrapper()
|
||||
set name = ".Me"
|
||||
set hidden = 1
|
||||
|
||||
set hidden = TRUE
|
||||
|
||||
set_typing_indicator(TRUE, TRUE)
|
||||
hud_typing = 1
|
||||
typing = TRUE
|
||||
var/message = typing_input(src, "", "me (text)")
|
||||
hud_typing = 0
|
||||
typing = FALSE
|
||||
set_typing_indicator(FALSE)
|
||||
if(message)
|
||||
me_verb(message)
|
||||
|
||||
/mob/proc/handle_typing_indicator()
|
||||
if(client)
|
||||
if(!(client.prefs.toggles & PREFTOGGLE_SHOW_TYPING) && !hud_typing)
|
||||
var/temp = winget(client, "input", "text")
|
||||
|
||||
if(temp != last_typed)
|
||||
last_typed = temp
|
||||
last_typed_time = world.time
|
||||
|
||||
if(world.time > last_typed_time + TYPING_INDICATOR_LIFETIME)
|
||||
set_typing_indicator(FALSE)
|
||||
return
|
||||
if(length(temp) > 5 && findtext(temp, "Say \"", 1, 7))
|
||||
set_typing_indicator(TRUE)
|
||||
else if(length(temp) > 3 && findtext(temp, "Me ", 1, 5))
|
||||
set_typing_indicator(TRUE, TRUE)
|
||||
|
||||
else
|
||||
set_typing_indicator(FALSE)
|
||||
|
||||
/client/verb/typing_indicator()
|
||||
set name = "Show/Hide Typing Indicator"
|
||||
set category = "Preferences"
|
||||
set desc = "Toggles showing an indicator when you are typing a message."
|
||||
set desc = "Toggles showing a typing/thought indicator when you have TGUIsay open."
|
||||
prefs.toggles ^= PREFTOGGLE_SHOW_TYPING
|
||||
prefs.save_preferences(src)
|
||||
to_chat(src, "You will [(prefs.toggles & PREFTOGGLE_SHOW_TYPING) ? "no longer" : "now"] display a typing indicator.")
|
||||
to_chat(src, "You will [(prefs.toggles & PREFTOGGLE_SHOW_TYPING) ? "no longer" : "now"] display a typing/thought indicator when you have TGUIsay open.")
|
||||
|
||||
// Clear out any existing typing indicator.
|
||||
if(prefs.toggles & PREFTOGGLE_SHOW_TYPING)
|
||||
if(istype(mob))
|
||||
mob.set_typing_indicator(FALSE)
|
||||
mob.set_thinking_indicator(FALSE)
|
||||
|
||||
SSblackbox.record_feedback("tally", "toggle_verbs", 1, "Toggle Typing Indicator (Speech)") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
|
||||
|
||||
/client/verb/emote_indicator()
|
||||
set name = "Show/Hide Emote Typing Indicator"
|
||||
set category = "Preferences"
|
||||
set desc = "Toggles showing an indicator when you are typing an emote."
|
||||
prefs.toggles2 ^= PREFTOGGLE_2_EMOTE_BUBBLE
|
||||
prefs.save_preferences(src)
|
||||
to_chat(src, "You will [(prefs.toggles2 & PREFTOGGLE_2_EMOTE_BUBBLE) ? "no longer" : "now"] display a typing indicator for emotes.")
|
||||
|
||||
SSblackbox.record_feedback("tally", "toggle_verbs", 1, "Toggle Typing Indicator (Emote)") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
|
||||
#undef TYPING_INDICATOR_LIFETIME
|
||||
|
||||
@@ -87,6 +87,7 @@
|
||||
window.acquire_lock(src)
|
||||
if(!window.is_ready())
|
||||
window.initialize(
|
||||
strict_mode = TRUE,
|
||||
fancy = (user.client.prefs.toggles2 & PREFTOGGLE_2_FANCYUI),
|
||||
assets = list(
|
||||
get_asset_datum(/datum/asset/simple/tgui),
|
||||
|
||||
@@ -13,9 +13,12 @@
|
||||
var/broken = FALSE
|
||||
var/initialized_at
|
||||
|
||||
/datum/tgui_panel/New(client/client)
|
||||
/datum/tgui_panel/New(client/client, id)
|
||||
if(!id)
|
||||
qdel(src)
|
||||
CRASH("New TGUI panel created for [client] but no id supplied, deleting.")
|
||||
src.client = client
|
||||
window = new(client, "browseroutput")
|
||||
window = new(client, id)
|
||||
window.subscribe(src, PROC_REF(on_message))
|
||||
|
||||
/datum/tgui_panel/Del()
|
||||
@@ -42,9 +45,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))
|
||||
request_telemetry()
|
||||
addtimer(CALLBACK(src, PROC_REF(on_initialize_timed_out)), 5 SECONDS)
|
||||
|
||||
@@ -34,3 +34,11 @@
|
||||
// Force show the panel to see if there are any errors
|
||||
winset(src, "output", "is-disabled=1&is-visible=0")
|
||||
winset(src, "browseroutput", "is-disabled=0;is-visible=1")
|
||||
|
||||
/client/verb/refresh_tgui()
|
||||
set name = "Refresh TGUI"
|
||||
set category = "Special Verbs"
|
||||
|
||||
for(var/window_id in tgui_windows)
|
||||
var/datum/tgui_window/window = tgui_windows[window_id]
|
||||
window.reinitialize()
|
||||
|
||||
@@ -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 = "",
|
||||
@@ -77,6 +82,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)
|
||||
@@ -94,14 +100,14 @@
|
||||
html = replacetextEx(html, "<!-- tgui:assets -->\n", inline_assets_str)
|
||||
// Inject inline HTML
|
||||
if(inline_html)
|
||||
html = replacetextEx(html, "<!-- tgui:inline-html -->", inline_html)
|
||||
html = replacetextEx(html, "<!-- tgui:inline-html -->", isfile(inline_html) ? file2text(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[isfile(inline_js) ? file2text(inline_js) : inline_js]\n</script>"
|
||||
html = replacetextEx(html, "<!-- tgui:inline-js -->", inline_js)
|
||||
// Inject inline CSS
|
||||
if(inline_css)
|
||||
inline_css = "<style>\n[inline_css]\n</style>"
|
||||
inline_css = "<style>\n[isfile(inline_css) ? file2text(inline_css) : inline_css]\n</style>"
|
||||
html = replacetextEx(html, "<!-- tgui:inline-css -->", inline_css)
|
||||
// Open the window
|
||||
client << browse(html, "window=[id];[options]")
|
||||
@@ -111,6 +117,23 @@
|
||||
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)
|
||||
// Resend assets
|
||||
for(var/datum/asset/asset in sent_assets)
|
||||
send_asset(asset)
|
||||
|
||||
/**
|
||||
* public
|
||||
*
|
||||
@@ -287,6 +310,18 @@
|
||||
: "[id].browser:update")
|
||||
message_queue = null
|
||||
|
||||
/**
|
||||
* public
|
||||
*
|
||||
* Replaces the inline HTML content.
|
||||
*
|
||||
* required inline_html string HTML to inject
|
||||
*/
|
||||
/datum/tgui_window/proc/replace_html(inline_html = "")
|
||||
client << output(url_encode(inline_html), is_browser \
|
||||
? "[id]:replaceHtml" \
|
||||
: "[id].browser:replaceHtml")
|
||||
|
||||
/**
|
||||
* private
|
||||
*
|
||||
@@ -329,15 +364,6 @@
|
||||
if("openLink")
|
||||
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)
|
||||
// Resend the assets
|
||||
for(var/asset in sent_assets)
|
||||
send_asset(asset)
|
||||
reinitialize()
|
||||
if("chat/resend")
|
||||
SSchat.handle_resend(client, payload)
|
||||
|
||||
@@ -0,0 +1,123 @@
|
||||
/**
|
||||
* Creates a JSON encoded message to open TGUI say modals properly.
|
||||
*
|
||||
* Arguments:
|
||||
* channel - The channel to open the modal in.
|
||||
* Returns:
|
||||
* string - A JSON encoded message to open the modal.
|
||||
*/
|
||||
/client/proc/tgui_say_create_open_command(channel)
|
||||
var/message = TGUI_CREATE_MESSAGE("open", list(
|
||||
channel = channel,
|
||||
))
|
||||
return "\".output tgui_say.browser:update [message]\""
|
||||
|
||||
/**
|
||||
* The tgui say modal. This initializes an input window which hides until
|
||||
* the user presses one of the speech hotkeys. Once something is entered, it will
|
||||
* delegate the speech to the proper channel.
|
||||
*/
|
||||
/datum/tgui_say
|
||||
/// The user who opened the window
|
||||
var/client/client
|
||||
/// The modal window
|
||||
var/datum/tgui_window/window
|
||||
/// Boolean for whether the tgui_say was opened by the user.
|
||||
var/window_open
|
||||
|
||||
/** Creates the new input window to exist in the background. */
|
||||
/datum/tgui_say/New(client/client, id)
|
||||
src.client = client
|
||||
window = new(client, id)
|
||||
winset(client, "tgui_say", "size=1,1;is-visible=0;")
|
||||
window.subscribe(src, PROC_REF(on_message))
|
||||
window.is_browser = TRUE
|
||||
|
||||
/**
|
||||
* After a brief period, injects the scripts into
|
||||
* the window to listen for open commands.
|
||||
*/
|
||||
/datum/tgui_say/proc/initialize()
|
||||
set waitfor = FALSE
|
||||
// Sleep to defer initialization to after client constructor
|
||||
sleep(3)
|
||||
window.initialize(
|
||||
strict_mode = TRUE,
|
||||
fancy = TRUE,
|
||||
inline_css = file("tgui/public/tgui-say.bundle.css"),
|
||||
inline_js = file("tgui/public/tgui-say.bundle.js"),
|
||||
);
|
||||
|
||||
/**
|
||||
* Ensures nothing funny is going on window load.
|
||||
* Minimizes the window, sets max length, closes all
|
||||
* typing and thinking indicators. This is triggered
|
||||
* as soon as the window sends the "ready" message.
|
||||
*/
|
||||
/datum/tgui_say/proc/load()
|
||||
window_open = FALSE
|
||||
winset(client, "tgui_say", "pos=848,500;size=275,30;is-visible=0;")
|
||||
window.send_message("props", list(
|
||||
"lightMode" = (client.prefs.toggles2 & PREFTOGGLE_2_ENABLE_TGUI_SAY_LIGHT_MODE),
|
||||
"maxLength" = MAX_MESSAGE_LEN,
|
||||
))
|
||||
stop_thinking()
|
||||
return TRUE
|
||||
|
||||
/**
|
||||
* Sets the window as "opened" server side, though it is already
|
||||
* visible to the user. We do this to set local vars &
|
||||
* start typing (if enabled and in an IC channel).
|
||||
*
|
||||
* Arguments:
|
||||
* payload - A list containing the channel the window was opened in.
|
||||
*/
|
||||
/datum/tgui_say/proc/open(payload)
|
||||
if(!payload?["channel"])
|
||||
CRASH("No channel provided to an open TGUI-Say")
|
||||
window_open = TRUE
|
||||
switch(payload["channel"])
|
||||
if(ME_CHANNEL, RADIO_CHANNEL, SAY_CHANNEL, WHISPER_CHANNEL)
|
||||
start_thinking()
|
||||
return TRUE
|
||||
|
||||
/**
|
||||
* Closes the window serverside. Closes any open chat bubbles
|
||||
* regardless of preference.
|
||||
*/
|
||||
/datum/tgui_say/proc/close()
|
||||
window_open = FALSE
|
||||
stop_thinking()
|
||||
stop_typing()
|
||||
|
||||
/**
|
||||
* The equivalent of ui_act, this waits on messages from the window
|
||||
* and delegates actions.
|
||||
*/
|
||||
/datum/tgui_say/proc/on_message(type, payload)
|
||||
switch(type)
|
||||
if("ready")
|
||||
load()
|
||||
return TRUE
|
||||
if("open")
|
||||
open(payload)
|
||||
return TRUE
|
||||
if("close")
|
||||
close()
|
||||
return TRUE
|
||||
if("thinking")
|
||||
if(payload["visible"] == TRUE)
|
||||
start_thinking()
|
||||
return TRUE
|
||||
if(payload["visible"] == FALSE)
|
||||
stop_thinking()
|
||||
return TRUE
|
||||
return FALSE
|
||||
if("typing")
|
||||
start_typing(payload["isMeChannel"])
|
||||
return TRUE
|
||||
if("entry")
|
||||
handle_entry(payload)
|
||||
return TRUE
|
||||
|
||||
return FALSE
|
||||
@@ -0,0 +1,61 @@
|
||||
/**
|
||||
* Delegates the speech to the proper channel.
|
||||
*
|
||||
* Arguments:
|
||||
* entry - the text to broadcast
|
||||
* channel - the channel to broadcast in
|
||||
* Returns:
|
||||
* boolean - on success or failure
|
||||
*/
|
||||
/datum/tgui_say/proc/delegate_speech(entry, channel)
|
||||
switch(channel)
|
||||
if(SAY_CHANNEL)
|
||||
client.mob.say_verb(entry)
|
||||
return TRUE
|
||||
if(RADIO_CHANNEL)
|
||||
client.mob.say_verb((isliving(client.mob) ? ";" : "") + entry)
|
||||
return TRUE
|
||||
if(WHISPER_CHANNEL)
|
||||
client.mob.whisper(entry)
|
||||
return TRUE
|
||||
if(ME_CHANNEL)
|
||||
client.mob.me_verb(entry)
|
||||
return TRUE
|
||||
if(OOC_CHANNEL)
|
||||
client.ooc(entry)
|
||||
return TRUE
|
||||
if(LOOC_CHANNEL)
|
||||
client.looc(entry)
|
||||
return TRUE
|
||||
if(ADMIN_CHANNEL)
|
||||
client.cmd_admin_say(entry)
|
||||
return TRUE
|
||||
if(MENTOR_CHANNEL)
|
||||
client.cmd_mentor_say(entry)
|
||||
return TRUE
|
||||
if(DSAY_CHANNEL)
|
||||
client.dsay(entry)
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/**
|
||||
* Handles text entry and forced speech.
|
||||
*
|
||||
* Arguments:
|
||||
* payload - a string list containing entry & channel
|
||||
* Returns:
|
||||
* boolean - success or failure
|
||||
*/
|
||||
/datum/tgui_say/proc/handle_entry(payload)
|
||||
if(!payload?["channel"] || !payload["entry"])
|
||||
var/hacker_man_ckey = usr.client.ckey
|
||||
qdel(usr.client)
|
||||
message_admins("[hacker_man_ckey] was kicked for attemping to send a null message to TGUI-say.")
|
||||
CRASH("[hacker_man_ckey] entered in a null payload to the chat window.")
|
||||
if(length(payload["entry"]) > MAX_MESSAGE_LEN)
|
||||
var/hacker_man_ckey = usr.client.ckey
|
||||
qdel(usr.client)
|
||||
message_admins("[hacker_man_ckey] was kicked for attemping to bypass TGUI-say character limits.")
|
||||
CRASH("[hacker_man_ckey] has entered more characters than allowed into a TGUI-Say.")
|
||||
delegate_speech(payload["entry"], payload["channel"])
|
||||
return TRUE
|
||||
@@ -0,0 +1,41 @@
|
||||
/** Sets the mob as "thinking" - with indicator */
|
||||
/datum/tgui_say/proc/start_thinking()
|
||||
if(!client?.mob || !window_open)
|
||||
return FALSE
|
||||
/// Special exemptions
|
||||
if(isabductor(client.mob))
|
||||
return FALSE
|
||||
client.mob.set_thinking_indicator(TRUE)
|
||||
addtimer(CALLBACK(src, PROC_REF(stop_thinking)), 5 SECONDS, TIMER_UNIQUE | TIMER_OVERRIDE | TIMER_STOPPABLE)
|
||||
|
||||
/** Removes typing/thinking indicators and flags the mob as not thinking */
|
||||
/datum/tgui_say/proc/stop_thinking()
|
||||
if(!client?.mob)
|
||||
return FALSE
|
||||
client.mob.set_thinking_indicator(FALSE)
|
||||
|
||||
/**
|
||||
* Handles the user typing. After a brief period of inactivity,
|
||||
* signals the client mob to revert to the "thinking" icon.
|
||||
*/
|
||||
/datum/tgui_say/proc/start_typing(me = FALSE)
|
||||
if(!client?.mob)
|
||||
return FALSE
|
||||
client.mob.set_typing_indicator(FALSE)
|
||||
client.mob.set_thinking_indicator(FALSE)
|
||||
if(!window_open)
|
||||
return FALSE
|
||||
client.mob.set_typing_indicator(TRUE, me)
|
||||
addtimer(CALLBACK(src, PROC_REF(stop_typing)), 5 SECONDS, TIMER_UNIQUE | TIMER_OVERRIDE | TIMER_STOPPABLE)
|
||||
|
||||
/**
|
||||
* Callback to remove the typing indicator after a brief period of inactivity.
|
||||
* If the user was typing IC, the thinking indicator is shown.
|
||||
*/
|
||||
/datum/tgui_say/proc/stop_typing()
|
||||
if(!client?.mob)
|
||||
return FALSE
|
||||
client.mob.set_typing_indicator(FALSE)
|
||||
if(!window_open)
|
||||
return FALSE
|
||||
client.mob.set_thinking_indicator(TRUE)
|
||||
Reference in New Issue
Block a user