Files
GS13NG/tgui/public/tgui.html
2020-09-02 17:52:47 +03:00

328 lines
9.7 KiB
HTML

<!DOCTYPE html>
<html>
<head>
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta charset="utf-8">
<!-- Inlined data -->
<meta id="tgui:windowId" content="[tgui:windowId]">
<!-- Early setup -->
<script type="text/javascript">
// Read window id into a global
window.__windowId__ = document
.getElementById('tgui:windowId')
.getAttribute('content');
if (window.__windowId__ === '[' + 'tgui:windowId' + ']') {
window.__windowId__ = null;
}
// BYOND API object
window.Byond = (function () {
var Byond = {};
// Utility functions
var hasOwn = Object.prototype.hasOwnProperty;
var assign = function (target) {
for (var i = 1; i < arguments.length; i++) {
var source = arguments[i];
for (var key in source) {
if (hasOwn.call(source, key)) {
target[key] = source[key];
}
}
}
return target;
};
// Trident engine version
var tridentVersion = (function () {
var groups = navigator.userAgent.match(/Trident\/(\d+).+?;/i);
var majorVersion = groups && groups[1];
return majorVersion
? parseInt(majorVersion, 10)
: null;
})();
// Basic checks to detect whether this page runs in BYOND
var isByond = tridentVersion !== null
&& location.hostname === '127.0.0.1'
&& location.pathname.indexOf('/tmp') === 0
&& location.search !== '?external';
// Version constants
Byond.IS_BYOND = isByond;
Byond.IS_LTE_IE8 = tridentVersion !== null && tridentVersion <= 4;
Byond.IS_LTE_IE9 = tridentVersion !== null && tridentVersion <= 5;
Byond.IS_LTE_IE10 = tridentVersion !== null && tridentVersion <= 6;
Byond.IS_LTE_IE11 = tridentVersion !== null && tridentVersion <= 7;
// Callbacks for asynchronous calls
Byond.__callbacks__ = [];
// Reviver for BYOND JSON
// IE8: No reviver for you!
// See: https://stackoverflow.com/questions/1288962
var byondJsonReviver;
if (!Byond.IS_LTE_IE8) {
byondJsonReviver = function (key, value) {
if (typeof value === 'object' && value !== null && value.__number__) {
return parseFloat(value.__number__);
}
return value;
};
}
// Makes a BYOND call.
// See: https://secure.byond.com/docs/ref/skinparams.html
Byond.call = function (path, params) {
// Not running in BYOND, abort.
if (!isByond) {
return;
}
// Build the URL
var url = (path || '') + '?';
var i = 0;
if (params) {
for (var key in params) {
if (hasOwn.call(params, key)) {
if (i++ > 0) {
url += '&';
}
var value = params[key];
if (value === null || value === undefined) {
value = '';
}
url += encodeURIComponent(key)
+ '=' + encodeURIComponent(value)
}
}
}
// Perform a standard call via location.href
if (url.length < 2048) {
location.href = 'byond://' + url;
return;
}
// Send an HTTP request to DreamSeeker's HTTP server.
// Allows sending much bigger payloads.
var 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.');
}
var index = Byond.__callbacks__.length;
var promise = new window.Promise(function (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) {
var isArray = propName instanceof Array;
var isSpecific = propName && propName !== '*' && !isArray;
var promise = Byond.callAsync('winget', {
id: id,
property: isArray && propName.join(',') || propName || '*',
});
if (isSpecific) {
promise = promise.then(function (props) {
return props[propName];
});
}
return promise;
};
Byond.winset = function (id, propName, propValue) {
if (typeof id === 'object' && id !== null) {
return Byond.call('winset', id);
}
var 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));
}
};
return Byond;
})();
// Global error handling
window.onerror = function (msg, url, line, col, error) {
// Proper stacktrace
var stack = error && error.stack;
// Ghetto stacktrace
if (!stack) {
stack = msg + '\n at ' + url + ':' + line;
if (col) {
stack += ':' + col;
}
}
// Augment the stack
stack = window.__augmentStack__(stack, error);
// Print error to the page
var errorRoot = document.getElementById('FatalError');
var errorStack = document.getElementById('FatalError__stack');
if (errorRoot) {
errorRoot.className = 'FatalError';
if (errorStack.textContent) {
errorStack.textContent += '\n\n' + stack;
}
else {
errorStack.textContent = stack;
}
}
// Set window geometry
var setFatalErrorGeometry = function () {
Byond.winset(window.__windowId__, {
titlebar: true,
size: '600x600',
'is-visible': true,
'can-resize': true,
});
};
setFatalErrorGeometry();
setInterval(setFatalErrorGeometry, 1000);
// Send logs to the game server
Byond.topic({
tgui: 1,
window_id: window.__windowId__,
type: 'log',
fatal: 1,
message: stack,
});
// Short-circuit further updates
window.__updateQueue__ = [];
window.update = function () {};
// Prevent default action
return true;
};
// Catch unhandled rejections
window.onunhandledrejection = window.onerror;
// Helper for augmenting stack traces on fatal errors
window.__augmentStack__ = function (stack, error) {
return stack + '\nUser Agent: ' + navigator.userAgent;
};
// Early initialization
window.__updateQueue__ = [];
window.update = function (message) {
window.__updateQueue__.push(message);
};
Byond.topic({
tgui: 1,
window_id: window.__windowId__,
type: 'ready',
});
// Necessary polyfill to make Webpack code splitting work on IE8
if (!Function.prototype.bind) (function () {
var slice = Array.prototype.slice;
Function.prototype.bind = function () {
var thatFunc = this, thatArg = arguments[0];
var args = slice.call(arguments, 1);
if (typeof thatFunc !== 'function') {
// closest thing possible to the ECMAScript 5
// internal IsCallable function
throw new TypeError('Function.prototype.bind - ' +
'what is trying to be bound is not callable');
}
return function () {
var funcArgs = args.concat(slice.call(arguments))
return thatFunc.apply(thatArg, funcArgs);
};
};
})();
</script>
<!-- Styles -->
<!-- tgui:styles -->
<!-- Scripts -->
<!-- tgui:scripts -->
</head>
<body>
<!-- Inline HTML -->
<!-- tgui:html -->
<!-- tgui container -->
<div id="react-root"></div>
<!-- Fatal error container -->
<div id="FatalError" style="display: none">
<div class="FatalError__logo">
_____ _____ _______ _____
/\ \ /\ \ /::\ \ /\ \
/::\____\ /::\ \ /::::\ \ /::\ \
/::::| | \:::\ \ /::::::\ \ /::::\ \
/:::::| | \:::\ \ /::::::::\ \ /::::::\ \
/::::::| | \:::\ \ /:::/~~\:::\ \ /:::/\:::\ \
/:::/|::| | \:::\ \ /:::/ \:::\ \ /:::/__\:::\ \
/:::/ |::| | /::::\ \ /:::/ / \:::\ \ \:::\ \:::\ \
/:::/ |::| | _____ /::::::\ \ /:::/____/ \:::\____\ ___\:::\ \:::\ \
/:::/ |::| |/\ \ /:::/\:::\ \|:::| | |:::| |/\ \:::\ \:::\ \
/:: / |::| /::\____\/:::/ \:::\____\:::|____| |:::| /::\ \:::\ \:::\____\
\::/ /|::| /:::/ /:::/ \::/ /\:::\ \ /:::/ /\:::\ \:::\ \::/ /
\/____/ |::| /:::/ /:::/ / \/____/ \:::\ \ /:::/ / \:::\ \:::\ \/____/
|::|/:::/ /:::/ / \:::\ /:::/ / \:::\ \:::\ \
|::::::/ /:::/ / \:::\__/:::/ / \:::\ \:::\____\
|:::::/ /\::/ / \::::::::/ / \:::\ /:::/ /
|::::/ / \/____/ \::::::/ / \:::\/:::/ /
/:::/ / \::::/ / \::::::/ /
/:::/ / \::/____/ \::::/ /
\::/ / \::/ /
\/____/ \/____/
</div>
<marquee class="FatalError__header">
A fatal exception has occurred at 002B:C562F1B7 in TGUI.
The current application will be terminated.
Please remain calm. Get to the nearest NTNet workstation
and send the copy of the following stack trace to:
www.github.com/tgstation/tgstation. Thank you for your cooperation.
</marquee>
<div id="FatalError__stack" class="FatalError__stack"></div>
<div class="FatalError__footer">
Nanotrasen (c) 2525-2559
</div>
</div>
<noscript>
<div class="NoticeBox">
<div>Javascript is required in order to use this interface.</div>
<div>Please enable Javascript and restart the game.</div>
</div>
</noscript>
</body>
</html>