mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-07-21 13:05:36 +01:00
Merge pull request #13703 from neersighted/nano_reduction
NanoUI Reduction
This commit is contained in:
+233
-240
@@ -1,240 +1,233 @@
|
||||
/*
|
||||
Asset cache quick users guide:
|
||||
|
||||
Make a datum at the bottom of this file with your assets for your thing.
|
||||
The simple subsystem will most like be of use for most cases.
|
||||
Then call get_asset_datum() with the type of the datum you created and store the return
|
||||
Then call .send(client) on that stored return value.
|
||||
|
||||
You can set verify to TRUE if you want send() to sleep until the client has the assets.
|
||||
*/
|
||||
|
||||
|
||||
// Amount of time(ds) MAX to send per asset, if this get exceeded we cancel the sleeping.
|
||||
// This is doubled for the first asset, then added per asset after
|
||||
#define ASSET_CACHE_SEND_TIMEOUT 7
|
||||
|
||||
//When sending mutiple assets, how many before we give the client a quaint little sending resources message
|
||||
#define ASSET_CACHE_TELL_CLIENT_AMOUNT 8
|
||||
|
||||
/client
|
||||
var/list/cache = list() // List of all assets sent to this client by the asset cache.
|
||||
var/list/completed_asset_jobs = list() // List of all completed jobs, awaiting acknowledgement.
|
||||
var/list/sending = list()
|
||||
var/last_asset_job = 0 // Last job done.
|
||||
|
||||
//This proc sends the asset to the client, but only if it needs it.
|
||||
//This proc blocks(sleeps) unless verify is set to false
|
||||
/proc/send_asset(var/client/client, var/asset_name, var/verify = TRUE)
|
||||
if(!istype(client))
|
||||
if(ismob(client))
|
||||
var/mob/M = client
|
||||
if(M.client)
|
||||
client = M.client
|
||||
|
||||
else
|
||||
return 0
|
||||
|
||||
else
|
||||
return 0
|
||||
|
||||
if(client.cache.Find(asset_name) || client.sending.Find(asset_name))
|
||||
return 0
|
||||
|
||||
client << browse_rsc(SSasset.cache[asset_name], asset_name)
|
||||
if(!verify || !winexists(client, "asset_cache_browser")) // Can't access the asset cache browser, rip.
|
||||
if (client)
|
||||
client.cache += asset_name
|
||||
return 1
|
||||
if (!client)
|
||||
return 0
|
||||
|
||||
client.sending |= asset_name
|
||||
var/job = ++client.last_asset_job
|
||||
|
||||
client << browse({"
|
||||
<script>
|
||||
window.location.href="?asset_cache_confirm_arrival=[job]"
|
||||
</script>
|
||||
"}, "window=asset_cache_browser")
|
||||
|
||||
var/t = 0
|
||||
var/timeout_time = (ASSET_CACHE_SEND_TIMEOUT * client.sending.len) + ASSET_CACHE_SEND_TIMEOUT
|
||||
while(client && !client.completed_asset_jobs.Find(job) && t < timeout_time) // Reception is handled in Topic()
|
||||
sleep(1) // Lock up the caller until this is received.
|
||||
t++
|
||||
|
||||
if(client)
|
||||
client.sending -= asset_name
|
||||
client.cache |= asset_name
|
||||
client.completed_asset_jobs -= job
|
||||
|
||||
return 1
|
||||
|
||||
//This proc blocks(sleeps) unless verify is set to false
|
||||
/proc/send_asset_list(var/client/client, var/list/asset_list, var/verify = TRUE)
|
||||
if(!istype(client))
|
||||
if(ismob(client))
|
||||
var/mob/M = client
|
||||
if(M.client)
|
||||
client = M.client
|
||||
|
||||
else
|
||||
return 0
|
||||
|
||||
else
|
||||
return 0
|
||||
|
||||
var/list/unreceived = asset_list - (client.cache + client.sending)
|
||||
if(!unreceived || !unreceived.len)
|
||||
return 0
|
||||
if (unreceived.len >= ASSET_CACHE_TELL_CLIENT_AMOUNT)
|
||||
client << "Sending Resources..."
|
||||
for(var/asset in unreceived)
|
||||
if (asset in SSasset.cache)
|
||||
client << browse_rsc(SSasset.cache[asset], asset)
|
||||
|
||||
if(!verify || !winexists(client, "asset_cache_browser")) // Can't access the asset cache browser, rip.
|
||||
if (client)
|
||||
client.cache += unreceived
|
||||
return 1
|
||||
if (!client)
|
||||
return 0
|
||||
client.sending |= unreceived
|
||||
var/job = ++client.last_asset_job
|
||||
|
||||
client << browse({"
|
||||
<script>
|
||||
window.location.href="?asset_cache_confirm_arrival=[job]"
|
||||
</script>
|
||||
"}, "window=asset_cache_browser")
|
||||
|
||||
var/t = 0
|
||||
var/timeout_time = ASSET_CACHE_SEND_TIMEOUT * client.sending.len
|
||||
while(client && !client.completed_asset_jobs.Find(job) && t < timeout_time) // Reception is handled in Topic()
|
||||
sleep(1) // Lock up the caller until this is received.
|
||||
t++
|
||||
|
||||
if(client)
|
||||
client.sending -= unreceived
|
||||
client.cache |= unreceived
|
||||
client.completed_asset_jobs -= job
|
||||
|
||||
return 1
|
||||
|
||||
//This proc will download the files without clogging up the browse() queue, used for passively sending files on connection start.
|
||||
//The proc calls procs that sleep for long times.
|
||||
/proc/getFilesSlow(var/client/client, var/list/files, var/register_asset = TRUE)
|
||||
for(var/file in files)
|
||||
if (!client)
|
||||
break
|
||||
if (register_asset)
|
||||
register_asset(file,files[file])
|
||||
send_asset(client,file)
|
||||
sleep(-1) //queuing calls like this too quickly can cause issues in some client versions
|
||||
|
||||
//This proc "registers" an asset, it adds it to the cache for further use, you cannot touch it from this point on or you'll fuck things up.
|
||||
//if it's an icon or something be careful, you'll have to copy it before further use.
|
||||
/proc/register_asset(var/asset_name, var/asset)
|
||||
SSasset.cache[asset_name] = asset
|
||||
|
||||
//These datums are used to populate the asset cache, the proc "register()" does this.
|
||||
|
||||
//all of our asset datums, used for referring to these later
|
||||
/var/global/list/asset_datums = list()
|
||||
|
||||
//get a assetdatum or make a new one
|
||||
/proc/get_asset_datum(var/type)
|
||||
if (!(type in asset_datums))
|
||||
return new type()
|
||||
return asset_datums[type]
|
||||
|
||||
/datum/asset/New()
|
||||
asset_datums[type] = src
|
||||
|
||||
/datum/asset/proc/register()
|
||||
return
|
||||
|
||||
/datum/asset/proc/send(client)
|
||||
return
|
||||
|
||||
//If you don't need anything complicated.
|
||||
/datum/asset/simple
|
||||
var/assets = list()
|
||||
var/verify = FALSE
|
||||
|
||||
/datum/asset/simple/register()
|
||||
for(var/asset_name in assets)
|
||||
register_asset(asset_name, assets[asset_name])
|
||||
/datum/asset/simple/send(client)
|
||||
send_asset_list(client,assets,verify)
|
||||
|
||||
|
||||
//DEFINITIONS FOR ASSET DATUMS START HERE.
|
||||
|
||||
|
||||
/datum/asset/simple/nanoui
|
||||
assets = list(
|
||||
"nanoui.lib.js" = 'nano/assets/nanoui.lib.js',
|
||||
"nanoui.main.js" = 'nano/assets/nanoui.main.js',
|
||||
"nanoui.templates.js" = 'nano/assets/nanoui.templates.js',
|
||||
"nanoui.lib.css" = 'nano/assets/nanoui.lib.css',
|
||||
"nanoui.common.css" = 'nano/assets/nanoui.common.css',
|
||||
"nanoui.generic.css" = 'nano/assets/nanoui.generic.css',
|
||||
"nanoui.nanotrasen.css" = 'nano/assets/nanoui.nanotrasen.css',
|
||||
"fontawesome-webfont.eot" = 'nano/assets/fontawesome-webfont.eot',
|
||||
"fontawesome-webfont.woff2" = 'nano/assets/fontawesome-webfont.woff2'
|
||||
)
|
||||
|
||||
/datum/asset/simple/pda
|
||||
assets = list(
|
||||
"pda_atmos.png" = 'icons/pda_icons/pda_atmos.png',
|
||||
"pda_back.png" = 'icons/pda_icons/pda_back.png',
|
||||
"pda_bell.png" = 'icons/pda_icons/pda_bell.png',
|
||||
"pda_blank.png" = 'icons/pda_icons/pda_blank.png',
|
||||
"pda_boom.png" = 'icons/pda_icons/pda_boom.png',
|
||||
"pda_bucket.png" = 'icons/pda_icons/pda_bucket.png',
|
||||
"pda_medbot.png" = 'icons/pda_icons/pda_medbot.png',
|
||||
"pda_floorbot.png" = 'icons/pda_icons/pda_floorbot.png',
|
||||
"pda_cleanbot.png" = 'icons/pda_icons/pda_cleanbot.png',
|
||||
"pda_crate.png" = 'icons/pda_icons/pda_crate.png',
|
||||
"pda_cuffs.png" = 'icons/pda_icons/pda_cuffs.png',
|
||||
"pda_eject.png" = 'icons/pda_icons/pda_eject.png',
|
||||
"pda_exit.png" = 'icons/pda_icons/pda_exit.png',
|
||||
"pda_flashlight.png" = 'icons/pda_icons/pda_flashlight.png',
|
||||
"pda_honk.png" = 'icons/pda_icons/pda_honk.png',
|
||||
"pda_mail.png" = 'icons/pda_icons/pda_mail.png',
|
||||
"pda_medical.png" = 'icons/pda_icons/pda_medical.png',
|
||||
"pda_menu.png" = 'icons/pda_icons/pda_menu.png',
|
||||
"pda_mule.png" = 'icons/pda_icons/pda_mule.png',
|
||||
"pda_notes.png" = 'icons/pda_icons/pda_notes.png',
|
||||
"pda_power.png" = 'icons/pda_icons/pda_power.png',
|
||||
"pda_rdoor.png" = 'icons/pda_icons/pda_rdoor.png',
|
||||
"pda_reagent.png" = 'icons/pda_icons/pda_reagent.png',
|
||||
"pda_refresh.png" = 'icons/pda_icons/pda_refresh.png',
|
||||
"pda_scanner.png" = 'icons/pda_icons/pda_scanner.png',
|
||||
"pda_signaler.png" = 'icons/pda_icons/pda_signaler.png',
|
||||
"pda_status.png" = 'icons/pda_icons/pda_status.png'
|
||||
)
|
||||
|
||||
/datum/asset/simple/paper
|
||||
assets = list(
|
||||
"large_stamp-clown.png" = 'icons/stamp_icons/large_stamp-clown.png',
|
||||
"large_stamp-deny.png" = 'icons/stamp_icons/large_stamp-deny.png',
|
||||
"large_stamp-ok.png" = 'icons/stamp_icons/large_stamp-ok.png',
|
||||
"large_stamp-hop.png" = 'icons/stamp_icons/large_stamp-hop.png',
|
||||
"large_stamp-cmo.png" = 'icons/stamp_icons/large_stamp-cmo.png',
|
||||
"large_stamp-ce.png" = 'icons/stamp_icons/large_stamp-ce.png',
|
||||
"large_stamp-hos.png" = 'icons/stamp_icons/large_stamp-hos.png',
|
||||
"large_stamp-rd.png" = 'icons/stamp_icons/large_stamp-rd.png',
|
||||
"large_stamp-cap.png" = 'icons/stamp_icons/large_stamp-cap.png',
|
||||
"large_stamp-qm.png" = 'icons/stamp_icons/large_stamp-qm.png',
|
||||
"large_stamp-law.png" = 'icons/stamp_icons/large_stamp-law.png'
|
||||
)
|
||||
|
||||
|
||||
//Registers HTML Interface assets.
|
||||
/datum/asset/HTML_interface/register()
|
||||
for(var/path in typesof(/datum/html_interface))
|
||||
var/datum/html_interface/hi = new path()
|
||||
hi.registerResources()
|
||||
/*
|
||||
Asset cache quick users guide:
|
||||
|
||||
Make a datum at the bottom of this file with your assets for your thing.
|
||||
The simple subsystem will most like be of use for most cases.
|
||||
Then call get_asset_datum() with the type of the datum you created and store the return
|
||||
Then call .send(client) on that stored return value.
|
||||
|
||||
You can set verify to TRUE if you want send() to sleep until the client has the assets.
|
||||
*/
|
||||
|
||||
|
||||
// Amount of time(ds) MAX to send per asset, if this get exceeded we cancel the sleeping.
|
||||
// This is doubled for the first asset, then added per asset after
|
||||
#define ASSET_CACHE_SEND_TIMEOUT 7
|
||||
|
||||
//When sending mutiple assets, how many before we give the client a quaint little sending resources message
|
||||
#define ASSET_CACHE_TELL_CLIENT_AMOUNT 8
|
||||
|
||||
/client
|
||||
var/list/cache = list() // List of all assets sent to this client by the asset cache.
|
||||
var/list/completed_asset_jobs = list() // List of all completed jobs, awaiting acknowledgement.
|
||||
var/list/sending = list()
|
||||
var/last_asset_job = 0 // Last job done.
|
||||
|
||||
//This proc sends the asset to the client, but only if it needs it.
|
||||
//This proc blocks(sleeps) unless verify is set to false
|
||||
/proc/send_asset(var/client/client, var/asset_name, var/verify = TRUE)
|
||||
if(!istype(client))
|
||||
if(ismob(client))
|
||||
var/mob/M = client
|
||||
if(M.client)
|
||||
client = M.client
|
||||
|
||||
else
|
||||
return 0
|
||||
|
||||
else
|
||||
return 0
|
||||
|
||||
if(client.cache.Find(asset_name) || client.sending.Find(asset_name))
|
||||
return 0
|
||||
|
||||
client << browse_rsc(SSasset.cache[asset_name], asset_name)
|
||||
if(!verify || !winexists(client, "asset_cache_browser")) // Can't access the asset cache browser, rip.
|
||||
if (client)
|
||||
client.cache += asset_name
|
||||
return 1
|
||||
if (!client)
|
||||
return 0
|
||||
|
||||
client.sending |= asset_name
|
||||
var/job = ++client.last_asset_job
|
||||
|
||||
client << browse({"
|
||||
<script>
|
||||
window.location.href="?asset_cache_confirm_arrival=[job]"
|
||||
</script>
|
||||
"}, "window=asset_cache_browser")
|
||||
|
||||
var/t = 0
|
||||
var/timeout_time = (ASSET_CACHE_SEND_TIMEOUT * client.sending.len) + ASSET_CACHE_SEND_TIMEOUT
|
||||
while(client && !client.completed_asset_jobs.Find(job) && t < timeout_time) // Reception is handled in Topic()
|
||||
sleep(1) // Lock up the caller until this is received.
|
||||
t++
|
||||
|
||||
if(client)
|
||||
client.sending -= asset_name
|
||||
client.cache |= asset_name
|
||||
client.completed_asset_jobs -= job
|
||||
|
||||
return 1
|
||||
|
||||
//This proc blocks(sleeps) unless verify is set to false
|
||||
/proc/send_asset_list(var/client/client, var/list/asset_list, var/verify = TRUE)
|
||||
if(!istype(client))
|
||||
if(ismob(client))
|
||||
var/mob/M = client
|
||||
if(M.client)
|
||||
client = M.client
|
||||
|
||||
else
|
||||
return 0
|
||||
|
||||
else
|
||||
return 0
|
||||
|
||||
var/list/unreceived = asset_list - (client.cache + client.sending)
|
||||
if(!unreceived || !unreceived.len)
|
||||
return 0
|
||||
if (unreceived.len >= ASSET_CACHE_TELL_CLIENT_AMOUNT)
|
||||
client << "Sending Resources..."
|
||||
for(var/asset in unreceived)
|
||||
if (asset in SSasset.cache)
|
||||
client << browse_rsc(SSasset.cache[asset], asset)
|
||||
|
||||
if(!verify || !winexists(client, "asset_cache_browser")) // Can't access the asset cache browser, rip.
|
||||
if (client)
|
||||
client.cache += unreceived
|
||||
return 1
|
||||
if (!client)
|
||||
return 0
|
||||
client.sending |= unreceived
|
||||
var/job = ++client.last_asset_job
|
||||
|
||||
client << browse({"
|
||||
<script>
|
||||
window.location.href="?asset_cache_confirm_arrival=[job]"
|
||||
</script>
|
||||
"}, "window=asset_cache_browser")
|
||||
|
||||
var/t = 0
|
||||
var/timeout_time = ASSET_CACHE_SEND_TIMEOUT * client.sending.len
|
||||
while(client && !client.completed_asset_jobs.Find(job) && t < timeout_time) // Reception is handled in Topic()
|
||||
sleep(1) // Lock up the caller until this is received.
|
||||
t++
|
||||
|
||||
if(client)
|
||||
client.sending -= unreceived
|
||||
client.cache |= unreceived
|
||||
client.completed_asset_jobs -= job
|
||||
|
||||
return 1
|
||||
|
||||
//This proc will download the files without clogging up the browse() queue, used for passively sending files on connection start.
|
||||
//The proc calls procs that sleep for long times.
|
||||
/proc/getFilesSlow(var/client/client, var/list/files, var/register_asset = TRUE)
|
||||
for(var/file in files)
|
||||
if (!client)
|
||||
break
|
||||
if (register_asset)
|
||||
register_asset(file,files[file])
|
||||
send_asset(client,file)
|
||||
sleep(-1) //queuing calls like this too quickly can cause issues in some client versions
|
||||
|
||||
//This proc "registers" an asset, it adds it to the cache for further use, you cannot touch it from this point on or you'll fuck things up.
|
||||
//if it's an icon or something be careful, you'll have to copy it before further use.
|
||||
/proc/register_asset(var/asset_name, var/asset)
|
||||
SSasset.cache[asset_name] = asset
|
||||
|
||||
//These datums are used to populate the asset cache, the proc "register()" does this.
|
||||
|
||||
//all of our asset datums, used for referring to these later
|
||||
/var/global/list/asset_datums = list()
|
||||
|
||||
//get a assetdatum or make a new one
|
||||
/proc/get_asset_datum(var/type)
|
||||
if (!(type in asset_datums))
|
||||
return new type()
|
||||
return asset_datums[type]
|
||||
|
||||
/datum/asset/New()
|
||||
asset_datums[type] = src
|
||||
|
||||
/datum/asset/proc/register()
|
||||
return
|
||||
|
||||
/datum/asset/proc/send(client)
|
||||
return
|
||||
|
||||
//If you don't need anything complicated.
|
||||
/datum/asset/simple
|
||||
var/assets = list()
|
||||
var/verify = FALSE
|
||||
|
||||
/datum/asset/simple/register()
|
||||
for(var/asset_name in assets)
|
||||
register_asset(asset_name, assets[asset_name])
|
||||
/datum/asset/simple/send(client)
|
||||
send_asset_list(client,assets,verify)
|
||||
|
||||
|
||||
//DEFINITIONS FOR ASSET DATUMS START HERE.
|
||||
|
||||
|
||||
/datum/asset/simple/nanoui
|
||||
assets = list(
|
||||
"nanoui.js" = 'nano/assets/nanoui.js',
|
||||
"nanoui.css" = 'nano/assets/nanoui.css',
|
||||
)
|
||||
|
||||
/datum/asset/simple/pda
|
||||
assets = list(
|
||||
"pda_atmos.png" = 'icons/pda_icons/pda_atmos.png',
|
||||
"pda_back.png" = 'icons/pda_icons/pda_back.png',
|
||||
"pda_bell.png" = 'icons/pda_icons/pda_bell.png',
|
||||
"pda_blank.png" = 'icons/pda_icons/pda_blank.png',
|
||||
"pda_boom.png" = 'icons/pda_icons/pda_boom.png',
|
||||
"pda_bucket.png" = 'icons/pda_icons/pda_bucket.png',
|
||||
"pda_medbot.png" = 'icons/pda_icons/pda_medbot.png',
|
||||
"pda_floorbot.png" = 'icons/pda_icons/pda_floorbot.png',
|
||||
"pda_cleanbot.png" = 'icons/pda_icons/pda_cleanbot.png',
|
||||
"pda_crate.png" = 'icons/pda_icons/pda_crate.png',
|
||||
"pda_cuffs.png" = 'icons/pda_icons/pda_cuffs.png',
|
||||
"pda_eject.png" = 'icons/pda_icons/pda_eject.png',
|
||||
"pda_exit.png" = 'icons/pda_icons/pda_exit.png',
|
||||
"pda_flashlight.png" = 'icons/pda_icons/pda_flashlight.png',
|
||||
"pda_honk.png" = 'icons/pda_icons/pda_honk.png',
|
||||
"pda_mail.png" = 'icons/pda_icons/pda_mail.png',
|
||||
"pda_medical.png" = 'icons/pda_icons/pda_medical.png',
|
||||
"pda_menu.png" = 'icons/pda_icons/pda_menu.png',
|
||||
"pda_mule.png" = 'icons/pda_icons/pda_mule.png',
|
||||
"pda_notes.png" = 'icons/pda_icons/pda_notes.png',
|
||||
"pda_power.png" = 'icons/pda_icons/pda_power.png',
|
||||
"pda_rdoor.png" = 'icons/pda_icons/pda_rdoor.png',
|
||||
"pda_reagent.png" = 'icons/pda_icons/pda_reagent.png',
|
||||
"pda_refresh.png" = 'icons/pda_icons/pda_refresh.png',
|
||||
"pda_scanner.png" = 'icons/pda_icons/pda_scanner.png',
|
||||
"pda_signaler.png" = 'icons/pda_icons/pda_signaler.png',
|
||||
"pda_status.png" = 'icons/pda_icons/pda_status.png'
|
||||
)
|
||||
|
||||
/datum/asset/simple/paper
|
||||
assets = list(
|
||||
"large_stamp-clown.png" = 'icons/stamp_icons/large_stamp-clown.png',
|
||||
"large_stamp-deny.png" = 'icons/stamp_icons/large_stamp-deny.png',
|
||||
"large_stamp-ok.png" = 'icons/stamp_icons/large_stamp-ok.png',
|
||||
"large_stamp-hop.png" = 'icons/stamp_icons/large_stamp-hop.png',
|
||||
"large_stamp-cmo.png" = 'icons/stamp_icons/large_stamp-cmo.png',
|
||||
"large_stamp-ce.png" = 'icons/stamp_icons/large_stamp-ce.png',
|
||||
"large_stamp-hos.png" = 'icons/stamp_icons/large_stamp-hos.png',
|
||||
"large_stamp-rd.png" = 'icons/stamp_icons/large_stamp-rd.png',
|
||||
"large_stamp-cap.png" = 'icons/stamp_icons/large_stamp-cap.png',
|
||||
"large_stamp-qm.png" = 'icons/stamp_icons/large_stamp-qm.png',
|
||||
"large_stamp-law.png" = 'icons/stamp_icons/large_stamp-law.png'
|
||||
)
|
||||
|
||||
|
||||
//Registers HTML Interface assets.
|
||||
/datum/asset/HTML_interface/register()
|
||||
for(var/path in typesof(/datum/html_interface))
|
||||
var/datum/html_interface/hi = new path()
|
||||
hi.registerResources()
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/mob/Logout()
|
||||
SSnano.user_logout(src) // this is used to clean up (remove) this user's Nano UIs
|
||||
SSnano.on_logout(src)
|
||||
player_list -= src
|
||||
log_access("Logout: [key_name(src)]")
|
||||
if(admin_datums[src.ckey])
|
||||
|
||||
@@ -27,6 +27,20 @@
|
||||
datum/topic_state/state = default_state)
|
||||
return -1 // Sorta implemented.
|
||||
|
||||
/**
|
||||
* public
|
||||
*
|
||||
* Data to be sent to the NanoUI.
|
||||
* This must be implemented for a NanoUI to work.
|
||||
*
|
||||
* required user mob The mob interacting with the NanoUI.
|
||||
*
|
||||
* return list Data to be sent to the NanoUI.
|
||||
**/
|
||||
/atom/movable/proc/get_ui_data(mob/user)
|
||||
return list() // Not implemented.
|
||||
|
||||
|
||||
/**
|
||||
* public
|
||||
*
|
||||
@@ -41,18 +55,6 @@
|
||||
/atom/movable/proc/ui_act(action, list/params)
|
||||
return // Not implemented.
|
||||
|
||||
/**
|
||||
* public
|
||||
*
|
||||
* Data to be sent to the NanoUI.
|
||||
* This must be implemented for a NanoUI to work.
|
||||
*
|
||||
* required user mob The mob interacting with the NanoUI.
|
||||
*
|
||||
* return list Data to be sent to the NanoUI.
|
||||
**/
|
||||
/atom/movable/proc/get_ui_data(mob/user)
|
||||
return list() // Not implemented.
|
||||
|
||||
/**
|
||||
* private
|
||||
@@ -67,7 +69,6 @@
|
||||
* global
|
||||
*
|
||||
* Used to track NanoUIs for a mob.
|
||||
*
|
||||
**/
|
||||
/mob/var/list/open_uis = list()
|
||||
|
||||
|
||||
+403
-405
@@ -1,405 +1,403 @@
|
||||
/**
|
||||
* NanoUI
|
||||
*
|
||||
* Contains the NanoUI datum, and its procs.
|
||||
*
|
||||
* /tg/station user interface library
|
||||
* thanks to baystation12
|
||||
*
|
||||
* modified by neersighted
|
||||
**/
|
||||
|
||||
/**
|
||||
* NanoUI datum:
|
||||
*
|
||||
* Represents a NanoUI.
|
||||
**/
|
||||
/datum/nanoui
|
||||
var/mob/user // The mob who opened/is using the NanoUI.
|
||||
var/atom/movable/src_object // The object which owns the NanoUI.
|
||||
var/title // The title of te NanoUI.
|
||||
var/ui_key // The ui_key of the NanoUI. This allows multiple UIs for one src_object.
|
||||
var/window_id // The window_id for browse() and onclose().
|
||||
var/width = 0 // The window width.
|
||||
var/height = 0 // The window height
|
||||
var/window_options = list( // Extra options to winset().
|
||||
"focus" = 0,
|
||||
"titlebar" = 1,
|
||||
"can_resize" = 1,
|
||||
"can_minimize" = 1,
|
||||
"can_maximize" = 0,
|
||||
"can_close" = 1,
|
||||
"auto_format" = 0
|
||||
)
|
||||
var/atom/ref = null // An extra ref to call when the window is closed.
|
||||
var/layout = "nanotrasen" // The layout to be used for this UI.
|
||||
var/template // The template to be used for this UI.
|
||||
var/auto_update = 1 // Update the NanoUI every MC tick.
|
||||
var/list/initial_data // The data (and datastructure) used to initialize the NanoUI
|
||||
var/status = NANO_INTERACTIVE // The status/visibility of the NanoUI.
|
||||
var/datum/topic_state/state = null // Topic state used to determine status. Topic states are in interactions/.
|
||||
var/datum/nanoui/master_ui // The parent NanoUI.
|
||||
var/list/datum/nanoui/children = list() // Children of this NanoUI.
|
||||
|
||||
/**
|
||||
* public
|
||||
*
|
||||
* Create a new NanoUI.
|
||||
*
|
||||
* required user mob The mob who opened/is using the NanoUI.
|
||||
* required src_object atom/movable The object which owns the NanoUI.
|
||||
* required ui_key string The ui_key of the NanoUI.
|
||||
* required template string The template to render the NanoUI content with.
|
||||
* optional title string The title of the NanoUI.
|
||||
* optional width int The window width.
|
||||
* optional height int The window height.
|
||||
* optional ref atom An extra ref to use when the window is closed.
|
||||
* optional master_ui datum/nanoui The parent NanoUI.
|
||||
* optional state datum/topic_state The state used to determine status.
|
||||
*
|
||||
* return datum/nanoui The requested NanoUI.
|
||||
**/
|
||||
/datum/nanoui/New(mob/user, atom/movable/src_object, ui_key, template, \
|
||||
title = 0, width = 0, height = 0, \
|
||||
atom/ref = null, datum/nanoui/master_ui = null, \
|
||||
datum/topic_state/state = default_state)
|
||||
src.user = user
|
||||
src.src_object = src_object
|
||||
src.ui_key = ui_key
|
||||
src.window_id = "\ref[src_object]-[ui_key]"
|
||||
|
||||
set_template(template)
|
||||
|
||||
if (title)
|
||||
src.title = sanitize(title)
|
||||
if (width)
|
||||
src.width = width
|
||||
if (height)
|
||||
src.height = height
|
||||
|
||||
if (ref)
|
||||
src.ref = ref
|
||||
|
||||
src.master_ui = master_ui
|
||||
if(master_ui)
|
||||
master_ui.children += src
|
||||
src.state = state
|
||||
|
||||
var/datum/asset/assets = get_asset_datum(/datum/asset/simple/nanoui)
|
||||
assets.send(user)
|
||||
|
||||
|
||||
/**
|
||||
* public
|
||||
*
|
||||
* Enable/disable auto-updating of the NanoUI.
|
||||
*
|
||||
* required state bool Enable/disable auto-updating.
|
||||
**/
|
||||
/datum/nanoui/proc/set_auto_update(state = 1)
|
||||
auto_update = state
|
||||
|
||||
/**
|
||||
* private
|
||||
*
|
||||
* Set the data to initialize the NanoUI with.
|
||||
* The datastructure cannot be changed by subsequent updates.
|
||||
*
|
||||
* optional data list The data/datastructure to initialize the NanoUI with.
|
||||
**/
|
||||
/datum/nanoui/proc/set_initial_data(list/data)
|
||||
initial_data = data
|
||||
|
||||
/**
|
||||
* private
|
||||
*
|
||||
* Get the config data/datastructure to initialize the NanoUI with.
|
||||
*
|
||||
* return list The config data.
|
||||
**/
|
||||
/datum/nanoui/proc/get_config_data()
|
||||
var/list/config_data = list(
|
||||
"title" = title,
|
||||
"status" = status,
|
||||
"ref" = "\ref[src]",
|
||||
"window" = list(
|
||||
"width" = width,
|
||||
"height" = height,
|
||||
"ref" = window_id
|
||||
),
|
||||
"user" = list(
|
||||
"name" = user.name,
|
||||
"fancy" = user.client.prefs.nanoui_fancy,
|
||||
"ref" = "\ref[user]"
|
||||
),
|
||||
"srcObject" = list(
|
||||
"name" = src_object.name,
|
||||
"ref" = "\ref[src_object]"
|
||||
),
|
||||
"templates" = list(
|
||||
"layout" = "_[layout]",
|
||||
"content" = "[template]"
|
||||
)
|
||||
)
|
||||
return config_data
|
||||
|
||||
/**
|
||||
* private
|
||||
*
|
||||
* Package the data to send to the UI.
|
||||
* This is the (regular) data and config data, bundled together.
|
||||
*
|
||||
* return list The packaged data.
|
||||
**/
|
||||
/datum/nanoui/proc/get_send_data(list/data)
|
||||
var/list/send_data = list()
|
||||
|
||||
send_data["config"] = get_config_data()
|
||||
if (!isnull(data))
|
||||
send_data["data"] = data
|
||||
|
||||
return send_data
|
||||
|
||||
/**
|
||||
* public
|
||||
*
|
||||
* Sets the browse() window options for this NanoUI.
|
||||
*
|
||||
* required window_options list The window options to set.
|
||||
**/
|
||||
/datum/nanoui/proc/set_window_options(list/window_options)
|
||||
src.window_options = window_options
|
||||
|
||||
/**
|
||||
* public
|
||||
*
|
||||
* Set the layout for this NanoUI.
|
||||
* This loads custom layout styles and templates for this NanoUI.
|
||||
*
|
||||
* required layout string The new UI layout.
|
||||
**/
|
||||
/datum/nanoui/proc/set_layout(layout)
|
||||
src.layout = lowertext(layout)
|
||||
|
||||
/**
|
||||
* public
|
||||
*
|
||||
* Set the template for this NanoUI.
|
||||
*
|
||||
* required template string The new UI template.
|
||||
**/
|
||||
/datum/nanoui/proc/set_template(template)
|
||||
src.template = lowertext(template)
|
||||
|
||||
/**
|
||||
* private
|
||||
*
|
||||
* Generate HTML for this NanoUI.
|
||||
*
|
||||
* return string NanoUI HTML output.
|
||||
**/
|
||||
/datum/nanoui/proc/get_html()
|
||||
// Generate <script> and <link> tags.
|
||||
var/script_html = {"
|
||||
<script type='text/javascript' src='nanoui.lib.js'></script>
|
||||
<script type='text/javascript' src='nanoui.main.js'></script>
|
||||
<script type='text/javascript' src='nanoui.templates.js'></script>
|
||||
"}
|
||||
var/stylesheet_html = {"
|
||||
<link rel="stylesheet" type='text/css' href='http://css-spinners.com/css/spinner/hexdots.css'>
|
||||
<link rel='stylesheet' type='text/css' href='nanoui.lib.css' />
|
||||
<link rel='stylesheet' type='text/css' href='nanoui.common.css' />
|
||||
<link rel='stylesheet' type='text/css' href='nanoui.[layout].css' />
|
||||
"}
|
||||
|
||||
// Generate JSON.
|
||||
var/list/send_data = get_send_data(initial_data)
|
||||
var/initial_data_json = replacetext(JSON.stringify(send_data), "'", "\\'")
|
||||
|
||||
// Generate the HTML document.
|
||||
return {"
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv='X-UA-Compatible' content='IE=edge'>
|
||||
<script type='text/javascript'>
|
||||
function receiveUpdate(dataString) {
|
||||
if (typeof NanoBus !== 'undefined') {
|
||||
NanoBus.emit('serverUpdate', dataString);
|
||||
}
|
||||
};
|
||||
</script>
|
||||
[stylesheet_html]
|
||||
[script_html]
|
||||
</head>
|
||||
<body>
|
||||
<div id='data' data-initial='[initial_data_json]'></div>
|
||||
<div id='layout'>
|
||||
<div class='hexdots-loader' style='position:fixed;top:50%;left:50%;transform:translate(-50%, -50%);-ms-transform:translate(-50%, -50%);'>
|
||||
Sending Resources...
|
||||
</div>
|
||||
</div>
|
||||
<noscript>
|
||||
<h1>Javascript Required</h1>
|
||||
<p>Javascript is required in order to use this NanoUI interface.</p>
|
||||
<p>Please enable Javascript in Internet Explorer, and restart your game.</p>
|
||||
</noscript>
|
||||
</body>
|
||||
</html>
|
||||
"}
|
||||
|
||||
/**
|
||||
* public
|
||||
*
|
||||
* Open this NanoUI (and initialize it with data).
|
||||
*
|
||||
* optional data list The data to intialize the UI with.
|
||||
**/
|
||||
/datum/nanoui/proc/open(list/data = null)
|
||||
if(!user.client) return
|
||||
|
||||
if (!initial_data)
|
||||
if (!data) // If we don't have initial_data and data was not passed, get data from the src_object.
|
||||
data = src_object.get_ui_data(user)
|
||||
set_initial_data(data) // Otherwise use the passed data.
|
||||
|
||||
var/window_size = ""
|
||||
if (width && height) // If we have a width and height, use them.
|
||||
window_size = "size=[width]x[height];"
|
||||
update_status(push = 0) // Update the window state.
|
||||
if (status == NANO_CLOSE)
|
||||
return // Bail if we should close.
|
||||
|
||||
user << browse(get_html(), "window=[window_id];[window_size][list2params(window_options)]") // Open the window.
|
||||
winset(user, window_id, "on-close=\"nanoclose \ref[src]\"") // Instruct the client to signal NanoUI when the window is closed.
|
||||
SSnano.ui_opened(src) // Call the opened handler.
|
||||
|
||||
/**
|
||||
* public
|
||||
*
|
||||
* Reinitialize the NanoUI.
|
||||
* (Possibly with a new template and/or data).
|
||||
*
|
||||
* optional template string The filename of the new template.
|
||||
* optional data list The new initial data.
|
||||
**/
|
||||
/datum/nanoui/proc/reinitialize(template, list/data)
|
||||
if(template)
|
||||
src.template = template // Set a new template.
|
||||
if(data)
|
||||
set_initial_data(data) // Replace the initial_data.
|
||||
open()
|
||||
|
||||
/**
|
||||
* public
|
||||
*
|
||||
* Close the NanoUI, and all its children.
|
||||
**/
|
||||
/datum/nanoui/proc/close()
|
||||
set_auto_update(0) // Disable auto-updates.
|
||||
user << browse(null, "window=[window_id]") // Close the window.
|
||||
SSnano.ui_closed(src) // Call the closed handler.
|
||||
for(var/datum/nanoui/child in children) // Loop through and close all children.
|
||||
child.close()
|
||||
|
||||
/**
|
||||
* private
|
||||
*
|
||||
* Push data to an already open NanoUI.
|
||||
*
|
||||
* required data list The data to send.
|
||||
* optional force bool If the update should be sent regardless of state.
|
||||
**/
|
||||
/datum/nanoui/proc/push_data(data, force = 0)
|
||||
update_status(push = 0) // Update the window state.
|
||||
if (status == NANO_DISABLED && !force)
|
||||
return // Cannot update UI, we have no visibility.
|
||||
|
||||
var/list/send_data = get_send_data(data) // Get the data to send.
|
||||
|
||||
// Send the new data to the recieveUpdate() Javascript function.
|
||||
user << output(list2params(list(JSON.stringify(send_data))), "[window_id].browser:receiveUpdate")
|
||||
|
||||
/**
|
||||
* private
|
||||
*
|
||||
* Handle clicks from the NanoUI.
|
||||
* Call the src_object's Topic() if status is NANO_INTERACTIVE.
|
||||
* If the src_object's Topic() returns 1, update all UIs attacked to it.
|
||||
**/
|
||||
/datum/nanoui/Topic(href, href_list)
|
||||
update_status(push = 0) // Update the window state.
|
||||
if (status != NANO_INTERACTIVE || user != usr)
|
||||
return // If UI is not interactive or usr calling Topic is not the UI user.
|
||||
|
||||
var/action = href_list["nano"] // Pull the action out.
|
||||
href_list -= "nano"
|
||||
|
||||
var/update = src_object.ui_act(action, href_list, state) // Call Topic() on the src_object.
|
||||
|
||||
if (src_object && update)
|
||||
SSnano.update_uis(src_object) // If we have a src_object and its Topic() told us to update.
|
||||
|
||||
/**
|
||||
* private
|
||||
*
|
||||
* Update the NanoUI. Only updates the contents/layout if update is true,
|
||||
* otherwise only updates the status.
|
||||
*
|
||||
* optional force bool If the UI should be forced to update.
|
||||
**/
|
||||
/datum/nanoui/process(force = 0)
|
||||
if (!src_object || !user) // If the object or user died (or something else), abort.
|
||||
close()
|
||||
return
|
||||
|
||||
if (status && (force || auto_update))
|
||||
update() // Update the UI if the status and update settings allow it.
|
||||
else
|
||||
update_status(push = 1) // Otherwise only update status.
|
||||
|
||||
/**
|
||||
* private
|
||||
*
|
||||
* Updates the UI by interacting with the src_object again, which will hopefully
|
||||
* call try_ui_update on it.
|
||||
*
|
||||
* optional force_open bool If force_open should be passed to ui_interact.
|
||||
**/
|
||||
/datum/nanoui/proc/update(force_open = 0)
|
||||
src_object.ui_interact(user, ui_key, src, force_open, master_ui, state)
|
||||
|
||||
/**
|
||||
* private
|
||||
*
|
||||
* Set the status/visibility of the NanoUI.
|
||||
*
|
||||
* required state int The status to set (NANO_CLOSE/NANO_DISABLED/NANO_UPDATE/NANO_INTERACTIVE).
|
||||
* optional push bool Push an update to the UI (an update is always sent for NANO_DISABLED).
|
||||
**/
|
||||
/datum/nanoui/proc/set_status(state, push = 0)
|
||||
if (state != status) // Only update if status has changed.
|
||||
if (status == NANO_DISABLED)
|
||||
status = state
|
||||
if (push)
|
||||
update()
|
||||
else
|
||||
status = state
|
||||
if (push || status == 0) // Force an update if NANO_DISABLED.
|
||||
push_data(null, 1)
|
||||
|
||||
/**
|
||||
* private
|
||||
*
|
||||
* Update the status/visibility of the NanoUI for its user.
|
||||
*
|
||||
* optional push bool Push an update to the UI (an update is always sent for NANO_DISABLED).
|
||||
**/
|
||||
/datum/nanoui/proc/update_status(push = 0)
|
||||
var/new_status = src_object.CanUseTopic(user, state)
|
||||
if(master_ui)
|
||||
new_status = min(new_status, master_ui.status)
|
||||
|
||||
set_status(new_status, push)
|
||||
if(new_status == NANO_CLOSE)
|
||||
close()
|
||||
/**
|
||||
* NanoUI
|
||||
*
|
||||
* Contains the NanoUI datum, and its procs.
|
||||
*
|
||||
* /tg/station user interface library
|
||||
* thanks to baystation12
|
||||
*
|
||||
* modified by neersighted
|
||||
**/
|
||||
|
||||
/**
|
||||
* NanoUI datum:
|
||||
*
|
||||
* Represents a NanoUI.
|
||||
**/
|
||||
/datum/nanoui
|
||||
var/mob/user // The mob who opened/is using the NanoUI.
|
||||
var/atom/movable/src_object // The object which owns the NanoUI.
|
||||
var/title // The title of te NanoUI.
|
||||
var/ui_key // The ui_key of the NanoUI. This allows multiple UIs for one src_object.
|
||||
var/window_id // The window_id for browse() and onclose().
|
||||
var/width = 0 // The window width.
|
||||
var/height = 0 // The window height
|
||||
var/window_options = list( // Extra options to winset().
|
||||
"focus" = 0,
|
||||
"titlebar" = 1,
|
||||
"can_resize" = 1,
|
||||
"can_minimize" = 1,
|
||||
"can_maximize" = 0,
|
||||
"can_close" = 1,
|
||||
"auto_format" = 0
|
||||
)
|
||||
var/atom/ref = null // An extra ref to call when the window is closed.
|
||||
var/layout = "nanotrasen" // The layout to be used for this UI.
|
||||
var/template // The template to be used for this UI.
|
||||
var/auto_update = 1 // Update the NanoUI every MC tick.
|
||||
var/list/initial_data // The data (and datastructure) used to initialize the NanoUI
|
||||
var/status = NANO_INTERACTIVE // The status/visibility of the NanoUI.
|
||||
var/datum/topic_state/state = null // Topic state used to determine status. Topic states are in interactions/.
|
||||
var/datum/nanoui/master_ui // The parent NanoUI.
|
||||
var/list/datum/nanoui/children = list() // Children of this NanoUI.
|
||||
|
||||
/**
|
||||
* public
|
||||
*
|
||||
* Create a new NanoUI.
|
||||
*
|
||||
* required user mob The mob who opened/is using the NanoUI.
|
||||
* required src_object atom/movable The object which owns the NanoUI.
|
||||
* required ui_key string The ui_key of the NanoUI.
|
||||
* required template string The template to render the NanoUI content with.
|
||||
* optional title string The title of the NanoUI.
|
||||
* optional width int The window width.
|
||||
* optional height int The window height.
|
||||
* optional ref atom An extra ref to use when the window is closed.
|
||||
* optional master_ui datum/nanoui The parent NanoUI.
|
||||
* optional state datum/topic_state The state used to determine status.
|
||||
*
|
||||
* return datum/nanoui The requested NanoUI.
|
||||
**/
|
||||
/datum/nanoui/New(mob/user, atom/movable/src_object, ui_key, template, \
|
||||
title = 0, width = 0, height = 0, \
|
||||
atom/ref = null, datum/nanoui/master_ui = null, \
|
||||
datum/topic_state/state = default_state)
|
||||
src.user = user
|
||||
src.src_object = src_object
|
||||
src.ui_key = ui_key
|
||||
src.window_id = "\ref[src_object]-[ui_key]"
|
||||
|
||||
set_template(template)
|
||||
|
||||
if (title)
|
||||
src.title = sanitize(title)
|
||||
if (width)
|
||||
src.width = width
|
||||
if (height)
|
||||
src.height = height
|
||||
|
||||
if (ref)
|
||||
src.ref = ref
|
||||
|
||||
src.master_ui = master_ui
|
||||
if(master_ui)
|
||||
master_ui.children += src
|
||||
src.state = state
|
||||
|
||||
var/datum/asset/assets = get_asset_datum(/datum/asset/simple/nanoui)
|
||||
assets.send(user)
|
||||
|
||||
/**
|
||||
* public
|
||||
*
|
||||
* Open this NanoUI (and initialize it with data).
|
||||
*
|
||||
* optional data list The data to intialize the UI with.
|
||||
**/
|
||||
/datum/nanoui/proc/open(list/data = null)
|
||||
if(!user.client)
|
||||
return // Bail if there is no client.
|
||||
if (status == NANO_CLOSE)
|
||||
return // Bail if we should close.
|
||||
|
||||
if (!initial_data)
|
||||
if (!data) // If we don't have initial_data and data was not passed, get data from the src_object.
|
||||
data = src_object.get_ui_data(user)
|
||||
set_initial_data(data) // Otherwise use the passed data.
|
||||
|
||||
var/window_size = ""
|
||||
if (width && height) // If we have a width and height, use them.
|
||||
window_size = "size=[width]x[height];"
|
||||
update_status(push = 0) // Update the window state.
|
||||
|
||||
user << browse(get_html(), "window=[window_id];[window_size][list2params(window_options)]") // Open the window.
|
||||
winset(user, window_id, "on-close=\"nanoclose \ref[src]\"") // Instruct the client to signal NanoUI when the window is closed.
|
||||
SSnano.on_open(src)
|
||||
|
||||
/**
|
||||
* public
|
||||
*
|
||||
* Reinitialize the NanoUI.
|
||||
* (Possibly with a new template and/or data).
|
||||
*
|
||||
* optional template string The filename of the new template.
|
||||
* optional data list The new initial data.
|
||||
**/
|
||||
/datum/nanoui/proc/reinitialize(template, list/data)
|
||||
if(template)
|
||||
set_template(template) // Set a new template.
|
||||
if(data)
|
||||
set_initial_data(data) // Replace the initial_data.
|
||||
open()
|
||||
|
||||
/**
|
||||
* public
|
||||
*
|
||||
* Close the NanoUI, and all its children.
|
||||
**/
|
||||
/datum/nanoui/proc/close()
|
||||
set_auto_update(0) // Disable auto-updates.
|
||||
user << browse(null, "window=[window_id]") // Close the window.
|
||||
SSnano.on_close(src)
|
||||
for(var/datum/nanoui/child in children) // Loop through and close all children.
|
||||
child.close()
|
||||
|
||||
/**
|
||||
* public
|
||||
*
|
||||
* Sets the browse() window options for this NanoUI.
|
||||
*
|
||||
* required window_options list The window options to set.
|
||||
**/
|
||||
/datum/nanoui/proc/set_window_options(list/window_options)
|
||||
src.window_options = window_options
|
||||
|
||||
/**
|
||||
* public
|
||||
*
|
||||
* Set the layout for this NanoUI.
|
||||
* This loads custom layout styles and templates for this NanoUI.
|
||||
*
|
||||
* required layout string The new UI layout.
|
||||
**/
|
||||
/datum/nanoui/proc/set_layout(layout)
|
||||
src.layout = lowertext(layout)
|
||||
|
||||
/**
|
||||
* public
|
||||
*
|
||||
* Set the template for this NanoUI.
|
||||
*
|
||||
* required template string The new UI template.
|
||||
**/
|
||||
/datum/nanoui/proc/set_template(template)
|
||||
src.template = lowertext(template)
|
||||
|
||||
/**
|
||||
* public
|
||||
*
|
||||
* Enable/disable auto-updating of the NanoUI.
|
||||
*
|
||||
* required state bool Enable/disable auto-updating.
|
||||
**/
|
||||
/datum/nanoui/proc/set_auto_update(state = 1)
|
||||
auto_update = state
|
||||
|
||||
/**
|
||||
* private
|
||||
*
|
||||
* Set the data to initialize the NanoUI with.
|
||||
* The datastructure cannot be changed by subsequent updates.
|
||||
*
|
||||
* optional data list The data/datastructure to initialize the NanoUI with.
|
||||
**/
|
||||
/datum/nanoui/proc/set_initial_data(list/data)
|
||||
initial_data = data
|
||||
|
||||
/**
|
||||
* private
|
||||
*
|
||||
* Generate HTML for this NanoUI.
|
||||
*
|
||||
* return string NanoUI HTML output.
|
||||
**/
|
||||
/datum/nanoui/proc/get_html()
|
||||
// Generate <script> and <link> tags.
|
||||
var/script_html = {"
|
||||
<script type='text/javascript' src='nanoui.js'></script>
|
||||
"}
|
||||
var/stylesheet_html = {"
|
||||
<link rel='stylesheet' type='text/css' href='http://css-spinners.com/css/spinner/hexdots.css' />
|
||||
<link rel='stylesheet' type='text/css' href='nanoui.css' />
|
||||
<link rel='stylesheet' type='text/css' href='https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.5.0/css/font-awesome.min.css' />
|
||||
"}
|
||||
|
||||
// Generate JSON.
|
||||
var/list/send_data = get_send_data(initial_data)
|
||||
var/initial_data_json = replacetext(JSON.stringify(send_data), "'", "'")
|
||||
|
||||
// Generate the HTML document.
|
||||
return {"
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv='X-UA-Compatible' content='IE=edge'>
|
||||
<script type='text/javascript'>
|
||||
function receiveUpdate(dataString) {
|
||||
if (typeof NanoBus !== 'undefined') {
|
||||
NanoBus.emit('serverUpdate', dataString);
|
||||
}
|
||||
};
|
||||
</script>
|
||||
[stylesheet_html]
|
||||
[script_html]
|
||||
</head>
|
||||
<body class='[layout]'>
|
||||
<div id='data' data-initial='[initial_data_json]'></div>
|
||||
<div id='layout'>
|
||||
<div class='hexdots-loader' style='position:fixed;top:50%;left:50%;transform:translate(-50%, -50%);-ms-transform:translate(-50%, -50%);'>
|
||||
Sending Resources...
|
||||
</div>
|
||||
</div>
|
||||
<noscript>
|
||||
<h1>Javascript Required</h1>
|
||||
<p>Javascript is required in order to use this NanoUI interface.</p>
|
||||
<p>Please enable Javascript in Internet Explorer, and restart your game.</p>
|
||||
</noscript>
|
||||
</body>
|
||||
</html>
|
||||
"}
|
||||
|
||||
/**
|
||||
* private
|
||||
*
|
||||
* Get the config data/datastructure to initialize the NanoUI with.
|
||||
*
|
||||
* return list The config data.
|
||||
**/
|
||||
/datum/nanoui/proc/get_config_data()
|
||||
var/list/config_data = list(
|
||||
"title" = title,
|
||||
"status" = status,
|
||||
"ref" = "\ref[src]",
|
||||
"window" = list(
|
||||
"width" = width,
|
||||
"height" = height,
|
||||
"ref" = window_id
|
||||
),
|
||||
"user" = list(
|
||||
"name" = user.name,
|
||||
"fancy" = user.client.prefs.nanoui_fancy,
|
||||
"ref" = "\ref[user]"
|
||||
),
|
||||
"srcObject" = list(
|
||||
"name" = src_object.name,
|
||||
"ref" = "\ref[src_object]"
|
||||
),
|
||||
"templates" = list(
|
||||
"layout" = "_[layout]",
|
||||
"content" = "[template]"
|
||||
)
|
||||
)
|
||||
return config_data
|
||||
|
||||
/**
|
||||
* private
|
||||
*
|
||||
* Package the data to send to the UI.
|
||||
* This is the (regular) data and config data, bundled together.
|
||||
*
|
||||
* return list The packaged data.
|
||||
**/
|
||||
/datum/nanoui/proc/get_send_data(list/data)
|
||||
var/list/send_data = list()
|
||||
|
||||
send_data["config"] = get_config_data()
|
||||
if (!isnull(data))
|
||||
send_data["data"] = data
|
||||
|
||||
return send_data
|
||||
|
||||
/**
|
||||
* private
|
||||
*
|
||||
* Handle clicks from the NanoUI.
|
||||
* Call the src_object's Topic() if status is NANO_INTERACTIVE.
|
||||
* If the src_object's Topic() returns 1, update all UIs attacked to it.
|
||||
**/
|
||||
/datum/nanoui/Topic(href, href_list)
|
||||
update_status(push = 0) // Update the window state.
|
||||
if (status != NANO_INTERACTIVE || user != usr)
|
||||
return // If UI is not interactive or usr calling Topic is not the UI user.
|
||||
|
||||
var/action = href_list["nano"] // Pull the action out.
|
||||
href_list -= "nano"
|
||||
|
||||
var/update = src_object.ui_act(action, href_list, state) // Call Topic() on the src_object.
|
||||
|
||||
if (src_object && update)
|
||||
SSnano.update_uis(src_object) // If we have a src_object and its Topic() told us to update.
|
||||
|
||||
/**
|
||||
* private
|
||||
*
|
||||
* Update the NanoUI. Only updates the contents/layout if update is true,
|
||||
* otherwise only updates the status.
|
||||
*
|
||||
* optional force bool If the UI should be forced to update.
|
||||
**/
|
||||
/datum/nanoui/process(force = 0)
|
||||
if (!src_object || !user) // If the object or user died (or something else), abort.
|
||||
close()
|
||||
return
|
||||
|
||||
if (status && (force || auto_update))
|
||||
update() // Update the UI if the status and update settings allow it.
|
||||
else
|
||||
update_status(push = 1) // Otherwise only update status.
|
||||
|
||||
/**
|
||||
* private
|
||||
*
|
||||
* Push data to an already open NanoUI.
|
||||
*
|
||||
* required data list The data to send.
|
||||
* optional force bool If the update should be sent regardless of state.
|
||||
**/
|
||||
/datum/nanoui/proc/push_data(data, force = 0)
|
||||
update_status(push = 0) // Update the window state.
|
||||
if (status == NANO_DISABLED && !force)
|
||||
return // Cannot update UI, we have no visibility.
|
||||
|
||||
var/list/send_data = get_send_data(data) // Get the data to send.
|
||||
|
||||
// Send the new data to the recieveUpdate() Javascript function.
|
||||
user << output(list2params(list(JSON.stringify(send_data))), "[window_id].browser:receiveUpdate")
|
||||
|
||||
|
||||
/**
|
||||
* private
|
||||
*
|
||||
* Updates the UI by interacting with the src_object again, which will hopefully
|
||||
* call try_ui_update on it.
|
||||
*
|
||||
* optional force_open bool If force_open should be passed to ui_interact.
|
||||
**/
|
||||
/datum/nanoui/proc/update(force_open = 0)
|
||||
src_object.ui_interact(user, ui_key, src, force_open, master_ui, state)
|
||||
|
||||
/**
|
||||
* private
|
||||
*
|
||||
* Update the status/visibility of the NanoUI for its user.
|
||||
*
|
||||
* optional push bool Push an update to the UI (an update is always sent for NANO_DISABLED).
|
||||
**/
|
||||
/datum/nanoui/proc/update_status(push = 0)
|
||||
var/new_status = src_object.nano_state(user, state)
|
||||
if(master_ui)
|
||||
new_status = min(new_status, master_ui.status)
|
||||
|
||||
set_status(new_status, push)
|
||||
if(new_status == NANO_CLOSE)
|
||||
close()
|
||||
|
||||
/**
|
||||
* private
|
||||
*
|
||||
* Set the status/visibility of the NanoUI.
|
||||
*
|
||||
* required state int The status to set (NANO_CLOSE/NANO_DISABLED/NANO_UPDATE/NANO_INTERACTIVE).
|
||||
* optional push bool Push an update to the UI (an update is always sent for NANO_DISABLED).
|
||||
**/
|
||||
/datum/nanoui/proc/set_status(state, push = 0)
|
||||
if (state != status) // Only update if status has changed.
|
||||
if (status == NANO_DISABLED)
|
||||
status = state
|
||||
if (push)
|
||||
update()
|
||||
else
|
||||
status = state
|
||||
if (push || status == 0) // Force an update if NANO_DISABLED.
|
||||
push_data(null, 1)
|
||||
@@ -14,7 +14,7 @@
|
||||
*
|
||||
* return NANO_state The state of the UI.
|
||||
**/
|
||||
/atom/proc/CanUseTopic(mob/user, datum/topic_state/state)
|
||||
/atom/proc/nano_state(mob/user, datum/topic_state/state)
|
||||
var/src_object = nano_host()
|
||||
return state.can_use_topic(src_object, user) // Check if the state allows interaction.
|
||||
|
||||
|
||||
@@ -158,7 +158,7 @@
|
||||
*
|
||||
* required ui datum/nanoui The UI to be added.
|
||||
**/
|
||||
/datum/subsystem/nano/proc/ui_opened(datum/nanoui/ui)
|
||||
/datum/subsystem/nano/proc/on_open(datum/nanoui/ui)
|
||||
var/src_object_key = "\ref[ui.src_object]"
|
||||
if (isnull(open_uis[src_object_key]) || !istype(open_uis[src_object_key], /list))
|
||||
open_uis[src_object_key] = list(ui.ui_key = list()) // Make a list for the ui_key and src_object.
|
||||
@@ -180,7 +180,7 @@
|
||||
*
|
||||
* return bool If the UI was removed or not.
|
||||
**/
|
||||
/datum/subsystem/nano/proc/ui_closed(datum/nanoui/ui)
|
||||
/datum/subsystem/nano/proc/on_close(datum/nanoui/ui)
|
||||
var/src_object_key = "\ref[ui.src_object]"
|
||||
if (isnull(open_uis[src_object_key]) || !istype(open_uis[src_object_key], /list))
|
||||
return 0 // It wasn't open.
|
||||
@@ -203,7 +203,7 @@
|
||||
*
|
||||
* return int The number of NanoUIs closed.
|
||||
**/
|
||||
/datum/subsystem/nano/proc/user_logout(mob/user)
|
||||
/datum/subsystem/nano/proc/on_logout(mob/user)
|
||||
return close_user_uis(user)
|
||||
|
||||
/**
|
||||
@@ -216,7 +216,7 @@
|
||||
*
|
||||
* return bool If the NanoUIs were transferred.
|
||||
**/
|
||||
/datum/subsystem/nano/proc/user_transferred(mob/oldMob, mob/newMob)
|
||||
/datum/subsystem/nano/proc/on_transfer(mob/oldMob, mob/newMob)
|
||||
if (!oldMob || isnull(oldMob.open_uis) || !istype(oldMob.open_uis, /list) || open_uis.len == 0)
|
||||
return 0 // The old mob had no open NanoUIs.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user