From fb673e1be26cb1e789aaa350ff2cca51b7edf58b Mon Sep 17 00:00:00 2001
From: Kashargul <144968721+Kashargul@users.noreply.github.com>
Date: Sun, 1 Feb 2026 21:22:20 +0100
Subject: [PATCH] request persistence for the iframe indexDB (#19105)
* request persistence for the iframe indexDB
* new min js
* also format this
* .
---
html/changelog.js | 18 +++++++-------
html/shock.js | 34 +++++++++++++-------------
tgui/packages/tgui-setup/helpers.js | 38 ++++++++++-------------------
tgui/public/helpers.min.js | 2 +-
tgui/public/iframe.html | 12 +++++++--
5 files changed, 50 insertions(+), 54 deletions(-)
diff --git a/html/changelog.js b/html/changelog.js
index 0da7e59cb12..2dee8b924d1 100644
--- a/html/changelog.js
+++ b/html/changelog.js
@@ -55,24 +55,24 @@ function filterchanges(type){
}
*/
function dropdowns() {
- var drops = $("div.drop");
- var indrops = $("div.indrop");
- if (drops.length != indrops.length) {
- alert("Some coder fucked up with dropdowns");
+ const drops = $('div.drop');
+ const indrops = $('div.indrop');
+ if (drops.length !== indrops.length) {
+ alert('Some coder fucked up with dropdowns');
}
drops.each(function (index) {
- $(this).toggleClass("closed");
+ $(this).toggleClass('closed');
$(indrops[index]).hide();
$(this).click(function () {
- $(this).toggleClass("closed");
- $(this).toggleClass("open");
+ $(this).toggleClass('closed');
+ $(this).toggleClass('open');
$(indrops[index]).toggle();
});
});
}
function filterchanges(type) {
- $("ul.changes li").each(function () {
+ $('ul.changes li').each(function () {
if (!type || $(this).hasClass(type)) {
$(this).show();
} else {
@@ -81,6 +81,6 @@ function filterchanges(type) {
});
}
-$(document).ready(function () {
+$(document).ready(() => {
dropdowns();
});
diff --git a/html/shock.js b/html/shock.js
index 4afce1a5542..9e10783bc7c 100644
--- a/html/shock.js
+++ b/html/shock.js
@@ -2,21 +2,21 @@ let webSocket;
let authKey;
let lastCall;
-const reactRoot = document.getElementById("react-root");
+const reactRoot = document.getElementById('react-root');
if (reactRoot) {
reactRoot.innerHTML =
"
You shouldn't see this window, update your skin.
";
}
-Byond.subscribeTo("estop", function () {
+Byond.subscribeTo('estop', () => {
if (webSocket) {
webSocket.close();
} else {
- Byond.sendMessage("disconnected");
+ Byond.sendMessage('disconnected');
}
});
-Byond.subscribeTo("connect", function (data) {
+Byond.subscribeTo('connect', (data) => {
if (webSocket) {
webSocket.close();
}
@@ -24,29 +24,29 @@ Byond.subscribeTo("connect", function (data) {
webSocket.sendJson = (data) => {
webSocket.send(JSON.stringify(data));
};
- authKey = JSON.parse(window.hubStorage.getItem("virgo-shocker-authkey"));
+ authKey = JSON.parse(window.hubStorage.getItem('virgo-shocker-authkey'));
webSocket.onopen = (ev) => {
- Byond.sendMessage("connected");
+ Byond.sendMessage('connected');
};
webSocket.onerror = (ev) => {
- Byond.sendMessage("error", ev);
+ Byond.sendMessage('error', ev);
};
webSocket.onclose = (ev) => {
- Byond.sendMessage("disconnected");
+ Byond.sendMessage('disconnected');
};
webSocket.onmessage = (ev) => {
- Byond.sendMessage("incomingMessage", { data: ev.data, lastCall });
+ Byond.sendMessage('incomingMessage', { data: ev.data, lastCall });
};
});
-Byond.subscribeTo("enumerateShockers", function () {
+Byond.subscribeTo('enumerateShockers', () => {
if (!webSocket) {
return;
}
- lastCall = "get_devices";
+ lastCall = 'get_devices';
webSocket.sendJson({
- cmd: "get_devices",
+ cmd: 'get_devices',
auth_key: authKey,
});
});
@@ -57,19 +57,19 @@ Byond.subscribeTo("enumerateShockers", function () {
// "shocker_ids": [], // [] - List of shocker ids
// "warning": false, // true, false - will send a vibrate with the same intensity and duration
// },
-Byond.subscribeTo("shock", function (data) {
+Byond.subscribeTo('shock', (data) => {
if (!webSocket) {
return;
}
- lastCall = "operate";
+ lastCall = 'operate';
webSocket.sendJson({
- cmd: "operate",
+ cmd: 'operate',
value: {
intensity: data.intensity, // 1 - 100 - int
duration: data.duration, // 0.1 - 15 - float
- shocker_option: "all", // all, random
- action: "shock", // shock, vibrate, beep, end
+ shocker_option: 'all', // all, random
+ action: 'shock', // shock, vibrate, beep, end
shocker_ids: data.shocker_ids, // [] - List of shocker ids
device_ids: [], // [] - list of pishock client ids, if one of these is provided it will activate all shockers associated with it
warning: data.warning, // true, false - will send a vibrate with the same intensity and duration
diff --git a/tgui/packages/tgui-setup/helpers.js b/tgui/packages/tgui-setup/helpers.js
index 8b0f2900390..f04138c1b83 100644
--- a/tgui/packages/tgui-setup/helpers.js
+++ b/tgui/packages/tgui-setup/helpers.js
@@ -16,7 +16,7 @@
};
const parseMetaTag = function (name) {
const content = document.getElementById(name).getAttribute('content');
- if (content === '[' + name + ']') {
+ if (content === `[${name}]`) {
return null;
}
return content;
@@ -81,7 +81,7 @@
return;
}
// Build the URL
- let url = (path || '') + '?';
+ let url = `${path || ''}?`;
let i = 0;
if (params) {
for (const key in params) {
@@ -93,20 +93,20 @@
if (value === null || value === undefined) {
value = '';
}
- url += encodeURIComponent(key) + '=' + encodeURIComponent(value);
+ url += `${encodeURIComponent(key)}=${encodeURIComponent(value)}`;
}
}
}
// If we're a Chromium client, just use the fancy method
if (window.cef_to_byond) {
- cef_to_byond('byond://' + url);
+ cef_to_byond(`byond://${url}`);
return;
}
// Perform a standard call via location.href
if (url.length < 2048) {
- location.href = 'byond://' + url;
+ location.href = `byond://${url}`;
return;
}
// Send an HTTP request to DreamSeeker's HTTP server.
@@ -127,7 +127,7 @@
Byond.call(
path,
assign({}, params, {
- callback: 'Byond.__callbacks__[' + index + ']',
+ callback: `Byond.__callbacks__[${index}]`,
})
);
return promise;
@@ -181,7 +181,7 @@
try {
return JSON.parse(json, byondJsonReviver);
} catch (err) {
- throw new Error('JSON parsing error: ' + (err && err.message));
+ throw new Error(`JSON parsing error: ${err?.message}`);
}
};
@@ -293,16 +293,9 @@
// Generic retry function
const retry = function () {
if (attempt >= RETRY_ATTEMPTS) {
- let errorMessage =
- 'Error: Failed to load the asset ' +
- "'" +
- url +
- "' after several attempts.";
+ let errorMessage = `Error: Failed to load the asset '${url}' after several attempts.`;
if (type === 'css') {
- errorMessage +=
- +'\nStylesheet was either not found, ' +
- "or you're trying to load an empty stylesheet " +
- 'that has no CSS rules in it.';
+ errorMessage += `\nStylesheet was either not found, or you're trying to load an empty stylesheet that has no CSS rules in it.`;
}
throw new Error(errorMessage);
}
@@ -425,10 +418,7 @@ window.onerror = function (msg, url, line, col, error) {
let stack = error && error.stack;
// Ghetto stacktrace
if (!stack) {
- stack = msg + '\n at ' + url + ':' + line;
- if (col) {
- stack += ':' + col;
- }
+ stack = `${msg}\n at ${url}:${line}${col ? `:${col}` : ''}`;
}
// Augment the stack
stack = window.__augmentStack__(stack, error);
@@ -486,7 +476,7 @@ window.onunhandledrejection = function (e) {
if (e.reason) {
msg += ': ' + (e.reason.message || e.reason.description || e.reason);
if (e.reason.stack) {
- e.reason.stack = 'UnhandledRejection: ' + e.reason.stack;
+ e.reason.stack = `UnhandledRejection: ${e.reason.stack}`;
}
}
window.onerror(msg, null, null, null, e.reason);
@@ -494,7 +484,7 @@ window.onunhandledrejection = function (e) {
// Helper for augmenting stack traces on fatal errors
window.__augmentStack__ = function (stack, error) {
- return stack + '\nUser Agent: ' + navigator.userAgent;
+ return `${stack}\nUser Agent: ${navigator.userAgent}`;
};
// Incoming message handling
@@ -552,8 +542,6 @@ window.replaceHtml = function (inline_html) {
document.body.insertAdjacentHTML(
'afterbegin',
- '' +
- inline_html +
- ''
+ `${inline_html}`
);
};
diff --git a/tgui/public/helpers.min.js b/tgui/public/helpers.min.js
index 17255ebb8fe..99640501524 100644
--- a/tgui/public/helpers.min.js
+++ b/tgui/public/helpers.min.js
@@ -1 +1 @@
-(function(){const hasOwn=Object.prototype.hasOwnProperty;const assign=function(target){for(let i=1;i0){url+="&"}let value=params[key];if(value===null||value===undefined){value=""}url+=encodeURIComponent(key)+"="+encodeURIComponent(value)}}}if(window.cef_to_byond){cef_to_byond("byond://"+url);return}if(url.length<2048){location.href="byond://"+url;return}const xhr=new XMLHttpRequest;xhr.open("GET",url);xhr.send()};Byond.callAsync=function(path,params){if(!window.Promise){throw new Error("Async calls require API level of ES2015 or later.")}const index=Byond.__callbacks__.length;const promise=new window.Promise(resolve=>{Byond.__callbacks__.push(resolve)});Byond.call(path,assign({},params,{callback:"Byond.__callbacks__["+index+"]"}));return promise};Byond.topic=function(params){return Byond.call("",params)};Byond.command=function(command){return Byond.call("winset",{command:command})};Byond.winget=function(id,propName){if(id===null){id=""}const isArray=propName instanceof Array;const isSpecific=propName&&propName!=="*"&&!isArray;let promise=Byond.callAsync("winget",{id:id,property:isArray&&propName.join(",")||propName||"*"});if(isSpecific){promise=promise.then(props=>props[propName])}return promise};Byond.winset=function(id,propName,propValue){if(id===null){id=""}else if(typeof id==="object"){return Byond.call("winset",id)}const props={};if(typeof propName==="string"){props[propName]=propValue}else{assign(props,propName)}props.id=id;return Byond.call("winset",props)};Byond.parseJson=function(json){try{return JSON.parse(json,byondJsonReviver)}catch(err){throw new Error("JSON parsing error: "+(err&&err.message))}};const MAX_PACKET_SIZE=1024;Byond.sendMessage=function(type,payload){let message=typeof type==="string"?{type:type,payload:payload}:type;if(message.payload!==null&&message.payload!==undefined){message.payload=JSON.stringify(message.payload);if(!Byond.TRIDENT&&message.payload.length>MAX_PACKET_SIZE&&type!=="payloadChunk"){const chunks=[];for(let i=0,charsLength=message.payload.length;i0}return false};const injectNode=function(node){if(!document.body){setTimeout(()=>{injectNode(node)});return}const refs=document.body.childNodes;const ref=refs[refs.length-1];ref.parentNode.insertBefore(node,ref.nextSibling)};const loadAsset=function(options){const url=options.url;const type=options.type;const sync=options.sync;const attempt=options.attempt||0;if(loadedAssetByUrl[url]){return}loadedAssetByUrl[url]=options;const retry=function(){if(attempt>=RETRY_ATTEMPTS){let errorMessage="Error: Failed to load the asset "+"'"+url+"' after several attempts.";if(type==="css"){errorMessage+=+"\nStylesheet was either not found, "+"or you're trying to load an empty stylesheet "+"that has no CSS rules in it."}throw new Error(errorMessage)}setTimeout(()=>{loadedAssetByUrl[url]=null;options.attempt+=1;loadAsset(options)},RETRY_WAIT_INITIAL+attempt*RETRY_WAIT_INCREMENT)};if(type==="js"){let node=document.createElement("script");node.type="text/javascript";node.crossOrigin="anonymous";node.src=url;if(sync){node.defer=true}else{node.async=true}node.onerror=function(){node.onerror=null;node.parentNode.removeChild(node);node=null;retry()};injectNode(node);return}if(type==="css"){let node=document.createElement("link");node.type="text/css";node.rel="stylesheet";node.crossOrigin="anonymous";node.href=url;if(!sync){node.media="only x"}const removeNodeAndRetry=function(){node.parentNode.removeChild(node);node=null;retry()};node.onerror=function(){node.onerror=null;removeNodeAndRetry()};node.onload=function(){node.onload=null;if(isStyleSheetLoaded(node,url)){node.media="all";return}removeNodeAndRetry()};injectNode(node);return}};Byond.loadJs=function(url,sync){loadAsset({url:url,sync:sync,type:"js"})};Byond.loadCss=function(url,sync){loadAsset({url:url,sync:sync,type:"css"})};Byond.saveBlob=function(blob,filename,ext){if(window.navigator.msSaveBlob){window.navigator.msSaveBlob(blob,filename)}else if(window.showSaveFilePicker){const accept={};accept[blob.type]=[ext];const opts={suggestedName:filename,types:[{description:"SS13 file",accept:accept}]};window.showSaveFilePicker(opts).then(function(file){return file.createWritable()}).then(function(file){return file.write(blob).then(function(){return file.close()})}).catch(function(){})}};Byond.iconRefMap={}})();window.onerror=function(msg,url,line,col,error){window.onerror.errorCount=(window.onerror.errorCount||0)+1;let stack=error&&error.stack;if(!stack){stack=msg+"\n at "+url+":"+line;if(col){stack+=":"+col}}stack=window.__augmentStack__(stack,error);if(Byond.strictMode){const errorRoot=document.getElementById("FatalError");const errorStack=document.getElementById("FatalError__stack");if(errorRoot){errorRoot.className="FatalError FatalError--visible";if(window.onerror.__stack__){window.onerror.__stack__+="\n\n"+stack}else{window.onerror.__stack__=stack}const textProp="textContent";errorStack[textProp]=window.onerror.__stack__}const setFatalErrorGeometry=function(){Byond.winset(Byond.windowId,{titlebar:true,"is-visible":true,"can-resize":true})};setFatalErrorGeometry();setInterval(setFatalErrorGeometry,1e3)}if(Byond.strictMode){Byond.sendMessage({type:"log",fatal:1,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})}if(Byond.strictMode){window.update=function(){};window.update.queue=[]}return true};window.onunhandledrejection=function(e){let msg="UnhandledRejection";if(e.reason){msg+=": "+(e.reason.message||e.reason.description||e.reason);if(e.reason.stack){e.reason.stack="UnhandledRejection: "+e.reason.stack}}window.onerror(msg,null,null,null,e.reason)};window.__augmentStack__=function(stack,error){return stack+"\nUser Agent: "+navigator.userAgent};window.update=function(rawMessage){if(window.update.queueActive){window.update.queue.push(rawMessage);return}const message=Byond.parseJson(rawMessage);const listeners=window.update.listeners;for(let i=0;i{window.update.queue=[]},0)}}const queue=window.update.queue;for(let i=0;i0){url+="&"}let value=params[key];if(value===null||value===undefined){value=""}url+=`${encodeURIComponent(key)}=${encodeURIComponent(value)}`}}}if(window.cef_to_byond){cef_to_byond(`byond://${url}`);return}if(url.length<2048){location.href=`byond://${url}`;return}const xhr=new XMLHttpRequest;xhr.open("GET",url);xhr.send()};Byond.callAsync=function(path,params){if(!window.Promise){throw new Error("Async calls require API level of ES2015 or later.")}const index=Byond.__callbacks__.length;const promise=new window.Promise(resolve=>{Byond.__callbacks__.push(resolve)});Byond.call(path,assign({},params,{callback:`Byond.__callbacks__[${index}]`}));return promise};Byond.topic=function(params){return Byond.call("",params)};Byond.command=function(command){return Byond.call("winset",{command:command})};Byond.winget=function(id,propName){if(id===null){id=""}const isArray=propName instanceof Array;const isSpecific=propName&&propName!=="*"&&!isArray;let promise=Byond.callAsync("winget",{id:id,property:isArray&&propName.join(",")||propName||"*"});if(isSpecific){promise=promise.then(props=>props[propName])}return promise};Byond.winset=function(id,propName,propValue){if(id===null){id=""}else if(typeof id==="object"){return Byond.call("winset",id)}const props={};if(typeof propName==="string"){props[propName]=propValue}else{assign(props,propName)}props.id=id;return Byond.call("winset",props)};Byond.parseJson=function(json){try{return JSON.parse(json,byondJsonReviver)}catch(err){throw new Error(`JSON parsing error: ${err?.message}`)}};const MAX_PACKET_SIZE=1024;Byond.sendMessage=function(type,payload){let message=typeof type==="string"?{type:type,payload:payload}:type;if(message.payload!==null&&message.payload!==undefined){message.payload=JSON.stringify(message.payload);if(!Byond.TRIDENT&&message.payload.length>MAX_PACKET_SIZE&&type!=="payloadChunk"){const chunks=[];for(let i=0,charsLength=message.payload.length;i0}return false};const injectNode=function(node){if(!document.body){setTimeout(()=>{injectNode(node)});return}const refs=document.body.childNodes;const ref=refs[refs.length-1];ref.parentNode.insertBefore(node,ref.nextSibling)};const loadAsset=function(options){const url=options.url;const type=options.type;const sync=options.sync;const attempt=options.attempt||0;if(loadedAssetByUrl[url]){return}loadedAssetByUrl[url]=options;const retry=function(){if(attempt>=RETRY_ATTEMPTS){let errorMessage=`Error: Failed to load the asset '${url}' after several attempts.`;if(type==="css"){errorMessage+=`\nStylesheet was either not found, or you're trying to load an empty stylesheet that has no CSS rules in it.`}throw new Error(errorMessage)}setTimeout(()=>{loadedAssetByUrl[url]=null;options.attempt+=1;loadAsset(options)},RETRY_WAIT_INITIAL+attempt*RETRY_WAIT_INCREMENT)};if(type==="js"){let node=document.createElement("script");node.type="text/javascript";node.crossOrigin="anonymous";node.src=url;if(sync){node.defer=true}else{node.async=true}node.onerror=function(){node.onerror=null;node.parentNode.removeChild(node);node=null;retry()};injectNode(node);return}if(type==="css"){let node=document.createElement("link");node.type="text/css";node.rel="stylesheet";node.crossOrigin="anonymous";node.href=url;if(!sync){node.media="only x"}const removeNodeAndRetry=function(){node.parentNode.removeChild(node);node=null;retry()};node.onerror=function(){node.onerror=null;removeNodeAndRetry()};node.onload=function(){node.onload=null;if(isStyleSheetLoaded(node,url)){node.media="all";return}removeNodeAndRetry()};injectNode(node);return}};Byond.loadJs=function(url,sync){loadAsset({url:url,sync:sync,type:"js"})};Byond.loadCss=function(url,sync){loadAsset({url:url,sync:sync,type:"css"})};Byond.saveBlob=function(blob,filename,ext){if(window.navigator.msSaveBlob){window.navigator.msSaveBlob(blob,filename)}else if(window.showSaveFilePicker){const accept={};accept[blob.type]=[ext];const opts={suggestedName:filename,types:[{description:"SS13 file",accept:accept}]};window.showSaveFilePicker(opts).then(function(file){return file.createWritable()}).then(function(file){return file.write(blob).then(function(){return file.close()})}).catch(function(){})}};Byond.iconRefMap={}})();window.onerror=function(msg,url,line,col,error){window.onerror.errorCount=(window.onerror.errorCount||0)+1;let stack=error&&error.stack;if(!stack){stack=`${msg}\n at ${url}:${line}${col?`:${col}`:""}`}stack=window.__augmentStack__(stack,error);if(Byond.strictMode){const errorRoot=document.getElementById("FatalError");const errorStack=document.getElementById("FatalError__stack");if(errorRoot){errorRoot.className="FatalError FatalError--visible";if(window.onerror.__stack__){window.onerror.__stack__+="\n\n"+stack}else{window.onerror.__stack__=stack}const textProp="textContent";errorStack[textProp]=window.onerror.__stack__}const setFatalErrorGeometry=function(){Byond.winset(Byond.windowId,{titlebar:true,"is-visible":true,"can-resize":true})};setFatalErrorGeometry();setInterval(setFatalErrorGeometry,1e3)}if(Byond.strictMode){Byond.sendMessage({type:"log",fatal:1,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})}if(Byond.strictMode){window.update=function(){};window.update.queue=[]}return true};window.onunhandledrejection=function(e){let msg="UnhandledRejection";if(e.reason){msg+=": "+(e.reason.message||e.reason.description||e.reason);if(e.reason.stack){e.reason.stack=`UnhandledRejection: ${e.reason.stack}`}}window.onerror(msg,null,null,null,e.reason)};window.__augmentStack__=function(stack,error){return`${stack}\nUser Agent: ${navigator.userAgent}`};window.update=function(rawMessage){if(window.update.queueActive){window.update.queue.push(rawMessage);return}const message=Byond.parseJson(rawMessage);const listeners=window.update.listeners;for(let i=0;i{window.update.queue=[]},0)}}const queue=window.update.queue;for(let i=0;i {
+ console.log(
+ `Indexed DB state: ${persistent ? 'Persistent' : 'Not persistent'}`,
+ );
+ });
+ }
+
const dbPromise = new Promise((resolve, reject) => {
const indexedDB = window.indexedDB;
const req = indexedDB.open(storeValue, INDEXED_DB_VERSION);
@@ -26,14 +34,14 @@
req.result.createObjectStore(INDEXED_DB_STORE_NAME);
}
} catch (err) {
- reject(new Error('Failed to upgrade IDB: ' + req.error));
+ reject(new Error(`Failed to upgrade IDB: ${req.error}`));
}
};
req.onsuccess = () => resolve(req.result);
req.onerror = () => {
- reject(new Error('Failed to open IDB: ' + req.error));
+ reject(new Error(`Failed to open IDB: ${req.error}`));
};
});