actual tgui code
This commit is contained in:
@@ -130,6 +130,13 @@
|
||||
*/
|
||||
/client/var/list/tgui_windows = list()
|
||||
|
||||
/**
|
||||
* global
|
||||
*
|
||||
* TRUE if cache was reloaded by tgui dev server at least once.
|
||||
*/
|
||||
/client/var/tgui_cache_reloaded = FALSE
|
||||
|
||||
/**
|
||||
* public
|
||||
*
|
||||
@@ -159,16 +166,29 @@
|
||||
/**
|
||||
* Middleware for /client/Topic.
|
||||
*
|
||||
* return bool Whether the topic is passed (TRUE), or cancelled (FALSE).
|
||||
* return bool If TRUE, prevents propagation of the topic call.
|
||||
*/
|
||||
/proc/tgui_Topic(href_list)
|
||||
// Skip non-tgui topics
|
||||
if(!href_list["tgui"])
|
||||
return TRUE
|
||||
return FALSE
|
||||
var/type = href_list["type"]
|
||||
// Unconditionally collect tgui logs
|
||||
if(type == "log")
|
||||
log_tgui(usr, href_list["message"])
|
||||
// Reload all tgui windows
|
||||
if(type == "cacheReloaded")
|
||||
if(!check_rights(R_ADMIN) || usr.client.tgui_cache_reloaded)
|
||||
return TRUE
|
||||
// Mark as reloaded
|
||||
usr.client.tgui_cache_reloaded = TRUE
|
||||
// Notify windows
|
||||
var/list/windows = usr.client.tgui_windows
|
||||
for(var/window_id in windows)
|
||||
var/datum/tgui_window/window = windows[window_id]
|
||||
if (window.status == TGUI_WINDOW_READY)
|
||||
window.on_message(type, null, href_list)
|
||||
return TRUE
|
||||
// Locate window
|
||||
var/window_id = href_list["window_id"]
|
||||
var/datum/tgui_window/window
|
||||
@@ -177,7 +197,7 @@
|
||||
if(!window)
|
||||
log_tgui(usr, "Error: Couldn't find the window datum, force closing.")
|
||||
SStgui.force_close_window(usr, window_id)
|
||||
return FALSE
|
||||
return TRUE
|
||||
// Decode payload
|
||||
var/payload
|
||||
if(href_list["payload"])
|
||||
@@ -185,4 +205,4 @@
|
||||
// Pass message to window
|
||||
if(window)
|
||||
window.on_message(type, payload, href_list)
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
GLOBAL_DATUM_INIT(debug_state, /datum/ui_state/debug_state, new)
|
||||
|
||||
/datum/ui_state/debug_state/can_use_topic(src_object, mob/user)
|
||||
if(check_rights_for(user.client, R_DEBUG))
|
||||
return UI_INTERACTIVE
|
||||
return UI_CLOSE
|
||||
+22
-10
@@ -80,14 +80,20 @@
|
||||
opened_at = world.time
|
||||
window.acquire_lock(src)
|
||||
if(!window.is_ready())
|
||||
window.initialize(inline_assets = list(
|
||||
get_asset_datum(/datum/asset/simple/tgui),
|
||||
))
|
||||
window.initialize(
|
||||
fancy = user.client.prefs.tgui_fancy,
|
||||
inline_assets = list(
|
||||
get_asset_datum(/datum/asset/simple/tgui_common),
|
||||
get_asset_datum(/datum/asset/simple/tgui),
|
||||
))
|
||||
else
|
||||
window.send_message("ping")
|
||||
window.send_asset(get_asset_datum(/datum/asset/simple/fontawesome))
|
||||
var/flush_queue = window.send_asset(get_asset_datum(
|
||||
/datum/asset/simple/namespaced/fontawesome))
|
||||
for(var/datum/asset/asset in src_object.ui_assets(user))
|
||||
window.send_asset(asset)
|
||||
flush_queue |= window.send_asset(asset)
|
||||
if (flush_queue)
|
||||
user.client.browse_queue_flush()
|
||||
window.send_message("update", get_payload(
|
||||
with_data = TRUE,
|
||||
with_static_data = TRUE))
|
||||
@@ -143,11 +149,13 @@
|
||||
* Makes an asset available to use in tgui.
|
||||
*
|
||||
* required asset datum/asset
|
||||
*
|
||||
* return bool - true if an asset was actually sent
|
||||
*/
|
||||
/datum/tgui/proc/send_asset(datum/asset/asset)
|
||||
if(!window)
|
||||
CRASH("send_asset() can only be called after open().")
|
||||
window.send_asset(asset)
|
||||
return window.send_asset(asset)
|
||||
|
||||
/**
|
||||
* public
|
||||
@@ -199,13 +207,17 @@
|
||||
"key" = window_key,
|
||||
"size" = window_size,
|
||||
"fancy" = user.client.prefs.tgui_fancy,
|
||||
"locked" = user.client.prefs.tgui_lock
|
||||
"locked" = user.client.prefs.tgui_lock,
|
||||
),
|
||||
"client" = list(
|
||||
"ckey" = user.client.ckey,
|
||||
"address" = user.client.address,
|
||||
"computer_id" = user.client.computer_id,
|
||||
),
|
||||
"user" = list(
|
||||
"name" = "[user]",
|
||||
"ckey" = "[user.ckey]",
|
||||
"observer" = isobserver(user)
|
||||
)
|
||||
"observer" = isobserver(user),
|
||||
),
|
||||
)
|
||||
var/data = custom_data || with_data && src_object.ui_data(user)
|
||||
if(data)
|
||||
|
||||
@@ -8,12 +8,18 @@
|
||||
var/client/client
|
||||
var/pooled
|
||||
var/pool_index
|
||||
var/is_browser = FALSE
|
||||
var/status = TGUI_WINDOW_CLOSED
|
||||
var/locked = FALSE
|
||||
var/datum/tgui/locked_by
|
||||
var/datum/subscriber_object
|
||||
var/subscriber_delegate
|
||||
var/fatally_errored = FALSE
|
||||
var/message_queue
|
||||
var/sent_assets = list()
|
||||
// Vars passed to initialize proc (and saved for later)
|
||||
var/inline_assets
|
||||
var/fancy
|
||||
|
||||
/**
|
||||
* public
|
||||
@@ -26,9 +32,9 @@
|
||||
/datum/tgui_window/New(client/client, id, pooled = FALSE)
|
||||
src.id = id
|
||||
src.client = client
|
||||
src.client.tgui_windows[id] = src
|
||||
src.pooled = pooled
|
||||
if(pooled)
|
||||
client.tgui_windows[id] = src
|
||||
src.pool_index = TGUI_WINDOW_INDEX(id)
|
||||
|
||||
/**
|
||||
@@ -39,18 +45,24 @@
|
||||
* will be put into the queue until the window finishes loading.
|
||||
*
|
||||
* optional inline_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.
|
||||
*/
|
||||
/datum/tgui_window/proc/initialize(inline_assets = list())
|
||||
/datum/tgui_window/proc/initialize(
|
||||
inline_assets = list(),
|
||||
inline_html = "",
|
||||
fancy = FALSE)
|
||||
log_tgui(client, "[id]/initialize")
|
||||
if(!client)
|
||||
return
|
||||
src.inline_assets = inline_assets
|
||||
src.fancy = fancy
|
||||
status = TGUI_WINDOW_LOADING
|
||||
fatally_errored = FALSE
|
||||
message_queue = null
|
||||
// Build window options
|
||||
var/options = "file=[id].html;can_minimize=0;auto_format=0;"
|
||||
// Remove titlebar and resize handles for a fancy window
|
||||
if(client.prefs.tgui_fancy)
|
||||
if(fancy)
|
||||
options += "titlebar=0;can_resize=0;"
|
||||
else
|
||||
options += "titlebar=1;can_resize=1;"
|
||||
@@ -69,13 +81,17 @@
|
||||
inline_styles += "<link rel=\"stylesheet\" type=\"text/css\" href=\"[url]\">\n"
|
||||
else if(copytext(name, -3) == ".js")
|
||||
inline_scripts += "<script type=\"text/javascript\" defer src=\"[url]\"></script>\n"
|
||||
asset.send()
|
||||
asset.send(client)
|
||||
html = replacetextEx(html, "<!-- tgui:styles -->\n", inline_styles)
|
||||
html = replacetextEx(html, "<!-- tgui:scripts -->\n", inline_scripts)
|
||||
// Inject custom HTML
|
||||
html = replacetextEx(html, "<!-- tgui:html -->\n", inline_html)
|
||||
// Open the window
|
||||
client << browse(html, "window=[id];[options]")
|
||||
// Instruct the client to signal UI when the window is closed.
|
||||
winset(client, id, "on-close=\"uiclose [id]\"")
|
||||
// Detect whether the control is a browser
|
||||
is_browser = winexists(client, id) == "BROWSER"
|
||||
|
||||
/**
|
||||
* public
|
||||
@@ -107,8 +123,8 @@
|
||||
* Acquire the window lock. Pool will not be able to provide this window
|
||||
* to other UIs for the duration of the lock.
|
||||
*
|
||||
* Can be given an optional tgui datum, which will hook its on_message
|
||||
* callback into the message stream.
|
||||
* Can be given an optional tgui datum, which will be automatically
|
||||
* subscribed to incoming messages via the on_message proc.
|
||||
*
|
||||
* optional ui /datum/tgui
|
||||
*/
|
||||
@@ -117,6 +133,8 @@
|
||||
locked_by = ui
|
||||
|
||||
/**
|
||||
* public
|
||||
*
|
||||
* Release the window lock.
|
||||
*/
|
||||
/datum/tgui_window/proc/release_lock()
|
||||
@@ -126,6 +144,28 @@
|
||||
locked = FALSE
|
||||
locked_by = null
|
||||
|
||||
/**
|
||||
* public
|
||||
*
|
||||
* Subscribes the datum to consume window messages on a specified proc.
|
||||
*
|
||||
* Note, that this supports only one subscriber, because code for that
|
||||
* is simpler and therefore faster. If necessary, this can be rewritten
|
||||
* to support multiple subscribers.
|
||||
*/
|
||||
/datum/tgui_window/proc/subscribe(datum/object, delegate)
|
||||
subscriber_object = object
|
||||
subscriber_delegate = delegate
|
||||
|
||||
/**
|
||||
* public
|
||||
*
|
||||
* Unsubscribes the datum. Do not forget to call this when cleaning up.
|
||||
*/
|
||||
/datum/tgui_window/proc/unsubscribe(datum/object)
|
||||
subscriber_object = null
|
||||
subscriber_delegate = null
|
||||
|
||||
/**
|
||||
* public
|
||||
*
|
||||
@@ -159,25 +199,40 @@
|
||||
* required payload list Message payload
|
||||
* optional force bool Send regardless of the ready status.
|
||||
*/
|
||||
/datum/tgui_window/proc/send_message(type, list/payload, force)
|
||||
/datum/tgui_window/proc/send_message(type, payload, force)
|
||||
if(!client)
|
||||
return
|
||||
var/message = json_encode(list(
|
||||
"type" = type,
|
||||
"payload" = payload,
|
||||
))
|
||||
// Strip #255/improper.
|
||||
message = replacetext(message, "\proper", "")
|
||||
message = replacetext(message, "\improper", "")
|
||||
// Pack for sending via output()
|
||||
message = url_encode(message)
|
||||
var/message = TGUI_CREATE_MESSAGE(type, payload)
|
||||
// Place into queue if window is still loading
|
||||
if(!force && status != TGUI_WINDOW_READY)
|
||||
if(!message_queue)
|
||||
message_queue = list()
|
||||
message_queue += list(message)
|
||||
return
|
||||
client << output(message, "[id].browser:update")
|
||||
client << output(message, is_browser \
|
||||
? "[id]:update" \
|
||||
: "[id].browser:update")
|
||||
|
||||
/**
|
||||
* public
|
||||
*
|
||||
* Sends a raw payload to tgui window.
|
||||
*
|
||||
* required message string JSON+urlencoded blob to send.
|
||||
* optional force bool Send regardless of the ready status.
|
||||
*/
|
||||
/datum/tgui_window/proc/send_raw_message(message, force)
|
||||
if(!client)
|
||||
return
|
||||
// Place into queue if window is still loading
|
||||
if(!force && status != TGUI_WINDOW_READY)
|
||||
if(!message_queue)
|
||||
message_queue = list()
|
||||
message_queue += list(message)
|
||||
return
|
||||
client << output(message, is_browser \
|
||||
? "[id]:update" \
|
||||
: "[id].browser:update")
|
||||
|
||||
/**
|
||||
* public
|
||||
@@ -185,16 +240,18 @@
|
||||
* Makes an asset available to use in tgui.
|
||||
*
|
||||
* required asset datum/asset
|
||||
*
|
||||
* return bool - TRUE if any assets had to be sent to the client
|
||||
*/
|
||||
/datum/tgui_window/proc/send_asset(datum/asset/asset)
|
||||
if(!client || !asset)
|
||||
return
|
||||
sent_assets |= list(asset)
|
||||
. = asset.send(client)
|
||||
if(istype(asset, /datum/asset/spritesheet))
|
||||
var/datum/asset/spritesheet/spritesheet = asset
|
||||
send_message("asset/stylesheet", spritesheet.css_filename())
|
||||
send_message("asset/mappings", asset.get_url_mappings())
|
||||
sent_assets += list(asset)
|
||||
asset.send(client)
|
||||
|
||||
/**
|
||||
* private
|
||||
@@ -205,7 +262,9 @@
|
||||
if(!client || !message_queue)
|
||||
return
|
||||
for(var/message in message_queue)
|
||||
client << output(message, "[id].browser:update")
|
||||
client << output(message, is_browser \
|
||||
? "[id]:update" \
|
||||
: "[id].browser:update")
|
||||
message_queue = null
|
||||
|
||||
/**
|
||||
@@ -213,26 +272,45 @@
|
||||
*
|
||||
* Callback for handling incoming tgui messages.
|
||||
*/
|
||||
/datum/tgui_window/proc/on_message(type, list/payload, list/href_list)
|
||||
switch(type)
|
||||
if("ready")
|
||||
// Status can be READY if user has refreshed the window.
|
||||
if(status == TGUI_WINDOW_READY)
|
||||
// Resend the assets
|
||||
for(var/asset in sent_assets)
|
||||
send_asset(asset)
|
||||
status = TGUI_WINDOW_READY
|
||||
if("log")
|
||||
if(href_list["fatal"])
|
||||
fatally_errored = TRUE
|
||||
/datum/tgui_window/proc/on_message(type, payload, href_list)
|
||||
// Status can be READY if user has refreshed the window.
|
||||
if(type == "ready" && status == TGUI_WINDOW_READY)
|
||||
// Resend the assets
|
||||
for(var/asset in sent_assets)
|
||||
send_asset(asset)
|
||||
// Mark this window as fatally errored which prevents it from
|
||||
// being suspended.
|
||||
if(type == "log" && href_list["fatal"])
|
||||
fatally_errored = TRUE
|
||||
// Mark window as ready since we received this message from somewhere
|
||||
if(status != TGUI_WINDOW_READY)
|
||||
status = TGUI_WINDOW_READY
|
||||
flush_message_queue()
|
||||
// Pass message to UI that requested the lock
|
||||
if(locked && locked_by)
|
||||
locked_by.on_message(type, payload, href_list)
|
||||
flush_message_queue()
|
||||
return
|
||||
var/prevent_default = locked_by.on_message(type, payload, href_list)
|
||||
if(prevent_default)
|
||||
return
|
||||
// Pass message to the subscriber
|
||||
else if(subscriber_object)
|
||||
var/prevent_default = call(
|
||||
subscriber_object,
|
||||
subscriber_delegate)(type, payload, href_list)
|
||||
if(prevent_default)
|
||||
return
|
||||
// If not locked, handle these message types
|
||||
switch(type)
|
||||
if("ping")
|
||||
send_message("pingReply", payload)
|
||||
if("suspend")
|
||||
close(can_be_suspended = TRUE)
|
||||
if("close")
|
||||
close(can_be_suspended = FALSE)
|
||||
if("openLink")
|
||||
client << link(href_list["url"])
|
||||
if("cacheReloaded")
|
||||
// Reinitialize
|
||||
initialize(inline_assets = inline_assets, fancy = fancy)
|
||||
// Resend the assets
|
||||
for(var/asset in sent_assets)
|
||||
send_asset(asset)
|
||||
|
||||
Reference in New Issue
Block a user