diff --git a/src/Message/MessageHelpers.js b/src/Message/MessageHelpers.js index 4932c7be2..79bda4adc 100644 --- a/src/Message/MessageHelpers.js +++ b/src/Message/MessageHelpers.js @@ -7,7 +7,7 @@ import { Player } from "../Player"; import { redPillFlag } from "../RedPill"; import { GetServerByHostname } from "../Server/ServerHelpers"; import { Settings } from "../Settings/Settings"; -import { dialogBoxCreate, dialogBoxOpened} from "../../utils/DialogBox"; +import { dialogBoxCreate} from "../../utils/DialogBox"; import { Reviver } from "../../utils/JSONReviver"; //Sends message to player, including a pop up @@ -59,12 +59,10 @@ function checkForMessagesToSend() { } if (redpill && redpillOwned && Player.sourceFiles.length === 0 && !redPillFlag && !inMission) { - if (!dialogBoxOpened) { - sendMessage(redpill, true); - } + sendMessage(redpill, true); } else if (redpill && redpillOwned) { //If player has already destroyed a BitNode, message is not forced - if (!redPillFlag && !inMission && !dialogBoxOpened) { + if (!redPillFlag && !inMission) { sendMessage(redpill); } } else if (jumper0 && !jumper0.recvd && Player.hacking_skill >= 25) { diff --git a/src/ui/React/Popup.tsx b/src/ui/React/Popup.tsx index cc777eaa9..c7d7e3004 100644 --- a/src/ui/React/Popup.tsx +++ b/src/ui/React/Popup.tsx @@ -3,15 +3,27 @@ * * Takes in a prop for rendering the content inside the popup */ -import * as React from "react"; +import React, { useEffect } from "react"; interface IProps { content: (props: T) => React.ReactElement; id: string; props: T; + removePopup: (id: string) => void; } export function Popup(props: IProps): React.ReactElement { + function keyDown(event: KeyboardEvent): void { + if(event.key === 'Escape') props.removePopup(props.id); + } + + useEffect(() => { + document.addEventListener('keydown', keyDown); + return () => { + document.removeEventListener('keydown', keyDown); + } + }); + return (
{React.createElement(props.content, props.props)} diff --git a/src/ui/React/createPopup.tsx b/src/ui/React/createPopup.tsx index 36e1085ea..df24bcfaa 100644 --- a/src/ui/React/createPopup.tsx +++ b/src/ui/React/createPopup.tsx @@ -16,20 +16,27 @@ import { removeElementById } from "../../../utils/uiHelpers/removeElementById"; let gameContainer: HTMLElement; -function getGameContainer(): void { - const container = document.getElementById("entire-game-container"); - if (container == null) { - throw new Error(`Failed to find game container DOM element`) +(function() { + function getGameContainer(): void { + const container = document.getElementById("entire-game-container"); + if (container == null) { + throw new Error(`Failed to find game container DOM element`) + } + + gameContainer = container; + document.removeEventListener("DOMContentLoaded", getGameContainer); } - gameContainer = container; - document.removeEventListener("DOMContentLoaded", getGameContainer); -} + document.addEventListener("DOMContentLoaded", getGameContainer); +})(); -document.addEventListener("DOMContentLoaded", getGameContainer); +// This variable is used to avoid setting the semi-transparent background +// several times on top of one another. Sometimes there's several popup at once. +let deepestPopupId: string = ""; // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types export function createPopup(id: string, rootComponent: (props: T) => React.ReactElement, props: T): HTMLElement | null { + let container = document.getElementById(id); if (container == null) { function onClick(this: HTMLElement, event: MouseEvent): any { @@ -39,19 +46,20 @@ export function createPopup(id: string, rootComponent: (props: T) => React.Re if(clickedId !== id) return; removePopup(id); } + const backgroundColor = deepestPopupId === "" ? 'rgba(0,0,0,0.5)' : 'rgba(0,0,0,0)'; container = createElement("div", { class: "popup-box-container", display: "flex", id: id, - backgroundColor: 'rgba(0,0,0,0.5)', + backgroundColor: backgroundColor, clickListener: onClick, }); gameContainer.appendChild(container); - } - ReactDOM.render(, container); + if(deepestPopupId === "") deepestPopupId = id; + ReactDOM.render(, container); return container; } @@ -67,4 +75,5 @@ export function removePopup(id: string): void { removeElementById(id); removeElementById(`${id}-close`); + if(id === deepestPopupId) deepestPopupId = ""; } diff --git a/utils/DialogBox.d.ts b/utils/DialogBox.d.ts deleted file mode 100644 index 87e1ea85a..000000000 --- a/utils/DialogBox.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -export function dialogBoxCreate(txt: string | JSX.Element, preformatted?: boolean): void; -export let dialogBoxOpened: boolean; diff --git a/utils/DialogBox.jsx b/utils/DialogBox.jsx deleted file mode 100644 index 56d5daa9c..000000000 --- a/utils/DialogBox.jsx +++ /dev/null @@ -1,76 +0,0 @@ -import { KEY } from "./helpers/keyCodes"; -import { DialogBox } from "./ui/DialogBox"; -import React from "react"; -import ReactDOM from "react-dom"; - -/** - * Create and display a pop-up dialog box. - * This dialog box does not allow for any interaction and should close when clicking - * outside of it - */ -let dialogBoxes = []; - -// Close dialog box when clicking outside -$(document).click(function(event) { - if (dialogBoxOpened && dialogBoxes.length >= 1) { - if (!$(event.target).closest(dialogBoxes[0]).length){ - closeTopmostDialogBox(); - } - } -}); - -function closeTopmostDialogBox() { - if (!dialogBoxOpened || dialogBoxes.length === 0) return; - dialogBoxes[0].remove(); - dialogBoxes.shift(); - if (dialogBoxes.length == 0) { - dialogBoxOpened = false; - } else { - dialogBoxes[0].style.visibility = "visible"; - } -} - -// Dialog box close buttons -$(document).on('click', '.dialog-box-close-button', function() { - closeTopmostDialogBox(); -}); - -document.addEventListener("keydown", function (event) { - if (event.keyCode == KEY.ESC && dialogBoxOpened) { - closeTopmostDialogBox(); - event.preventDefault(); - } -}); - -let dialogBoxOpened = false; - - - -function dialogBoxCreate(txt, preformatted=false) { - const container = document.createElement("div"); - container.setAttribute("class", "dialog-box-container"); - - let elem = txt; - if (typeof txt === 'string') { - if (preformatted) { - // For text files as they are often computed data that - // shouldn't be wrapped and should retain tabstops. - elem =
-        } else {
-            elem = 

') }} /> - } - } - - ReactDOM.render(DialogBox(elem), container); - document.body.appendChild(container); - if (dialogBoxes.length >= 1) { - container.style.visibility = "hidden"; - } - dialogBoxes.push(container); - - setTimeout(function() { - dialogBoxOpened = true; - }, 400); -} - -export {dialogBoxCreate, dialogBoxOpened}; diff --git a/utils/DialogBox.tsx b/utils/DialogBox.tsx new file mode 100644 index 000000000..8d42d471d --- /dev/null +++ b/utils/DialogBox.tsx @@ -0,0 +1,38 @@ +import { KEY } from "./helpers/keyCodes"; +import { DialogBox } from "./ui/DialogBox"; +import { createPopup } from "../src/ui/React/createPopup"; +import { getRandomInt } from "./helpers/getRandomInt"; + +import React from "react"; +import ReactDOM from "react-dom"; + +interface IProps { + content: JSX.Element; +} + +export function MessagePopup(props: IProps): React.ReactElement { + return (<>{props.content}); +} + +function dialogBoxCreate(txt: string | JSX.Element, preformatted: boolean = false): void { + const popupId = `popup-`+(Array.from(Array(16))).map(() => `${getRandomInt(0, 9)}`).join(''); + if (typeof txt === 'string') { + if (preformatted) { + // For text files as they are often computed data that + // shouldn't be wrapped and should retain tabstops. + createPopup(popupId, MessagePopup, { + content: (

)
+            });
+        } else {
+            createPopup(popupId, MessagePopup, {
+                content: (

') }} />) + }); + } + } else { + createPopup(popupId, MessagePopup, { + content: txt + }); + } +} + +export {dialogBoxCreate};