diff --git a/.github/workflows/generate_documentation.yml b/.github/workflows/generate_web_assets.yml similarity index 82% rename from .github/workflows/generate_documentation.yml rename to .github/workflows/generate_web_assets.yml index 7c178d1ac93b..21c32f511384 100644 --- a/.github/workflows/generate_documentation.yml +++ b/.github/workflows/generate_web_assets.yml @@ -1,13 +1,13 @@ -name: Generate documentation +name: Generate web assets on: push: branches: - master jobs: - generate_documentation: + generate_static_assets: if: ( !contains(github.event.head_commit.message, '[ci skip]') ) runs-on: ubuntu-latest - concurrency: gen-docs + concurrency: gen-assets steps: - uses: actions/checkout@v3 - name: Setup cache @@ -17,11 +17,12 @@ jobs: key: ${{ runner.os }}-spacemandmm-${{ secrets.CACHE_PURGE_KEY }} - name: Install SpacemanDMM run: bash tools/ci/install_spaceman_dmm.sh dmdoc - - name: Generate documentation + - name: Generate documentation and static assets run: | ~/dmdoc touch dmdoc/.nojekyll echo docs.cm-ss13.com > dmdoc/CNAME + mv tgui/public/ dmdoc/assets - name: Deploy uses: JamesIves/github-pages-deploy-action@3.7.1 with: diff --git a/code/controllers/configuration/entries/resources.dm b/code/controllers/configuration/entries/resources.dm index c839ccc078d4..2ceb9e3afe7a 100644 --- a/code/controllers/configuration/entries/resources.dm +++ b/code/controllers/configuration/entries/resources.dm @@ -28,3 +28,7 @@ if (str_var && str_var[length(str_var)] != "/") str_var += "/" return ..(str_var) + +/datum/config_entry/string/storage_cdn_iframe + config_entry_value = "https://cmss13-devs.github.io/cmss13/assets/iframe.html" + protection = CONFIG_ENTRY_LOCKED diff --git a/code/controllers/subsystem/statpanel.dm b/code/controllers/subsystem/statpanel.dm index 1a2a98ef4344..1a1fc3d81836 100644 --- a/code/controllers/subsystem/statpanel.dm +++ b/code/controllers/subsystem/statpanel.dm @@ -412,15 +412,3 @@ SUBSYSTEM_DEF(statpanels) else client.stat_panel.send_message("remove_listedturf") client.obj_window.stop_turf_tracking() - -/client/verb/open_statbrowser_options(current_fontsize as num|null) - set name = "Open Statbrowser Options" - set hidden = TRUE - - if (!current_fontsize) - current_fontsize = 14 - - var/datum/statbrowser_options/options_panel = statbrowser_options - if(!options_panel) - options_panel = statbrowser_options = new(src, current_fontsize) - options_panel.tgui_interact() diff --git a/code/controllers/subsystem/tgui.dm b/code/controllers/subsystem/tgui.dm index e9719d4610b0..e3cc9b23b0a6 100644 --- a/code/controllers/subsystem/tgui.dm +++ b/code/controllers/subsystem/tgui.dm @@ -42,11 +42,23 @@ SUBSYSTEM_DEF(tgui) basehtml = replacetext(basehtml, "tgui:stylesheet", MAP_STYLESHEET) /datum/controller/subsystem/tgui/OnConfigLoad() + var/storage_iframe = CONFIG_GET(string/storage_cdn_iframe) + + if(storage_iframe && storage_iframe != /datum/config_entry/string/storage_cdn_iframe::config_entry_value) + basehtml = replacetext(basehtml, "tgui:storagecdn", storage_iframe) + return + if(CONFIG_GET(string/asset_transport) == "webroot") var/datum/asset_transport/webroot/webroot = SSassets.transport var/datum/asset_cache_item/item = webroot.register_asset("iframe.html", file("tgui/public/iframe.html")) basehtml = replacetext(basehtml, "tgui:storagecdn", webroot.get_asset_url("iframe.html", item)) + return + + if(!storage_iframe) + return + + basehtml = replacetext(basehtml, "tgui:storagecdn", storage_iframe) /datum/controller/subsystem/tgui/Shutdown() close_all_uis() diff --git a/code/modules/admin/verbs/debug.dm b/code/modules/admin/verbs/debug.dm index 3541f994887e..02f63624677d 100644 --- a/code/modules/admin/verbs/debug.dm +++ b/code/modules/admin/verbs/debug.dm @@ -358,7 +358,9 @@ return to_chat(src, SPAN_INFO("You can now right click to use inspect on browsers.")) - winset(src, "", "browser-options=byondstorage,find,devtools,refresh") + winset(src, null, list("browser-options" = "+devtools")) + winset(src, null, list("browser-options" = "+find")) + winset(src, null, list("browser-options" = "+refresh")) #ifdef TESTING GLOBAL_LIST_EMPTY(dirty_vars) diff --git a/code/modules/client/client_procs.dm b/code/modules/client/client_procs.dm index 0b5d1710d63e..af76f48e89ed 100644 --- a/code/modules/client/client_procs.dm +++ b/code/modules/client/client_procs.dm @@ -286,9 +286,6 @@ GLOBAL_LIST_INIT(whitelisted_client_procs, list( GLOB.clients += src GLOB.directory[ckey] = src - if(byond_version >= 516) // Enable 516 compat browser storage mechanisms - winset(src, "", "browser-options=byondstorage") - // Instantiate stat panel stat_panel = new(src, "statbrowser") stat_panel.subscribe(src, PROC_REF(on_stat_panel_message)) diff --git a/code/modules/client/statbrowser_options.dm b/code/modules/client/statbrowser_options.dm deleted file mode 100644 index 57da98db1265..000000000000 --- a/code/modules/client/statbrowser_options.dm +++ /dev/null @@ -1,34 +0,0 @@ -/client/var/datum/statbrowser_options/statbrowser_options - -/// Handles the Statbrowser Options window for a given client -/datum/statbrowser_options - var/client/client - var/current_fontsize - -/datum/statbrowser_options/New(client/client, current_fontsize) - src.client = client - src.current_fontsize = current_fontsize - -/datum/statbrowser_options/tgui_interact(mob/user = client.mob, datum/tgui/ui) - ui = SStgui.try_update_ui(user, src, ui) - if (!ui) - ui = new(user, src, "StatbrowserOptions", "Statbrowser Options") - ui.open() - -/datum/statbrowser_options/ui_data(mob/user) - . = list() - .["current_fontsize"] = current_fontsize - -/datum/statbrowser_options/ui_state() - return GLOB.always_state - -/datum/statbrowser_options/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state) - . = ..() - if(.) - return - - switch(action) - if("change_fontsize") - var/new_fontsize = text2num(params["new_fontsize"]) - current_fontsize = new_fontsize - client.stat_panel.send_message("change_fontsize", new_fontsize) diff --git a/colonialmarines.dme b/colonialmarines.dme index 914cac5c55ee..4462b8e0a99e 100644 --- a/colonialmarines.dme +++ b/colonialmarines.dme @@ -1650,7 +1650,6 @@ #include "code\modules\client\preferences_gear.dm" #include "code\modules\client\preferences_savefile.dm" #include "code\modules\client\preferences_toggles.dm" -#include "code\modules\client\statbrowser_options.dm" #include "code\modules\client\tgui_macro.dm" #include "code\modules\client\traits_picker.dm" #include "code\modules\clothing\clothing.dm" diff --git a/html/statbrowser.js b/html/statbrowser.js index 329f43c2b95d..4519900952df 100644 --- a/html/statbrowser.js +++ b/html/statbrowser.js @@ -23,45 +23,12 @@ function testHubStorage() { } } -function loadFontSize() { - current_fontsize = parseInt(window.hubStorage.getItem("fontsize")); - if (isNaN(current_fontsize) || current_fontsize <= 0) { - current_fontsize = 14; - } - statcontentdiv.style.fontSize = current_fontsize + "px"; - tab_change(current_tab, true); // Redraw the current tab -} - -function onByondStorageLoad(event) { - document.removeEventListener('byondstorageupdated', onByondStorageLoad); - setTimeout(loadFontSize, 0); // Unfortunately its STILL not ready yet -} // Status panel implementation ------------------------------------------------ var status_tab_parts = ["Loading..."]; var current_tab = null; var current_fontsize = 14; // in px, also determines line height and category header sizes for the verb menus -// Per `storage.js` for tgui: -// Localstorage can sometimes throw an error, even if DOM storage is not -// disabled in IE11 settings. -// See: https://superuser.com/questions/1080011 -try { - if (!Byond.TRIDENT) { - // Unfortunately byond storage isn't available immediately - if (!testHubStorage()) { - document.addEventListener('byondstorageupdated', onByondStorageLoad); - } else { - current_fontsize = parseInt(window.hubStorage.getItem("fontsize")); - } - } else { // TODO: Remove with 516 - current_fontsize = parseInt(window.localStorage.getItem("fontsize")); - } -} catch (error) { - current_fontsize = 14; -} -if (isNaN(current_fontsize) || current_fontsize <= 0) { - current_fontsize = 14; -} + var mc_tab_parts = [["Loading...", ""]]; var href_token = null; var spells = []; @@ -208,9 +175,6 @@ let clientButtons = { {name: "Effects", command: "Adjust-Volume-SFX"}, {name: "Ambience", command: "Adjust-Volume-Ambience"}, {name: "Admin Music", command: "Adjust-Volume-Admin-Music"} - ], - "Statbrowser": [ - {name: "Change Fontsize", function: openOptionsMenu} ] } @@ -1158,6 +1122,12 @@ window.onload = function () { Byond.sendMessage("Update-Verbs"); }; +function set_font_size(size) { + current_fontsize = parseInt(size); + statcontentdiv.style.fontSize = current_fontsize + "px"; + tab_change(current_tab, true); +} + Byond.subscribeTo("update_spells", function (payload) { spell_tabs = payload.spell_tabs; var do_update = false; @@ -1373,18 +1343,3 @@ Byond.subscribeTo("changelog_read", function(read) { function createOptionsButton() { addPermanentTab("Options", true); } - -function openOptionsMenu() { - Byond.command("Open-Statbrowser-Options " + current_fontsize); -} - -Byond.subscribeTo("change_fontsize", function (new_fontsize) { - current_fontsize = parseInt(new_fontsize); - if (!Byond.TRIDENT) { - window.hubStorage.setItem("fontsize", current_fontsize.toString()); - } else { // TODO: Remove with 516 - window.localStorage.setItem("fontsize", current_fontsize.toString()); - } - statcontentdiv.style.fontSize = current_fontsize + "px"; - tab_change(current_tab, true); // Redraw the current tab -}); diff --git a/tgui/packages/common/storage.js b/tgui/packages/common/storage.js index 082e41ecf5ee..358378897564 100644 --- a/tgui/packages/common/storage.js +++ b/tgui/packages/common/storage.js @@ -99,7 +99,8 @@ class IFrameIndexedDbBackend { iframe.onload = () => resolve(this); }); - this.iframeWindow = document.body.appendChild(iframe).contentWindow; + this.documentElement = document.body.appendChild(iframe); + this.iframeWindow = this.documentElement.contentWindow; return completePromise; } @@ -129,6 +130,21 @@ class IFrameIndexedDbBackend { this.iframeWindow.postMessage({ type: 'clear' }, '*'); } + async ping() { + const promise = new Promise((resolve) => { + window.addEventListener('message', (message) => { + if (message.data === true) { + resolve(true); + } + }); + + setTimeout(() => resolve(false), 100); + }); + + this.iframeWindow.postMessage({ type: 'ping' }, '*'); + return promise; + } + async processChatMessages(messages) { this.iframeWindow.postMessage( { type: 'processChatMessages', messages: messages }, @@ -148,6 +164,12 @@ class IFrameIndexedDbBackend { this.iframeWindow.postMessage({ type: 'getChatMessages' }, '*'); return promise; } + + async destroy() { + document.body.removeChild(this.documentElement); + this.documentElement = null; + this.iframeWindow = null; + } } class IndexedDbBackend { @@ -212,16 +234,42 @@ class IndexedDbBackend { * depending on the environment. */ export class StorageProxy { - constructor(chat) { + constructor() { this.backendPromise = (async () => { if (!Byond.TRIDENT) { - if (chat) { + if (Byond.storageCdn && !window.hubStorage) { const iframe = new IFrameIndexedDbBackend(); await iframe.ready(); - return iframe; + + if ((await iframe.ping()) === true) { + // Remove with 516... eventually + if (await iframe.get('byondstorage-migrated')) return iframe; + + Byond.winset(null, 'browser-options', '+byondstorage'); + + await new Promise((resolve) => { + document.addEventListener('byondstorageupdated', async () => { + setTimeout(() => { + const hub = new HubStorageBackend(); + hub + .get('panel-settings') + .then((settings) => iframe.set('panel-settings', settings)); + iframe.set('byondstorage-migrated', true); + + resolve(); + }, 1); + }); + }); + + return iframe; + } + + iframe.destroy(); } if (!testHubStorage()) { + Byond.winset(null, 'browser-options', '+byondstorage'); + return new Promise((resolve) => { const listener = () => { document.removeEventListener('byondstorageupdated', listener); diff --git a/tgui/packages/common/types.ts b/tgui/packages/common/types.ts index e219bd3b7e12..15cac32d7e79 100644 --- a/tgui/packages/common/types.ts +++ b/tgui/packages/common/types.ts @@ -4,3 +4,20 @@ // prettier-ignore export type ArgumentsOf = F extends (...args: infer A) => unknown ? A : never; + +type ByondStorage = { + clear: () => void; + fill: (data: object) => void; + getItem: (item: string) => object; + hasitem: (item: string) => boolean; + removeItem: (item: string) => void; + setItem: (item: string, value: any) => void; + sync: () => void; +}; + +export type ByondWindow = Window & + typeof globalThis & { + hubStorage?: ByondStorage; + serverStorage?: ByondStorage; + domainStorage?: ByondStorage; + }; diff --git a/tgui/packages/tgui-panel/chat/middleware.ts b/tgui/packages/tgui-panel/chat/middleware.ts index 3076bfa0c142..aae7c6d6e5a3 100644 --- a/tgui/packages/tgui-panel/chat/middleware.ts +++ b/tgui/packages/tgui-panel/chat/middleware.ts @@ -4,7 +4,8 @@ * @license MIT */ -import { storage as realStorage, StorageProxy } from 'common/storage'; +import { storage } from 'common/storage'; +import type { ByondWindow } from 'common/types'; import DOMPurify from 'dompurify'; import { @@ -38,14 +39,10 @@ import { selectChat, selectCurrentChatPage } from './selectors'; // List of blacklisted tags const FORBID_TAGS = ['a', 'iframe', 'link', 'video']; -const usingCdnStorage = - !Byond.TRIDENT && Byond.storageCdn !== 'tgui:storagecdn'; -const storage = usingCdnStorage ? new StorageProxy(true) : realStorage; - const saveChatToStorage = async (store) => { const state = selectChat(store.getState()); - if (usingCdnStorage) { + if (!(window as ByondWindow).hubStorage) { const indexedDbBackend = await storage.backendPromise; indexedDbBackend.processChatMessages(chatRenderer.storeQueue); } else { @@ -69,7 +66,7 @@ const loadChatFromStorage = async (store) => { const state = await storage.get('chat-state-cm'); let messages; - if (usingCdnStorage) { + if (!(window as ByondWindow).hubStorage) { messages = await (await storage.backendPromise).getChatMessages(); } else { messages = await storage.get('chat-messages-cm'); diff --git a/tgui/packages/tgui-panel/chat/renderer.tsx b/tgui/packages/tgui-panel/chat/renderer.tsx index c162ab78581e..337911331c60 100644 --- a/tgui/packages/tgui-panel/chat/renderer.tsx +++ b/tgui/packages/tgui-panel/chat/renderer.tsx @@ -516,7 +516,7 @@ class ChatRenderer { } } } - this.storeQueue.push({ ...message }); + this.storeQueue.push({ ...message, stored: true }); // Store the node in the message message.node = node; // Query all possible selectors to find out the message type diff --git a/tgui/packages/tgui-panel/chat/types.ts b/tgui/packages/tgui-panel/chat/types.ts index 691886f394a2..0f5809a21b90 100644 --- a/tgui/packages/tgui-panel/chat/types.ts +++ b/tgui/packages/tgui-panel/chat/types.ts @@ -6,6 +6,7 @@ export type message = { times?: number; createdAt: number; avoidHighlighting?: boolean; + stored?: boolean; }; export type Page = { diff --git a/tgui/packages/tgui-panel/settings/SettingTabs/SettingsStatPanel.tsx b/tgui/packages/tgui-panel/settings/SettingTabs/SettingsStatPanel.tsx index cf089dad59e5..f09dbfdec2ef 100644 --- a/tgui/packages/tgui-panel/settings/SettingTabs/SettingsStatPanel.tsx +++ b/tgui/packages/tgui-panel/settings/SettingTabs/SettingsStatPanel.tsx @@ -1,5 +1,4 @@ import { toFixed } from 'common/math'; -import { capitalize } from 'common/string'; import { useDispatch, useSelector } from 'tgui/backend'; import { Button, @@ -13,7 +12,6 @@ import { import { updateSettings } from '../actions'; import { selectSettings } from '../selectors'; -const TabsViews = ['default', 'classic', 'scrollable']; const LinkedToChat = () => ( Unlink Stat Panel from chat! ); @@ -28,20 +26,6 @@ export function SettingsStatPanel(props) { - - {TabsViews.map((view) => ( - - ))} - {statLinked ? ( diff --git a/tgui/packages/tgui-panel/settings/SettingsPanel.tsx b/tgui/packages/tgui-panel/settings/SettingsPanel.tsx index c4fab331a2b0..ff5849d182d1 100644 --- a/tgui/packages/tgui-panel/settings/SettingsPanel.tsx +++ b/tgui/packages/tgui-panel/settings/SettingsPanel.tsx @@ -12,6 +12,7 @@ import { changeSettingsTab } from './actions'; import { SETTINGS_TABS } from './constants'; import { selectActiveTab } from './selectors'; import { SettingsGeneral } from './SettingTabs/SettingsGeneral'; +import { SettingsStatPanel } from './SettingTabs/SettingsStatPanel'; import { TextHighlightSettings } from './SettingTabs/TextHighlight'; export const SettingsPanel = (props) => { @@ -44,6 +45,7 @@ export const SettingsPanel = (props) => { {activeTab === 'general' && } {activeTab === 'chatPage' && } {activeTab === 'textHighlight' && } + {activeTab === 'statPanel' && } ); diff --git a/tgui/packages/tgui-panel/settings/constants.ts b/tgui/packages/tgui-panel/settings/constants.ts index 86ac41a23ebc..984cc1c21fa7 100644 --- a/tgui/packages/tgui-panel/settings/constants.ts +++ b/tgui/packages/tgui-panel/settings/constants.ts @@ -18,6 +18,10 @@ export const SETTINGS_TABS = [ id: 'chatPage', name: 'Chat Tabs', }, + { + id: 'statPanel', + name: 'Statpanel', + }, ]; export const FONTS_DISABLED = 'Default'; diff --git a/tgui/packages/tgui-panel/settings/middleware.ts b/tgui/packages/tgui-panel/settings/middleware.ts index 58b22512feb2..23a18ca0e9cc 100644 --- a/tgui/packages/tgui-panel/settings/middleware.ts +++ b/tgui/packages/tgui-panel/settings/middleware.ts @@ -59,11 +59,11 @@ function setGlobalFontSize( // Used solution from theme.ts clearInterval(statFontTimer); Byond.command( - `.output statbrowser:set_font_size ${statLinked ? fontSize : statFontSize}px`, + `.output statbrowser:set_font_size ${statLinked ? fontSize : statFontSize}`, ); statFontTimer = setTimeout(() => { Byond.command( - `.output statbrowser:set_font_size ${statLinked ? fontSize : statFontSize}px`, + `.output statbrowser:set_font_size ${statLinked ? fontSize : statFontSize}`, ); }, 1500); } diff --git a/tgui/packages/tgui-panel/settings/reducer.ts b/tgui/packages/tgui-panel/settings/reducer.ts index f74f693788dc..2fec5f559b18 100644 --- a/tgui/packages/tgui-panel/settings/reducer.ts +++ b/tgui/packages/tgui-panel/settings/reducer.ts @@ -39,8 +39,8 @@ const initialState = { visible: false, activeTab: SETTINGS_TABS[0].id, }, - statLinked: true, - statFontSize: 12, + statLinked: false, + statFontSize: 14, statTabsStyle: 'default', initialized: false, } as const; diff --git a/tgui/packages/tgui/interfaces/StatbrowserOptions.tsx b/tgui/packages/tgui/interfaces/StatbrowserOptions.tsx deleted file mode 100644 index c59157aad67a..000000000000 --- a/tgui/packages/tgui/interfaces/StatbrowserOptions.tsx +++ /dev/null @@ -1,66 +0,0 @@ -import { useState } from 'react'; -import { useBackend } from 'tgui/backend'; -import { Flex, NumberInput, Section } from 'tgui/components'; -import { Window } from 'tgui/layouts'; - -type Data = { current_fontsize: number }; - -export const StatbrowserOptions = (props) => { - const { act, data } = useBackend(); - const { current_fontsize } = data; - const [fontsize, setFontsize] = useState(current_fontsize); - - return ( - - - - value + 'px'} - onChange={(value) => { - setFontsize(value); - act('change_fontsize', { new_fontsize: value }); - }} - /> - - - - ); -}; - -const Options = (props: { readonly children: React.JSX.Element | string }) => { - const { children } = props; - - return ( -
- - {!Array.isArray(children) - ? children - : children.map((option, i) => ( - {option} - ))} - -
- ); -}; - -const Option = (props) => { - const { category, input } = props; - - return ( - - {category} - {input} - - ); -}; - -const NumberOption = (props) => { - const { category, ...rest } = props; - - return