Merge pull request #14189 from ItsSelis/tgui-strict-mode

Adds tgui strict mode
This commit is contained in:
Heroman3003
2022-12-12 05:24:37 +10:00
committed by CHOMPStation2
parent 7566c3306c
commit 4be9009e01
4 changed files with 89 additions and 44 deletions

View File

@@ -95,6 +95,7 @@
window.acquire_lock(src) window.acquire_lock(src)
if(!window.is_ready()) if(!window.is_ready())
window.initialize( window.initialize(
strict_mode = TRUE,
fancy = user.client.prefs.tgui_fancy, fancy = user.client.prefs.tgui_fancy,
assets = list( assets = list(
get_asset_datum(/datum/asset/simple/tgui), get_asset_datum(/datum/asset/simple/tgui),

View File

@@ -18,6 +18,7 @@
var/message_queue var/message_queue
var/sent_assets = list() var/sent_assets = list()
// Vars passed to initialize proc (and saved for later) // Vars passed to initialize proc (and saved for later)
var/initial_strict_mode
var/initial_fancy var/initial_fancy
var/initial_assets var/initial_assets
var/initial_inline_html var/initial_inline_html
@@ -48,11 +49,15 @@
* state. You can begin sending messages right after initializing. Messages * state. You can begin sending messages right after initializing. Messages
* will be put into the queue until the window finishes loading. * will be put into the queue until the window finishes loading.
* *
* optional assets list List of assets to inline into the html. * optional strict_mode bool - Enables strict error handling and BSOD.
* optional inline_html string Custom HTML to inject. * optional fancy bool - If TRUE and if this is NOT a panel, will hide the window titlebar.
* optional fancy bool If TRUE, 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( /datum/tgui_window/proc/initialize(
strict_mode = FALSE,
fancy = FALSE, fancy = FALSE,
assets = list(), assets = list(),
inline_html = "", inline_html = "",
@@ -80,6 +85,7 @@
// Generate page html // Generate page html
var/html = SStgui.basehtml var/html = SStgui.basehtml
html = replacetextEx(html, "\[tgui:windowId]", id) html = replacetextEx(html, "\[tgui:windowId]", id)
html = replacetextEx(html, "\[tgui:strictMode]", strict_mode)
// Inject assets // Inject assets
var/inline_assets_str = "" var/inline_assets_str = ""
for(var/datum/asset/asset in assets) for(var/datum/asset/asset in assets)
@@ -100,7 +106,7 @@
html = replacetextEx(html, "<!-- tgui:inline-html -->", inline_html) html = replacetextEx(html, "<!-- tgui:inline-html -->", inline_html)
// Inject inline JS // Inject inline JS
if (inline_js) if (inline_js)
inline_js = "<script>\n[inline_js]\n</script>" inline_js = "<script>\n'use strict';\n[inline_js]\n</script>"
html = replacetextEx(html, "<!-- tgui:inline-js -->", inline_js) html = replacetextEx(html, "<!-- tgui:inline-js -->", inline_js)
// Inject inline CSS // Inject inline CSS
if (inline_css) if (inline_css)
@@ -114,6 +120,20 @@
if(!is_browser) if(!is_browser)
winset(client, id, "on-close=\"uiclose [id]\"") 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)
/** /**
* public * public
* *
@@ -353,12 +373,7 @@
client << link(href_list["url"]) client << link(href_list["url"])
if("cacheReloaded") if("cacheReloaded")
// Reinitialize // Reinitialize
initialize( reinitialize()
fancy = initial_fancy,
assets = initial_assets,
inline_html = initial_inline_html,
inline_js = initial_inline_js,
inline_css = initial_inline_css)
// Resend the assets // Resend the assets
for(var/asset in sent_assets) for(var/asset in sent_assets)
send_asset(asset) send_asset(asset)

12
tgui/global.d.ts vendored
View File

@@ -64,6 +64,18 @@ type ByondType = {
*/ */
IS_LTE_IE11: boolean; IS_LTE_IE11: boolean;
/**
* If `true`, unhandled errors and common mistakes result in a blue screen
* of death, which stops this window from handling incoming messages and
* closes the active instance of tgui datum if there was one.
*
* It can be defined in window.initialize() in DM, or changed in runtime
* here via this property to `true` or `false`.
*
* It is recommended that you keep this ON to detect hard to find bugs.
*/
strictMode: boolean;
/** /**
* Makes a BYOND call. * Makes a BYOND call.
* *

View File

@@ -6,6 +6,7 @@
<!-- Inlined metadata --> <!-- Inlined metadata -->
<meta id="tgui:windowId" content="[tgui:windowId]"> <meta id="tgui:windowId" content="[tgui:windowId]">
<meta id="tgui:strictMode" content="[tgui:strictMode]">
<!-- Early setup --> <!-- Early setup -->
<script type="text/javascript"> <script type="text/javascript">
@@ -65,6 +66,9 @@
Byond.IS_LTE_IE10 = Byond.TRIDENT !== null && Byond.TRIDENT <= 6; Byond.IS_LTE_IE10 = Byond.TRIDENT !== null && Byond.TRIDENT <= 6;
Byond.IS_LTE_IE11 = Byond.TRIDENT !== null && Byond.TRIDENT <= 7; Byond.IS_LTE_IE11 = Byond.TRIDENT !== null && Byond.TRIDENT <= 7;
// Strict mode flag
Byond.strictMode = Boolean(Number(parseMetaTag('tgui:strictMode')));
// Callbacks for asynchronous calls // Callbacks for asynchronous calls
Byond.__callbacks__ = []; Byond.__callbacks__ = [];
@@ -221,13 +225,13 @@
}; };
Byond.subscribeTo = function (type, listener) { Byond.subscribeTo = function (type, listener) {
listener = function (_type, payload) { var _listener = function (_type, payload) {
if (_type === type) { if (_type === type) {
listener(payload); listener(payload);
} }
}; };
window.update.listeners.push(listener); window.update.flushQueue(_listener);
window.update.flushQueue(listener); window.update.listeners.push(_listener);
}; };
// Asset loaders // Asset loaders
@@ -365,6 +369,7 @@
// ------------------------------------------------------ // ------------------------------------------------------
window.onerror = function (msg, url, line, col, error) { window.onerror = function (msg, url, line, col, error) {
window.onerror.errorCount = (window.onerror.errorCount || 0) + 1;
// Send fallback command // Send fallback command
Byond.topic({ Byond.topic({
tgui: 1, tgui: 1,
@@ -383,6 +388,7 @@ window.onerror = function (msg, url, line, col, error) {
// Augment the stack // Augment the stack
stack = window.__augmentStack__(stack, error); stack = window.__augmentStack__(stack, error);
// Print error to the page // Print error to the page
if (Byond.strictMode) {
var errorRoot = document.getElementById('FatalError'); var errorRoot = document.getElementById('FatalError');
var errorStack = document.getElementById('FatalError__stack'); var errorStack = document.getElementById('FatalError__stack');
if (errorRoot) { if (errorRoot) {
@@ -400,22 +406,33 @@ window.onerror = function (msg, url, line, col, error) {
var setFatalErrorGeometry = function () { var setFatalErrorGeometry = function () {
Byond.winset(Byond.windowId, { Byond.winset(Byond.windowId, {
titlebar: true, titlebar: true,
size: '600x600',
'is-visible': true, 'is-visible': true,
'can-resize': true, 'can-resize': true,
}); });
}; };
setFatalErrorGeometry(); setFatalErrorGeometry();
setInterval(setFatalErrorGeometry, 1000); setInterval(setFatalErrorGeometry, 1000);
}
// Send logs to the game server // Send logs to the game server
if (Byond.strictMode) {
Byond.sendMessage({ Byond.sendMessage({
type: 'log', type: 'log',
fatal: 1, fatal: 1,
message: stack, message: stack,
}); });
}
else if (window.onerror.errorCount <= 1) {
stack += '\nWindow is in non-strict mode, future errors are suppressed.';
Byond.sendMessage({
type: 'log',
message: stack,
});
}
// Short-circuit further updates // Short-circuit further updates
window.__updateQueue__ = []; if (Byond.strictMode) {
window.update = function () {}; window.update = function () {};
window.update.queue = [];
}
// Prevent default action // Prevent default action
return true; return true;
}; };