diff --git a/code/modules/client/asset_cache.dm b/code/modules/client/asset_cache.dm index ff1eac08238..d5f6b6f7545 100644 --- a/code/modules/client/asset_cache.dm +++ b/code/modules/client/asset_cache.dm @@ -396,7 +396,6 @@ GLOBAL_LIST_EMPTY(asset_datums) "tgui-fallback.html" = 'tgui-next/packages/tgui/public/tgui-fallback.html', "tgui.bundle.js" = 'tgui-next/packages/tgui/public/tgui.bundle.js', "tgui.bundle.css" = 'tgui-next/packages/tgui/public/tgui.bundle.css', - "shim-console.js" = 'tgui-next/packages/tgui/public/shim-console.js', "shim-html5shiv.js" = 'tgui-next/packages/tgui/public/shim-html5shiv.js', "shim-ie8.js" = 'tgui-next/packages/tgui/public/shim-ie8.js', "shim-dom4.js" = 'tgui-next/packages/tgui/public/shim-dom4.js', diff --git a/code/modules/tgui/tgui.dm b/code/modules/tgui/tgui.dm index df7da3ceff1..6faf4aed69a 100644 --- a/code/modules/tgui/tgui.dm +++ b/code/modules/tgui/tgui.dm @@ -67,7 +67,7 @@ src.user = user src.src_object = src_object src.ui_key = ui_key - src.window_id = browser_id ? browser_id : "[REF(src_object)]-[ui_key]" + src.window_id = browser_id ? browser_id : "[REF(src_object)]-[ui_key]" // DO NOT replace with \ref here. src_object could potentially be tagged src.custom_browser_id = browser_id ? TRUE : FALSE set_interface(interface) @@ -100,19 +100,37 @@ if(status < UI_UPDATE) return // Bail if we're not supposed to open. - var/window_size = "" + var/window_size if(width && height) // If we have a width and height, use them. window_size = "size=[width]x[height];" + else + window_size = "" // Remove titlebar and resize handles for a fancy window - // right from the beginning - var/have_title_bar = "" + var/have_title_bar if(user.client.prefs.tgui_fancy) - have_title_bar = "titlebar=0;can_resize=0" + have_title_bar = "titlebar=0;can_resize=0;" + else + have_title_bar = "titlebar=1;can_resize=1;" - user << browse(get_html(), "window=[window_id];can_minimize=0;auto_format=0;[window_size][have_title_bar]") // Open the window. + // Generate page html + var/html + html = SStgui.basehtml + // Allow the src object to override the html if needed + html = src_object.ui_base_html(html) + // Replace template tokens with important UI data + // NOTE: Intentional \ref usage; tgui datums can't/shouldn't + // be tagged, so this is an effective unwrap + html = replacetextEx(html, "\[ref]", "\ref[src]") + html = replacetextEx(html, "\[style]", style) + + // Open the window. + user << browse(html, "window=[window_id];can_minimize=0;auto_format=0;[window_size][have_title_bar]") if (!custom_browser_id) - winset(user, window_id, "on-close=\"uiclose [REF(src)]\"") // Instruct the client to signal UI when the window is closed. + // Instruct the client to signal UI when the window is closed. + // NOTE: Intentional \ref usage; tgui datums can't/shouldn't + // be tagged, so this is an effective unwrap + winset(user, window_id, "on-close=\"uiclose \ref[src]\"") if(!initial_data) initial_data = src_object.ui_data(user) @@ -185,57 +203,6 @@ /datum/tgui/proc/set_autoupdate(state = TRUE) autoupdate = state - /** - * private - * - * Generate HTML for this UI. - * - * return string UI HTML output. - **/ -/datum/tgui/proc/get_html() - var/html - html = SStgui.basehtml - - //Allow the src object to override the html if needed - html = src_object.ui_base_html(html) - //Strip out any remaining custom tags that are used in ui_base_html - html = replacetext(html, "", "") - - //Setup for tgui stuff, including styles - html = replacetextEx(html, "\[ref]", "[REF(src)]") - html = replacetextEx(html, "\[style]", style) - return html - - /** - * private - * - * Get the config data/datastructure to initialize the UI with. - * - * return list The config data. - **/ -/datum/tgui/proc/get_config_data() - var/list/config_data = list( - "title" = title, - "status" = status, - "screen" = ui_screen, - "style" = style, - "interface" = interface, - "fancy" = user.client.prefs.tgui_fancy, - "locked" = user.client.prefs.tgui_lock && !custom_browser_id, - "window" = window_id, - "ref" = "[REF(src)]", - "user" = list( - "name" = user.name, - "ref" = "[REF(user)]" - ), - "srcObject" = list( - "name" = "[src_object]", - "ref" = "[REF(src_object)]" - ), - "titlebar" = titlebar - ) - return config_data - /** * private * @@ -247,7 +214,19 @@ /datum/tgui/proc/get_json(list/data, list/static_data) var/list/json_data = list() - json_data["config"] = get_config_data() + json_data["config"] = list( + "title" = title, + "status" = status, + "screen" = ui_screen, + "style" = style, + "interface" = interface, + "fancy" = user.client.prefs.tgui_fancy, + "locked" = user.client.prefs.tgui_lock && !custom_browser_id, + "window" = window_id, + // Intentional \ref usage; tgui datums can't/shouldn't be tagged so this is an effective unwrap + "ref" = "\ref[src]" + ) + if(!isnull(data)) json_data["data"] = data if(!isnull(static_data)) diff --git a/tgui-next/packages/tgui/drag.js b/tgui-next/packages/tgui/drag.js index 0e42ea12a0b..49e7eb87c74 100644 --- a/tgui-next/packages/tgui/drag.js +++ b/tgui-next/packages/tgui/drag.js @@ -29,9 +29,47 @@ export const setupDrag = async state => { x: realPosition.x - window.screenX, y: realPosition.y - window.screenY, }; + // Constraint window position + const [relocated, safePosition] = constraintPosition(realPosition); + if (relocated) { + winset(dragState.windowRef, 'pos', [ + safePosition.x, + safePosition.y, + ].join(',')); + } logger.debug('current dragState', dragState); }; +/** + * Constraints window position to safe screen area, accounting for safe + * margins which could be a system taskbar. + */ +const constraintPosition = position => { + let { x, y } = position; + let relocated = false; + // Left + if (x < 0) { + x = 0; + relocated = true; + } + // Right + else if (x + window.innerWidth > window.screen.availWidth) { + x = window.screen.availWidth - window.innerWidth; + relocated = true; + } + // Top + if (y < 0) { + y = 0; + relocated = true; + } + // Bottom + else if (y + window.innerHeight > window.screen.availHeight) { + y = window.screen.availHeight - window.innerHeight; + relocated = true; + } + return [relocated, { x, y }]; +}; + export const dragStartHandler = event => { logger.log('drag start'); dragState.dragging = true; diff --git a/tgui-next/packages/tgui/index.js b/tgui-next/packages/tgui/index.js index f04e988e839..4f02ec65a5f 100644 --- a/tgui-next/packages/tgui/index.js +++ b/tgui-next/packages/tgui/index.js @@ -6,9 +6,9 @@ import { loadCSS } from 'fg-loadcss'; import { render } from 'inferno'; import { setupHotReloading } from 'tgui-dev-server/link/client'; import { backendUpdate } from './backend'; -import { act, tridentVersion } from './byond'; +import { tridentVersion } from './byond'; import { setupDrag } from './drag'; -import { createLogger, setLoggerRef } from './logging'; +import { createLogger } from './logging'; import { getRoute } from './routes'; import { createStore } from './store'; @@ -33,6 +33,8 @@ const renderLayout = () => { const state = store.getState(); // Initial render setup if (initialRender) { + logger.log('initial render', state); + // ----- Old TGUI chain-loader: begin ----- const route = getRoute(state); // Route was not found, load old TGUI @@ -45,7 +47,7 @@ const renderLayout = () => { // Load old TGUI using redirection method for IE8 if (tridentVersion <= 4) { setTimeout(() => { - location.href = 'tgui-fallback.html?ref=' + ref; + location.href = 'tgui-fallback.html?ref=' + window.__ref__; }, 10); return; } @@ -65,8 +67,6 @@ const renderLayout = () => { } // ----- Old TGUI chain-loader: end ----- - logger.log('initial render', state); - // Setup dragging setupDrag(state); } @@ -107,14 +107,7 @@ const parseStateJson = json => { }; const setupApp = () => { - // Find data in the page, load inlined state. - const holder = document.getElementById('data'); - const ref = holder.getAttribute('data-ref'); - - // Initialize logger - setLoggerRef(ref); - - // Subscribe for state updates + // Subscribe for redux state updates store.subscribe(() => { renderLayout(); }); @@ -134,8 +127,14 @@ const setupApp = () => { }); } - // Initialize - act(ref, 'tgui:initialize'); + // Process the early update queue + while (true) { + let stateJson = window.__updateQueue__.shift(); + if (!stateJson) { + break; + } + window.update(stateJson); + } // Dynamically load font-awesome from browser's cache loadCSS('font-awesome.css'); diff --git a/tgui-next/packages/tgui/logging.js b/tgui-next/packages/tgui/logging.js index fc881e01e6a..b0b6f671585 100644 --- a/tgui-next/packages/tgui/logging.js +++ b/tgui-next/packages/tgui/logging.js @@ -1,12 +1,6 @@ import { sendLogEntry } from 'tgui-dev-server/link/client'; import { act } from './byond'; -let _ref = null; - -export const setLoggerRef = ref => { - _ref = ref; -}; - const LEVEL_DEBUG = 0; const LEVEL_LOG = 1; const LEVEL_INFO = 2; @@ -33,7 +27,7 @@ const log = (level, ns, ...args) => { .filter(value => value) .join(' ') + '\nUser Agent: ' + navigator.userAgent; - act(_ref, 'tgui:log', { + act(window.__ref__, 'tgui:log', { log: logEntry, }); } diff --git a/tgui-next/packages/tgui/package.json b/tgui-next/packages/tgui/package.json index fb7df62330c..729cee60ecf 100644 --- a/tgui-next/packages/tgui/package.json +++ b/tgui-next/packages/tgui/package.json @@ -8,6 +8,7 @@ "@babel/preset-env": "^7.6.2", "babel-loader": "^8.0.6", "babel-plugin-inferno": "^6.1.0", + "babel-plugin-transform-remove-console": "^6.9.4", "core-js": "^3.2.1", "css-loader": "^3.2.0", "cssnano": "^4.1.10", diff --git a/tgui-next/packages/tgui/public/shim-console.js b/tgui-next/packages/tgui/public/shim-console.js deleted file mode 100644 index 75ba1efa657..00000000000 --- a/tgui-next/packages/tgui/public/shim-console.js +++ /dev/null @@ -1,55 +0,0 @@ -/** - * Shims the console in embedded IE8 window. - * - * You can subscribe using console.__subscribe__(fn) to handle - * incoming log messages, otherwise they will be simply lost. - */ - -/* eslint-disable */ -(function () { - -// Ignore user agents with console. -if (window.console) { - return; -} - -var noop = function () {}; - -var handleLogs = function () { - for (var i = 0; i < subscribers.length; i++) { - subscribers[i].apply(null, arguments); - } -}; - -var subscribers = []; - -// Start shimming -window.console = {}; - -console.__subscribe__ = function (fn) { - subscribers.push(fn); -}; - -console.debug = handleLogs; -console.error = handleLogs; -console.info = handleLogs; -console.log = handleLogs; -console.trace = handleLogs; -console.warn = handleLogs; - -console.assert = noop; -console.count = noop; -console.dir = noop; -console.dirxml = noop; -console.exception = noop; -console.group = noop; -console.groupCollapsed = noop; -console.groupEnd = noop; -console.table = noop; -console.clear = noop; -console.count = noop; -console.profile = noop; -console.profileEnd = noop; -console.timeStamp = noop; - -})(); diff --git a/tgui-next/packages/tgui/public/shim-css-om.js b/tgui-next/packages/tgui/public/shim-css-om.js index a033b9d93b7..82964c71c7a 100644 --- a/tgui-next/packages/tgui/public/shim-css-om.js +++ b/tgui-next/packages/tgui/public/shim-css-om.js @@ -1,6 +1,5 @@ /** * CSS Object Model patches - * * Adapted from: https://github.com/shawnbot/aight */ diff --git a/tgui-next/packages/tgui/public/shim-dom4.js b/tgui-next/packages/tgui/public/shim-dom4.js index 074c7a5c9f4..3c972e70ba0 100644 --- a/tgui-next/packages/tgui/public/shim-dom4.js +++ b/tgui-next/packages/tgui/public/shim-dom4.js @@ -1,23 +1,6 @@ /** - * Copyright (C) 2013-2015 by Andrea Giammarchi - @WebReflection - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * Copyright (c) 2013 Andrea Giammarchi @WebReflection + * SPDX-License-Identifier: MIT */ /* eslint-disable */ diff --git a/tgui-next/packages/tgui/public/shim-html5shiv.js b/tgui-next/packages/tgui/public/shim-html5shiv.js index 6027449ccbc..6600c4f9118 100644 --- a/tgui-next/packages/tgui/public/shim-html5shiv.js +++ b/tgui-next/packages/tgui/public/shim-html5shiv.js @@ -1,6 +1,6 @@ /** - * HTML5 Shiv 3.7.3 | @afarkas @jdalton @jon_neal @rem - * MIT/GPL2 Licensed + * Copyright (c) 2014 Alexander Farkas + * SPDX-License-Identifier: MIT */ /* eslint-disable */ diff --git a/tgui-next/packages/tgui/public/shim-ie8.js b/tgui-next/packages/tgui/public/shim-ie8.js index efb4eae3f40..72eb8b916d0 100644 --- a/tgui-next/packages/tgui/public/shim-ie8.js +++ b/tgui-next/packages/tgui/public/shim-ie8.js @@ -1,23 +1,6 @@ /** - * Copyright (C) 2013-2015 by WebReflection - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * Copyright (c) 2013 Andrea Giammarchi @WebReflection + * SPDX-License-Identifier: MIT */ /* eslint-disable */ diff --git a/tgui-next/packages/tgui/public/tgui-main.html b/tgui-next/packages/tgui/public/tgui-main.html index 7e547ce5d53..6d8a5f8a60f 100644 --- a/tgui-next/packages/tgui/public/tgui-main.html +++ b/tgui-next/packages/tgui/public/tgui-main.html @@ -4,13 +4,47 @@ + + + + - + + + + + + +
@@ -21,31 +55,6 @@ - - - - - - - - -