Skip to content
This repository has been archived by the owner on Jan 1, 2025. It is now read-only.

Commit

Permalink
tgui: Fixes assets, CDN support (tgstation#52321)
Browse files Browse the repository at this point in the history
* tgui: Better asset code, CDN support

* Rebuild tgui

* µ-fix
  • Loading branch information
stylemistake authored Jul 19, 2020
1 parent b057982 commit 8a12f15
Show file tree
Hide file tree
Showing 19 changed files with 131 additions and 84 deletions.
2 changes: 0 additions & 2 deletions code/__DEFINES/tgui.dm
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,6 @@
#define TGUI_WINDOW_LOADING 1
/// Window is free and ready to receive data
#define TGUI_WINDOW_READY 2
/// Window is in use by a tgui datum
#define TGUI_WINDOW_ACTIVE 3

/// Get a window id based on the provided pool index
#define TGUI_WINDOW_ID(index) "tgui-window-[index]"
Expand Down
10 changes: 4 additions & 6 deletions code/modules/asset_cache/asset_list.dm
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ GLOBAL_LIST_EMPTY(asset_datums)
if (!ACI)
continue
.[asset_name] = ACI.url


// For registering or sending multiple others at once
/datum/asset/group
Expand Down Expand Up @@ -86,18 +86,16 @@ GLOBAL_LIST_EMPTY(asset_datums)
if (!name)
CRASH("spritesheet [type] cannot register without a name")
ensure_stripped()

for(var/size_id in sizes)
var/size = sizes[size_id]
register_asset("[name]_[size_id].png", size[SPRSZ_STRIPPED])
var/res_name = "spritesheet_[name].css"
var/fname = "data/spritesheets/[res_name]"
fdel(fname)
text2file(generate_css(), fname)
register_asset(res_name, fcopy_rsc(fname))
fdel(fname)

for(var/size_id in sizes)
var/size = sizes[size_id]
register_asset("[name]_[size_id].png", size[SPRSZ_STRIPPED])

/datum/asset/spritesheet/send(client/C)
if (!name)
return
Expand Down
6 changes: 0 additions & 6 deletions code/modules/asset_cache/asset_list_items.dm
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,6 @@
"tgui.bundle.css" = 'tgui/packages/tgui/public/tgui.bundle.css',
)

/datum/asset/group/tgui
children = list(
/datum/asset/simple/tgui,
/datum/asset/simple/fontawesome
)

