diff --git a/code/__defines/_compile_options.dm b/code/__defines/_compile_options.dm index d395c4019a..37fca65861 100644 --- a/code/__defines/_compile_options.dm +++ b/code/__defines/_compile_options.dm @@ -54,3 +54,6 @@ //CHOMPEdit end #endif //ifdef REFERENCE_TRACKING + +// Standard flags to use for browser-options +#define DEFAULT_CLIENT_BROWSER_OPTIONS "byondstorage,find" diff --git a/code/controllers/hooks.dm b/code/controllers/hooks.dm index e7888304e5..293a90aff0 100644 --- a/code/controllers/hooks.dm +++ b/code/controllers/hooks.dm @@ -29,10 +29,10 @@ error("Invalid hook '/hook/[hook]' called.") return 0 - var/caller = new hook_path + var/requester = new hook_path var/status = 1 for(var/P in typesof("[hook_path]/proc")) - if(!call(caller, P)(arglist(args))) + if(!call(requester, P)(arglist(args))) error("Hook '[P]' failed or runtimed.") status = 0 diff --git a/code/game/antagonist/antagonist_panel.dm b/code/game/antagonist/antagonist_panel.dm index 0f42ad5893..8fa2d060f0 100644 --- a/code/game/antagonist/antagonist_panel.dm +++ b/code/game/antagonist/antagonist_panel.dm @@ -17,7 +17,7 @@ /datum/antagonist/proc/get_extra_panel_options() return -/datum/antagonist/proc/get_check_antag_output(var/datum/admins/caller) +/datum/antagonist/proc/get_check_antag_output(var/datum/admins/requester) if(!current_antagonists || !current_antagonists.len) return "" @@ -31,7 +31,7 @@ if(!M.client) dat += " (logged out)" if(M.stat == DEAD) dat += " (DEAD)" dat += "" - dat += "\[PP]\[PM\]\[TP\]" + dat += "\[PP]\[PM\]\[TP\]" else dat += "[player.key] Mob not found!" dat += "" @@ -45,17 +45,17 @@ while(!istype(disk_loc, /turf)) if(istype(disk_loc, /mob)) var/mob/M = disk_loc - dat += "carried by [M.real_name] " + dat += "carried by [M.real_name] " if(istype(disk_loc, /obj)) var/obj/O = disk_loc dat += "in \a [O.name] " disk_loc = disk_loc.loc dat += "in [disk_loc.loc] at ([disk_loc.x], [disk_loc.y], [disk_loc.z])" dat += "" - dat += get_additional_check_antag_output(caller) + dat += get_additional_check_antag_output(requester) dat += "
" return dat //Overridden elsewhere. -/datum/antagonist/proc/get_additional_check_antag_output(var/datum/admins/caller) +/datum/antagonist/proc/get_additional_check_antag_output(var/datum/admins/requester) return "" diff --git a/code/modules/client/client procs.dm b/code/modules/client/client procs.dm index 72c6f5a171..2bcaee9c41 100644 --- a/code/modules/client/client procs.dm +++ b/code/modules/client/client procs.dm @@ -185,6 +185,10 @@ //CONNECT// /////////// /client/New(TopicData) + // TODO: Remove version check with 516 + if(byond_version >= 516) // Enable 516 compat browser storage mechanisms + winset(src, null, "browser-options=[DEFAULT_CLIENT_BROWSER_OPTIONS]") + TopicData = null //Prevent calls to client.Topic from connect if(!(connection in list("seeker", "web"))) //Invalid connection type. @@ -314,6 +318,12 @@ fully_created = TRUE attempt_auto_fit_viewport() + // TODO: Remove version check with 516 + if(byond_version >= 516) + // Now that we're fully initialized, use our prefs + if(prefs?.read_preference(/datum/preference/toggle/browser_dev_tools)) + winset(src, null, "browser-options=[DEFAULT_CLIENT_BROWSER_OPTIONS],devtools") + ////////////// //DISCONNECT// ////////////// diff --git a/code/modules/client/preferences/types/misc.dm b/code/modules/client/preferences/types/misc.dm index 54a85477e3..3efea58893 100644 --- a/code/modules/client/preferences/types/misc.dm +++ b/code/modules/client/preferences/types/misc.dm @@ -81,3 +81,15 @@ savefile_key = "AutoPunctuation" default_value = FALSE savefile_identifier = PREFERENCE_PLAYER + +/datum/preference/toggle/browser_dev_tools + category = PREFERENCE_CATEGORY_GAME_PREFERENCES + savefile_key = "BrowserDevTools" + default_value = FALSE + savefile_identifier = PREFERENCE_PLAYER + +/datum/preference/toggle/browser_dev_tools/apply_to_client(client/client, value) + if(value) + winset(client, null, "browser-options=[DEFAULT_CLIENT_BROWSER_OPTIONS],devtools") + else + winset(client, null, "browser-options=[DEFAULT_CLIENT_BROWSER_OPTIONS]") diff --git a/code/modules/tgui_panel/external.dm b/code/modules/tgui_panel/external.dm index d7545ac6b1..e64660977f 100644 --- a/code/modules/tgui_panel/external.dm +++ b/code/modules/tgui_panel/external.dm @@ -35,6 +35,12 @@ // 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") + // TODO: Remove version check with 516 + if(byond_version >= 516) + if(prefs?.read_preference(/datum/preference/toggle/browser_dev_tools)) + winset(src, null, "browser-options=[DEFAULT_CLIENT_BROWSER_OPTIONS],devtools") + else + winset(src, null, "browser-options=[DEFAULT_CLIENT_BROWSER_OPTIONS]") /client/verb/refresh_tgui() set name = "Refresh TGUI" diff --git a/code/modules/vore/trycatch_vr.dm b/code/modules/vore/trycatch_vr.dm index 396352aadc..fa1b556280 100644 --- a/code/modules/vore/trycatch_vr.dm +++ b/code/modules/vore/trycatch_vr.dm @@ -49,10 +49,10 @@ The hooks you're calling should return nonzero values on success. error("hook_vr: Invalid hook '/hook/[hook]' called.") return 0 - var/caller = new hook_path + var/hook_instance = new hook_path var/status = 1 for(var/P in typesof("[hook_path]/proc")) - if(!call(caller, P)(arglist(args))) + if(!call(hook_instance, P)(arglist(args))) error("hook_vr: Hook '[P]' failed or runtimed.") status = 0 diff --git a/tgui/packages/common/storage.js b/tgui/packages/common/storage.js index 8bc35b0b59..2235199075 100644 --- a/tgui/packages/common/storage.js +++ b/tgui/packages/common/storage.js @@ -7,7 +7,7 @@ */ export const IMPL_MEMORY = 0; -export const IMPL_LOCAL_STORAGE = 1; +export const IMPL_HUB_STORAGE = 1; export const IMPL_INDEXED_DB = 2; const INDEXED_DB_VERSION = 1; @@ -25,14 +25,11 @@ const testGeneric = (testFn) => () => { } }; -// Localstorage can sometimes throw an error, even if DOM storage is not -// disabled in IE11 settings. -// See: https://superuser.com/questions/1080011 -// prettier-ignore -const testLocalStorage = testGeneric(() => ( - window.localStorage && window.localStorage.getItem -)); +const testHubStorage = testGeneric( + () => window.hubStorage && window.hubStorage.getItem, +); +// TODO: Remove with 516 // prettier-ignore const testIndexedDb = testGeneric(() => ( (window.indexedDB || window.msIndexedDB) @@ -45,49 +42,50 @@ class MemoryBackend { this.store = {}; } - get(key) { + async get(key) { return this.store[key]; } - set(key, value) { + async set(key, value) { this.store[key] = value; } - remove(key) { + async remove(key) { this.store[key] = undefined; } - clear() { + async clear() { this.store = {}; } } -class LocalStorageBackend { +class HubStorageBackend { constructor() { - this.impl = IMPL_LOCAL_STORAGE; + this.impl = IMPL_HUB_STORAGE; } - get(key) { - const value = localStorage.getItem(key); + async get(key) { + const value = await window.hubStorage.getItem('chomp-' + key); // CHOMPEdit if (typeof value === 'string') { return JSON.parse(value); } } set(key, value) { - localStorage.setItem(key, JSON.stringify(value)); + window.hubStorage.setItem('chomp-' + key, JSON.stringify(value)); // CHOMPEdit } remove(key) { - localStorage.removeItem(key); + window.hubStorage.removeItem('chomp-' + key); // CHOMPEdit } clear() { - localStorage.clear(); + window.hubStorage.clear(); } } class IndexedDbBackend { + // TODO: Remove with 516 constructor() { this.impl = IMPL_INDEXED_DB; /** @type {Promise} */ @@ -108,7 +106,7 @@ class IndexedDbBackend { }); } - getStore(mode) { + async getStore(mode) { // prettier-ignore return this.dbPromise.then((db) => db .transaction(INDEXED_DB_STORE_NAME, mode) @@ -125,13 +123,6 @@ class IndexedDbBackend { } async set(key, value) { - // The reason we don't _save_ null is because IE 10 does - // not support saving the `null` type in IndexedDB. How - // ironic, given the bug below! - // See: https://github.com/mozilla/localForage/issues/161 - if (value === null) { - value = undefined; - } // NOTE: We deliberately make this operation transactionless const store = await this.getStore(READ_WRITE); store.put(value, key); @@ -157,6 +148,10 @@ class IndexedDbBackend { class StorageProxy { constructor() { this.backendPromise = (async () => { + if (!Byond.TRIDENT && testHubStorage()) { + return new HubStorageBackend(); + } + // TODO: Remove with 516 if (testIndexedDb()) { try { const backend = new IndexedDbBackend(); @@ -164,9 +159,9 @@ class StorageProxy { return backend; } catch {} } - if (testLocalStorage()) { - return new LocalStorageBackend(); - } + console.warn( + 'No supported storage backend found. Using in-memory storage.', + ); return new MemoryBackend(); })(); } diff --git a/tgui/packages/tgui-panel/chat/middleware.js b/tgui/packages/tgui-panel/chat/middleware.js index f1745b353b..d2b55898b7 100644 --- a/tgui/packages/tgui-panel/chat/middleware.js +++ b/tgui/packages/tgui-panel/chat/middleware.js @@ -35,7 +35,7 @@ import { chatRenderer } from './renderer'; import { selectChat, selectCurrentChatPage } from './selectors'; // List of blacklisted tags -const FORBID_TAGS = ['a', 'iframe', 'link', 'video']; +const blacklisted_tags = ['a', 'iframe', 'link', 'video']; let storedRounds = []; let storedLines = []; @@ -72,7 +72,7 @@ const loadChatFromStorage = async (store) => { for (let message of messages) { if (message.html) { message.html = DOMPurify.sanitize(message.html, { - FORBID_TAGS, + FORBID_TAGS: blacklisted_tags, }); } } @@ -90,7 +90,7 @@ const loadChatFromStorage = async (store) => { for (let archivedMessage of archivedMessages) { if (archivedMessage.html) { archivedMessage.html = DOMPurify.sanitize(archivedMessage.html, { - FORBID_TAGS, + FORBID_TAGS: blacklisted_tags, }); } } diff --git a/tgui/packages/tgui-panel/styles/tgchat/chat-dark.scss b/tgui/packages/tgui-panel/styles/tgchat/chat-dark.scss index cb27c044ad..a23afafa9c 100644 --- a/tgui/packages/tgui-panel/styles/tgchat/chat-dark.scss +++ b/tgui/packages/tgui-panel/styles/tgchat/chat-dark.scss @@ -15,7 +15,7 @@ img { margin: 0; padding: 0; line-height: 1; - -ms-interpolation-mode: nearest-neighbor; + -ms-interpolation-mode: nearest-neighbor; // TODO: Remove with 516 image-rendering: pixelated; } @@ -176,12 +176,6 @@ a.popt { padding: 2px 0; } -.filterMessages input { -} - -.filterMessages label { -} - .icon-stack { height: 1em; line-height: 1em; @@ -375,19 +369,6 @@ img.icon.bigicon { font-weight: bold; } -.say, -.emote, -.emotesubtle, -.multizsay, -.npcemote, -.npcsay, -.infoplain, -.oocplain, -.warningplain, -.chatexport, -.body { -} - .warningplain { font-style: italic; } @@ -396,9 +377,6 @@ img.icon.bigicon { font-style: italic; } -.nif { -} - .psay { color: #e300e4; font-style: italic; diff --git a/tgui/packages/tgui-panel/styles/tgchat/chat-light.scss b/tgui/packages/tgui-panel/styles/tgchat/chat-light.scss index e7b4e47ba7..3d6385f904 100644 --- a/tgui/packages/tgui-panel/styles/tgchat/chat-light.scss +++ b/tgui/packages/tgui-panel/styles/tgchat/chat-light.scss @@ -33,7 +33,7 @@ img { margin: 0; padding: 0; line-height: 1; - -ms-interpolation-mode: nearest-neighbor; + -ms-interpolation-mode: nearest-neighbor; // TODO: Remove with 516 image-rendering: pixelated; } @@ -194,12 +194,6 @@ a.popt { padding: 2px 0; } -.filterMessages input { -} - -.filterMessages label { -} - .icon-stack { height: 1em; line-height: 1em; @@ -393,19 +387,6 @@ img.icon.bigicon { font-weight: bold; } -.say, -.emote, -.emotesubtle, -.multizsay, -.npcemote, -.npcsay, -.infoplain, -.oocplain, -.warningplain, -.chatexport, -.body { -} - .warningplain { font-style: italic; } @@ -414,9 +395,6 @@ img.icon.bigicon { font-style: italic; } -.nif { -} - .psay { color: #800080; font-style: italic; diff --git a/tgui/packages/tgui-panel/styles/tgchat/chat-vchatdark.scss b/tgui/packages/tgui-panel/styles/tgchat/chat-vchatdark.scss index 32ab6331d5..5797bc3243 100644 --- a/tgui/packages/tgui-panel/styles/tgchat/chat-vchatdark.scss +++ b/tgui/packages/tgui-panel/styles/tgchat/chat-vchatdark.scss @@ -15,7 +15,7 @@ img { margin: 0; padding: 0; line-height: 1; - -ms-interpolation-mode: nearest-neighbor; + -ms-interpolation-mode: nearest-neighbor; // TODO: Remove with 516 image-rendering: pixelated; } @@ -176,12 +176,6 @@ a.popt { padding: 2px 0; } -.filterMessages input { -} - -.filterMessages label { -} - .icon-stack { height: 1em; line-height: 1em; @@ -375,18 +369,6 @@ img.icon.bigicon { font-weight: bold; } -.say, -.emote, -.emotesubtle, -.multizsay, -.npcemote, -.npcsay, -.infoplain, -.oocplain, -.chatexport, -.body { -} - .warningplain { font-style: italic; } @@ -396,9 +378,6 @@ img.icon.bigicon { color: #ffffff; } -.nif { -} - .psay { color: #e300e4; font-style: italic; diff --git a/tgui/packages/tgui-panel/styles/tgchat/chat-vchatlight.scss b/tgui/packages/tgui-panel/styles/tgchat/chat-vchatlight.scss index fd4c060a7f..eef022ff5b 100644 --- a/tgui/packages/tgui-panel/styles/tgchat/chat-vchatlight.scss +++ b/tgui/packages/tgui-panel/styles/tgchat/chat-vchatlight.scss @@ -33,7 +33,7 @@ img { margin: 0; padding: 0; line-height: 1; - -ms-interpolation-mode: nearest-neighbor; + -ms-interpolation-mode: nearest-neighbor; // TODO: Remove with 516 image-rendering: pixelated; } @@ -194,12 +194,6 @@ a.popt { padding: 2px 0; } -.filterMessages input { -} - -.filterMessages label { -} - .icon-stack { height: 1em; line-height: 1em; @@ -393,19 +387,6 @@ img.icon.bigicon { font-weight: bold; } -.say, -.emote, -.emotesubtle, -.multizsay, -.npcemote, -.npcsay, -.infoplain, -.oocplain, -.warningplain, -.chatexport, -.body { -} - .warningplain { font-style: italic; } @@ -414,9 +395,6 @@ img.icon.bigicon { font-style: italic; } -.nif { -} - .psay { color: #800080; font-style: italic; diff --git a/tgui/packages/tgui-say/TguiSay.tsx b/tgui/packages/tgui-say/TguiSay.tsx index cb11f78e89..9c558c3411 100644 --- a/tgui/packages/tgui-say/TguiSay.tsx +++ b/tgui/packages/tgui-say/TguiSay.tsx @@ -1,4 +1,4 @@ -import { KEY } from 'common/keys'; +import { isEscape, KEY } from 'common/keys'; import { clamp } from 'common/math'; import { BooleanLike } from 'common/react'; import { Component, createRef, RefObject } from 'react'; @@ -31,6 +31,14 @@ type State = { const CHANNEL_REGEX = /^:\w\s|^,b\s/; +const ROWS: Record = { + small: 1, + medium: 2, + large: 3, + max: 6, + width: 1, // not used +} as const; + export class TguiSay extends Component<{}, State> { private channelIterator: ChannelIterator; private chatHistory: ChatHistory; @@ -281,9 +289,10 @@ export class TguiSay extends Component<{}, State> { } break; - case KEY.Escape: - this.handleClose(); - break; + default: + if (isEscape(event.key)) { + this.handleClose(); + } } } @@ -369,11 +378,14 @@ export class TguiSay extends Component<{}, State> { {this.state.buttonContent}