/datum/asset/simple/headers
assets = list(
"alarm_green.gif" = 'icons/program_icons/alarm_green.gif',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,9 @@
ui = SStgui.try_update_ui(user, src, ui)
if (!ui)
ui = new(user, src, "NtosMain")
ui.send_asset(get_asset_datum(/datum/asset/simple/headers))
ui.set_autoupdate(TRUE)
ui.open()
ui.send_asset(get_asset_datum(/datum/asset/simple/headers))


/obj/item/modular_computer/ui_data(mob/user)
Expand Down
2 changes: 1 addition & 1 deletion code/modules/modular_computers/file_system/program.dm
Original file line number Diff line number Diff line change
Expand Up @@ -170,8 +170,8 @@
ui = SStgui.try_update_ui(user, src, ui)
if(!ui && tgui_id)
ui = new(user, src, tgui_id, filedesc)
ui.send_asset(get_asset_datum(/datum/asset/simple/headers))
ui.open()
ui.send_asset(get_asset_datum(/datum/asset/simple/headers))

// CONVENTIONS, READ THIS WHEN CREATING NEW PROGRAM AND OVERRIDING THIS PROC:
// Topic calls are automagically forwarded from NanoModule this program contains.
Expand Down
23 changes: 9 additions & 14 deletions code/modules/tgui/tgui.dm
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,6 @@
var/status = UI_INTERACTIVE
/// Topic state used to determine status/interactability.
var/datum/ui_state/state = null
/// Asset data to be sent with every update
var/list/asset_data

/**
* public
Expand Down Expand Up @@ -82,11 +80,14 @@
opened_at = world.time
window.acquire_lock(src)
if(!window.is_ready())
window.initialize()
window.initialize(inline_assets = list(
get_asset_datum(/datum/asset/simple/tgui),
))
else
window.send_message("ping")
window.send_asset(get_asset_datum(/datum/asset/simple/fontawesome))
for(var/datum/asset/asset in src_object.ui_assets(user))
send_asset(asset)
window.send_asset(asset)
window.send_message("update", get_payload(
with_data = TRUE,
with_static_data = TRUE))
Expand Down Expand Up @@ -143,14 +144,10 @@
*
* required asset datum/asset
*/
/datum/tgui/proc/send_asset(var/datum/asset/asset)
if(!user.client)
return
if(istype(asset, /datum/asset/spritesheet))
var/datum/asset/spritesheet/spritesheet = asset
LAZYINITLIST(asset_data)
LAZYADD(asset_data["styles"], list(spritesheet.css_filename()))
asset.send(user)
/datum/tgui/proc/send_asset(datum/asset/asset)
if(!window)
CRASH("send_asset() can only be called after open().")
window.send_asset(asset)

/**
* public
Expand Down Expand Up @@ -216,8 +213,6 @@
var/static_data = with_static_data && src_object.ui_static_data(user)
if(static_data)
json_data["static_data"] = static_data
if(asset_data)
json_data["assets"] = asset_data
if(src_object.tgui_shared_states)
json_data["shared"] = src_object.tgui_shared_states
return json_data
Expand Down
57 changes: 47 additions & 10 deletions code/modules/tgui/tgui_window.dm
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
var/datum/tgui/locked_by
var/fatally_errored = FALSE
var/message_queue
var/sent_assets = list()

/**
* public
Expand All @@ -36,8 +37,10 @@
* Initializes the window with a fresh page. Puts window into the "loading"
* state. You can begin sending messages right after initializing. Messages
* will be put into the queue until the window finishes loading.
*
* optional inline_assets list List of assets to inline into the html.
*/
/datum/tgui_window/proc/initialize()
/datum/tgui_window/proc/initialize(inline_assets = list())
log_tgui(client, "[id]/initialize")
if(!client)
return
Expand All @@ -52,13 +55,23 @@
else
options += "titlebar=1;can_resize=1;"
// Generate page html
// TODO: Make this static
var/html = SStgui.basehtml
html = replacetextEx(html, "\[tgui:windowId]", id)
// Send required assets
var/datum/asset/asset
asset = get_asset_datum(/datum/asset/group/tgui)
asset.send(client)
// Process inline assets
var/inline_styles = ""
var/inline_scripts = ""
for(var/datum/asset/asset in inline_assets)
var/mappings = asset.get_url_mappings()
for(var/name in mappings)
var/url = mappings[name]
// Not urlencoding since asset strings are considered safe
if(copytext(name, -4) == ".css")
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()
html = replacetextEx(html, "<!-- tgui:styles -->\n", inline_styles)
html = replacetextEx(html, "<!-- tgui:scripts -->\n", inline_scripts)
// Open the window
client << browse(html, "window=[id];[options]")
// Instruct the client to signal UI when the window is closed.
Expand Down Expand Up @@ -86,7 +99,7 @@
&& pooled \
&& pool_index > 0 \
&& pool_index <= TGUI_WINDOW_SOFT_LIMIT \
&& status >= TGUI_WINDOW_READY
&& status == TGUI_WINDOW_READY

/**
* public
Expand All @@ -107,6 +120,9 @@
* Release the window lock.
*/
/datum/tgui_window/proc/release_lock()
// Clean up assets sent by tgui datum which requested the lock
if(locked)
sent_assets = list()
locked = FALSE
locked_by = null

Expand All @@ -126,8 +142,7 @@
send_message("suspend")
return
log_tgui(client, "[id]/close")
locked = FALSE
locked_by = null
release_lock()
status = TGUI_WINDOW_CLOSED
message_queue = null
// Do not close the window to give user some time
Expand Down Expand Up @@ -157,13 +172,30 @@
// Pack for sending via output()
message = url_encode(message)
// Place into queue if window is still loading
if(!force && status == TGUI_WINDOW_LOADING)
if(!force && status != TGUI_WINDOW_READY)
if(!message_queue)
message_queue = list()
message_queue += list(message)
return
client << output(message, "[id].browser:update")

/**
* public
*
* Makes an asset available to use in tgui.
*
* required asset datum/asset
*/
/datum/tgui_window/proc/send_asset(datum/asset/asset)
if(!client || !asset)
return
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
*
Expand All @@ -184,6 +216,11 @@
/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"])
Expand Down
4 changes: 2 additions & 2 deletions tgui/packages/tgui-dev-server/link/client.js
Original file line number Diff line number Diff line change
Expand Up @@ -98,8 +98,8 @@ const sendRawMessage = msg => {
socket.send(json);
}
else {
// Keep only 10 latest messages in the queue
if (queue.length > 10) {
// Keep only 100 latest messages in the queue
if (queue.length > 100) {
queue.shift();
}
queue.push(json);
Expand Down
45 changes: 38 additions & 7 deletions tgui/packages/tgui/assets.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,46 @@ import { createLogger } from './logging';

const logger = createLogger('assets');

const loadedAssets = {
styles: [],
const EXCLUDED_PATTERNS = [
/v4shim/i,
];

const loadedStyles = [];
const loadedMappings = {};

export const loadCSS = url => {
if (loadedStyles.includes(url)) {
return;
}
loadedStyles.push(url);
logger.log(`loading stylesheet '${url}'`);
fgLoadCSS(url);
};

export const loadCSS = filename => {
if (loadedAssets.styles.includes(filename)) {
export const resolveAsset = name => (
loadedMappings[name] || name
);

export const assetMiddleware = store => next => action => {
const { type, payload } = action;
if (type === 'asset/stylesheet') {
loadCSS(payload);
return;
}
if (type === 'asset/mappings') {
for (let name of Object.keys(payload)) {
// Skip anything that matches excluded patterns
if (EXCLUDED_PATTERNS.some(regex => regex.test(name))) {
continue;
}
const url = payload[name];
const ext = name.split('.').pop();
loadedMappings[name] = url;
if (ext === 'css') {
loadCSS(url);
}
}
return;
}
loadedAssets.styles.push(filename);
logger.log(`loading stylesheet '${filename}'`);
fgLoadCSS(filename);
next(action);
};
2 changes: 0 additions & 2 deletions tgui/packages/tgui/backend.js
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,6 @@ export const backendReducer = (state = initialState, action) => {
return {
...state,
config,
assets: payload.assets || {},
data,
shared,
visible,
Expand Down Expand Up @@ -253,7 +252,6 @@ export const sendAct = (action, payload = {}) => {
* },
* },
* data: any,
* assets: any,
* shared: any,
* visible: boolean,
* interactive: boolean,
Expand Down
12 changes: 3 additions & 9 deletions tgui/packages/tgui/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ import './styles/themes/syndicate.scss';
import { perf } from 'common/perf';
import { render } from 'inferno';
import { setupHotReloading } from 'tgui-dev-server/link/client';
import { loadCSS } from './assets';
import { backendUpdate, backendSuspendSuccess, selectBackend, sendMessage } from './backend';
import { setupDrag } from './drag';
import { logger } from './logging';
Expand Down Expand Up @@ -96,8 +95,6 @@ const renderLayout = () => {
if (initialRender) {
initialRender = false;
}
// Load assets
assets?.styles?.forEach(filename => loadCSS(filename));
};

// Parse JSON and report all abnormal JSON strings coming from BYOND
Expand Down Expand Up @@ -143,9 +140,8 @@ const setupApp = () => {
logger.debug(`received message '${message?.type}'`);
const { type, payload } = message;
if (type === 'update') {
window.__ref__ = payload.config.ref;
if (suspended) {
logger.log('reinitializing to:', payload.config.ref);
logger.log('resuming');
initialRender = 'recycled';
}
// Backend update dispatches a store action
Expand All @@ -162,7 +158,8 @@ const setupApp = () => {
});
return;
}
logger.log('unhandled message', message);
// Pass the message directly to the store
store.dispatch(message);
};

// Enable hot module reloading
Expand All @@ -185,9 +182,6 @@ const setupApp = () => {
}
window.update(stateJson);
}

// Dynamically load font-awesome from browser's cache
loadCSS('font-awesome.css');
};

// Setup a fatal error reporter
Expand Down
3 changes: 2 additions & 1 deletion tgui/packages/tgui/interfaces/DnaConsole.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { flow } from 'common/fp';
import { classes } from 'common/react';
import { capitalize } from 'common/string';
import { Fragment } from 'inferno';
import { resolveAsset } from '../assets';
import { useBackend } from '../backend';
import { Box, Button, Collapsible, Dimmer, Divider, Dropdown, Flex, Icon, LabeledList, NumberInput, ProgressBar, Section } from '../components';
import { Window } from '../layouts';
Expand Down Expand Up @@ -777,7 +778,7 @@ const DnaConsoleSequencer = (props, context) => {
{mutations.map(mutation => (
<GenomeImage
key={mutation.Alias}
url={mutation.Image}
url={resolveAsset(mutation.Image)}
selected={mutation.Alias === sequencerMutation}
onClick={() => {
act('set_view', {
Expand Down
Loading

0 comments on commit 8a12f15

Please sign in to comment.