mirror of
https://github.com/bitburner-official/bitburner-src.git
synced 2024-12-19 04:35:46 +01:00
Refactored 'workerScripts' array and killWorkerScript() fn to be their own modules in TypeScript
This commit is contained in:
parent
b1248521f3
commit
42804b0cd3
119
css/activescripts.scss
Normal file
119
css/activescripts.scss
Normal file
@ -0,0 +1,119 @@
|
||||
@import "theme";
|
||||
|
||||
.active-scripts-list {
|
||||
list-style-type: none;
|
||||
}
|
||||
|
||||
#active-scripts-container {
|
||||
position: fixed;
|
||||
padding-top: 10px;
|
||||
|
||||
> p {
|
||||
width: 70%;
|
||||
margin: 6px;
|
||||
padding: 4px;
|
||||
}
|
||||
}
|
||||
|
||||
.active-scripts-server-header {
|
||||
background-color: #444;
|
||||
font-size: $defaultFontSize * 1.25;
|
||||
color: #fff;
|
||||
margin: 6px 6px 0 6px;
|
||||
padding: 6px;
|
||||
cursor: pointer;
|
||||
width: 60%;
|
||||
text-align: left;
|
||||
border: none;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.active-scripts-server-header.active,
|
||||
.active-scripts-server-header:hover {
|
||||
background-color: #555;
|
||||
}
|
||||
|
||||
.active-scripts-server-header.active:hover {
|
||||
background-color: #666;
|
||||
}
|
||||
|
||||
.active-scripts-server-header:after {
|
||||
content: '\02795'; /* "plus" sign (+) */
|
||||
font-size: $defaultFontSize * 0.8125;
|
||||
color: #fff;
|
||||
float: right;
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
.active-scripts-server-header.active:after {
|
||||
content: "\2796"; /* "minus" sign (-) */
|
||||
font-size: $defaultFontSize * 0.8125;
|
||||
color: #fff;
|
||||
float: right;
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
.active-scripts-server-panel {
|
||||
margin: 0 6px 6px 6px;
|
||||
padding: 0 6px 6px 6px;
|
||||
width: 55%;
|
||||
margin-left: 5%;
|
||||
display: none;
|
||||
}
|
||||
|
||||
.active-scripts-server-panel div,
|
||||
.active-scripts-server-panel ul,
|
||||
.active-scripts-server-panel ul > li {
|
||||
background-color: #555;
|
||||
}
|
||||
|
||||
.active-scripts-script-header {
|
||||
background-color: #555;
|
||||
color: var(--my-font-color);
|
||||
padding: 4px 25px 4px 10px;
|
||||
cursor: pointer;
|
||||
width: auto;
|
||||
text-align: left;
|
||||
border: none;
|
||||
outline: none;
|
||||
position: relative;
|
||||
|
||||
&:after {
|
||||
content: '\02795'; /* "plus" sign (+) */
|
||||
font-size: $defaultFontSize * 0.8125;
|
||||
float: right;
|
||||
margin-left: 5px;
|
||||
color: transparent;
|
||||
text-shadow: 0 0 0 var(--my-font-color);
|
||||
position: absolute;
|
||||
bottom: 4px;
|
||||
}
|
||||
|
||||
&.active:after {
|
||||
content: "\2796"; /* "minus" sign (-) */
|
||||
}
|
||||
|
||||
&:hover,
|
||||
&.active:hover {
|
||||
background-color: #666;
|
||||
}
|
||||
|
||||
&.active {
|
||||
background-color: #555;
|
||||
}
|
||||
}
|
||||
|
||||
.active-scripts-script-panel {
|
||||
padding: 0 18px;
|
||||
background-color: #555;
|
||||
width: auto;
|
||||
display: none;
|
||||
margin-bottom: 6px;
|
||||
|
||||
p, h2, ul, li {
|
||||
background-color: #555;
|
||||
width: auto;
|
||||
color: #fff;
|
||||
margin-left: 5%;
|
||||
}
|
||||
}
|
@ -18,126 +18,6 @@
|
||||
position: fixed;
|
||||
}
|
||||
|
||||
/* Active scripts */
|
||||
.active-scripts-list {
|
||||
list-style-type: none;
|
||||
}
|
||||
|
||||
#active-scripts-container {
|
||||
position: fixed;
|
||||
padding-top: 10px;
|
||||
}
|
||||
|
||||
#active-scripts-text,
|
||||
#active-scripts-total-prod {
|
||||
width: 70%;
|
||||
margin: 6px;
|
||||
padding: 4px;
|
||||
}
|
||||
|
||||
.active-scripts-server-header {
|
||||
background-color: #444;
|
||||
font-size: $defaultFontSize * 1.25;
|
||||
color: #fff;
|
||||
margin: 6px 6px 0 6px;
|
||||
padding: 6px;
|
||||
cursor: pointer;
|
||||
width: 60%;
|
||||
text-align: left;
|
||||
border: none;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.active-scripts-server-header.active,
|
||||
.active-scripts-server-header:hover {
|
||||
background-color: #555;
|
||||
}
|
||||
|
||||
.active-scripts-server-header.active:hover {
|
||||
background-color: #666;
|
||||
}
|
||||
|
||||
.active-scripts-server-header:after {
|
||||
content: '\02795'; /* "plus" sign (+) */
|
||||
font-size: $defaultFontSize * 0.8125;
|
||||
color: #fff;
|
||||
float: right;
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
.active-scripts-server-header.active:after {
|
||||
content: "\2796"; /* "minus" sign (-) */
|
||||
font-size: $defaultFontSize * 0.8125;
|
||||
color: #fff;
|
||||
float: right;
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
.active-scripts-server-panel {
|
||||
margin: 0 6px 6px 6px;
|
||||
padding: 0 6px 6px 6px;
|
||||
width: 55%;
|
||||
margin-left: 5%;
|
||||
display: none;
|
||||
}
|
||||
|
||||
.active-scripts-server-panel div,
|
||||
.active-scripts-server-panel ul,
|
||||
.active-scripts-server-panel ul > li {
|
||||
background-color: #555;
|
||||
}
|
||||
|
||||
.active-scripts-script-header {
|
||||
background-color: #555;
|
||||
color: var(--my-font-color);
|
||||
padding: 4px 25px 4px 10px;
|
||||
cursor: pointer;
|
||||
width: auto;
|
||||
text-align: left;
|
||||
border: none;
|
||||
outline: none;
|
||||
position: relative;
|
||||
|
||||
&:after {
|
||||
content: '\02795'; /* "plus" sign (+) */
|
||||
font-size: $defaultFontSize * 0.8125;
|
||||
float: right;
|
||||
margin-left: 5px;
|
||||
color: transparent;
|
||||
text-shadow: 0 0 0 var(--my-font-color);
|
||||
position: absolute;
|
||||
bottom: 4px;
|
||||
}
|
||||
|
||||
&.active:after {
|
||||
content: "\2796"; /* "minus" sign (-) */
|
||||
}
|
||||
|
||||
&:hover,
|
||||
&.active:hover {
|
||||
background-color: #666;
|
||||
}
|
||||
|
||||
&.active {
|
||||
background-color: #555;
|
||||
}
|
||||
}
|
||||
|
||||
.active-scripts-script-panel {
|
||||
padding: 0 18px;
|
||||
background-color: #555;
|
||||
width: auto;
|
||||
display: none;
|
||||
margin-bottom: 6px;
|
||||
|
||||
p, h2, ul, li {
|
||||
background-color: #555;
|
||||
width: auto;
|
||||
color: #fff;
|
||||
margin-left: 5%;
|
||||
}
|
||||
}
|
||||
|
||||
/* World */
|
||||
#world-container {
|
||||
position: fixed;
|
||||
|
@ -32,6 +32,11 @@ export class WorkerScript {
|
||||
*/
|
||||
delay: number | null = null;
|
||||
|
||||
/**
|
||||
* Holds the Promise resolve() function for when the script is "blocked" by an async op
|
||||
*/
|
||||
delayResolve?: () => void;
|
||||
|
||||
/**
|
||||
* Stores names of all functions that have logging disabled
|
||||
*/
|
||||
|
6
src/Netscript/WorkerScripts.ts
Normal file
6
src/Netscript/WorkerScripts.ts
Normal file
@ -0,0 +1,6 @@
|
||||
/**
|
||||
* Global pool of all active scripts (scripts that are currently running)
|
||||
*/
|
||||
import { WorkerScript } from "./WorkerScript";
|
||||
|
||||
export const workerScripts: WorkerScript[] = [];
|
123
src/Netscript/killWorkerScript.ts
Normal file
123
src/Netscript/killWorkerScript.ts
Normal file
@ -0,0 +1,123 @@
|
||||
/**
|
||||
* Function that stops an active script (represented by a WorkerScript object)
|
||||
* and removes it from the global pool of active scripts.
|
||||
*/
|
||||
import { WorkerScript } from "./WorkerScript";
|
||||
import { workerScripts } from "./WorkerScripts";
|
||||
|
||||
import { RunningScript } from "../Script/RunningScript";
|
||||
import { AllServers } from "../Server/AllServers";
|
||||
|
||||
import { compareArrays } from "../../utils/helpers/compareArrays";
|
||||
import { roundToTwo } from "../../utils/helpers/roundToTwo";
|
||||
|
||||
export function killWorkerScript(runningScriptObj: RunningScript, serverIp: string): boolean;
|
||||
export function killWorkerScript(workerScript: WorkerScript): boolean;
|
||||
export function killWorkerScript(script: RunningScript | WorkerScript, serverIp?: string): boolean {
|
||||
if (script instanceof WorkerScript) {
|
||||
script.env.stopFlag = true;
|
||||
killNetscriptDelay(script);
|
||||
removeWorkerScript(script);
|
||||
|
||||
return true;
|
||||
} else if (script instanceof RunningScript && typeof serverIp === "string") {
|
||||
for (let i = 0; i < workerScripts.length; i++) {
|
||||
if (workerScripts[i].name == script.filename && workerScripts[i].serverIp == serverIp &&
|
||||
compareArrays(workerScripts[i].args, script.args)) {
|
||||
workerScripts[i].env.stopFlag = true;
|
||||
killNetscriptDelay(workerScripts[i]);
|
||||
removeWorkerScript(workerScripts[i]);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function that removes the script being killed from the global pool.
|
||||
* Also handles other cleanup-time operations
|
||||
*
|
||||
* @param {WorkerScript | number} - Identifier for WorkerScript. Either the object itself, or
|
||||
* its index in the global workerScripts array
|
||||
*/
|
||||
function removeWorkerScript(id: WorkerScript | number): void {
|
||||
// Get a reference to the WorkerScript and its index in the global pool
|
||||
let workerScript: WorkerScript;
|
||||
let index: number | null = null;
|
||||
|
||||
if (typeof id === "number") {
|
||||
if (id < 0 || id >= workerScripts.length) {
|
||||
console.error(`Too high of an index passed into removeWorkerScript(): ${id}`);
|
||||
return;
|
||||
}
|
||||
|
||||
workerScript = workerScripts[id];
|
||||
index = id;
|
||||
} else if (id instanceof WorkerScript) {
|
||||
workerScript = id;
|
||||
for (let i = 0; i < workerScripts.length; ++i) {
|
||||
if (workerScripts[i] == id) {
|
||||
index = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (index == null) {
|
||||
console.error(`Could not find WorkerScript in global pool:`);
|
||||
console.error(workerScript);
|
||||
}
|
||||
} else {
|
||||
console.error(`Invalid argument passed into removeWorkerScript(): ${id}`);
|
||||
return;
|
||||
}
|
||||
|
||||
const ip = workerScript.serverIp;
|
||||
const name = workerScript.name;
|
||||
|
||||
// Get the server on which the script runs
|
||||
const server = AllServers[ip];
|
||||
if (server == null) {
|
||||
console.error(`Could not find server on which this script is running: ${ip}`);
|
||||
return;
|
||||
}
|
||||
|
||||
// Recalculate ram used on that server
|
||||
server.ramUsed = roundToTwo(server.ramUsed - workerScript.ramUsage);
|
||||
if (server.ramUsed < 0) {
|
||||
console.warn(`Server RAM usage went negative (if it's due to floating pt imprecision, it's okay): ${server.ramUsed}`);
|
||||
server.ramUsed = 0;
|
||||
}
|
||||
|
||||
// Delete the RunningScript object from that server
|
||||
for (let i = 0; i < server.runningScripts.length; ++i) {
|
||||
const runningScript = server.runningScripts[i];
|
||||
if (runningScript.filename === name && compareArrays(runningScript.args, workerScript.args)) {
|
||||
server.runningScripts.splice(i, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Delete script from global pool (workerScripts)
|
||||
workerScripts.splice(<number>index, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function that interrupts a script's delay if it is in the middle of a
|
||||
* timed, blocked operation (like hack(), sleep(), etc.). This allows scripts to
|
||||
* be killed immediately even if they're in the middle of one of those long operations
|
||||
*/
|
||||
function killNetscriptDelay(workerScript: WorkerScript) {
|
||||
if (workerScript instanceof WorkerScript) {
|
||||
if (workerScript.delay) {
|
||||
clearTimeout(workerScript.delay);
|
||||
if (workerScript.delayResolve) {
|
||||
workerScript.delayResolve();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,21 +1,9 @@
|
||||
import { WorkerScript } from "./Netscript/WorkerScript";
|
||||
import { getServer } from "./Server/ServerHelpers";
|
||||
|
||||
import { setTimeoutRef } from "./utils/SetTimeoutRef";
|
||||
import { parse, Node } from "../utils/acorn";
|
||||
|
||||
import { isValidIPAddress } from "../utils/helpers/isValidIPAddress";
|
||||
import { isString } from "../utils/helpers/isString";
|
||||
|
||||
export function killNetscriptDelay(workerScript) {
|
||||
if (workerScript instanceof WorkerScript) {
|
||||
if (workerScript.delay) {
|
||||
clearTimeout(workerScript.delay);
|
||||
workerScript.delayResolve();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function netscriptDelay(time, workerScript) {
|
||||
return new Promise(function(resolve, reject) {
|
||||
workerScript.delay = setTimeoutRef(() => {
|
||||
|
@ -120,11 +120,11 @@ import {
|
||||
} from "./NetscriptBladeburner";
|
||||
import * as nsGang from "./NetscriptGang";
|
||||
import {
|
||||
workerScripts,
|
||||
killWorkerScript,
|
||||
NetscriptPorts,
|
||||
runScriptFromScript,
|
||||
} from "./NetscriptWorker";
|
||||
import { killWorkerScript } from "./Netscript/killWorkerScript";
|
||||
import { workerScripts } from "./Netscript/WorkerScripts";
|
||||
import {
|
||||
makeRuntimeRejectMsg,
|
||||
netscriptDelay,
|
||||
|
@ -3,6 +3,7 @@
|
||||
* that allows for scripts to run
|
||||
*/
|
||||
import { WorkerScript } from "./Netscript/WorkerScript";
|
||||
import { workerScripts } from "./Netscript/WorkerScripts";
|
||||
|
||||
import {
|
||||
addActiveScriptsItem,
|
||||
@ -15,7 +16,6 @@ import { Interpreter } from "./JSInterpreter";
|
||||
import {
|
||||
isScriptErrorMessage,
|
||||
makeRuntimeRejectMsg,
|
||||
killNetscriptDelay
|
||||
} from "./NetscriptEvaluator";
|
||||
import { NetscriptFunctions } from "./NetscriptFunctions";
|
||||
import { executeJSScript } from "./NetscriptJSEvaluator";
|
||||
@ -29,6 +29,7 @@ import {
|
||||
} from "./Script/ScriptHelpers";
|
||||
import { AllServers } from "./Server/AllServers";
|
||||
import { Settings } from "./Settings/Settings";
|
||||
import { EventEmitter } from "./utils/EventEmitter";
|
||||
import { setTimeoutRef } from "./utils/SetTimeoutRef";
|
||||
|
||||
import { generate } from "escodegen";
|
||||
@ -42,14 +43,15 @@ import { isString } from "../utils/StringHelperFunctions";
|
||||
|
||||
const walk = require("acorn/dist/walk");
|
||||
|
||||
//Array containing all scripts that are running across all servers, to easily run them all
|
||||
export const workerScripts = [];
|
||||
|
||||
// Netscript Ports are instantiated here
|
||||
export const NetscriptPorts = [];
|
||||
for (var i = 0; i < CONSTANTS.NumNetscriptPorts; ++i) {
|
||||
NetscriptPorts.push(new NetscriptPort());
|
||||
}
|
||||
|
||||
// WorkerScript-related event emitter. Used for the UI
|
||||
export const WorkerScriptEventEmitter = new EventEmitter();
|
||||
|
||||
export function prestigeWorkerScripts() {
|
||||
for (var i = 0; i < workerScripts.length; ++i) {
|
||||
deleteActiveScriptsItem(workerScripts[i]);
|
||||
@ -415,46 +417,6 @@ function processNetscript1Imports(code, workerScript) {
|
||||
|
||||
// Loop through workerScripts and run every script that is not currently running
|
||||
export function runScriptsLoop() {
|
||||
let scriptDeleted = false;
|
||||
|
||||
// Delete any scripts that finished or have been killed. Loop backwards bc removing items screws up indexing
|
||||
for (let i = workerScripts.length - 1; i >= 0; i--) {
|
||||
if (workerScripts[i].running == false && workerScripts[i].env.stopFlag == true) {
|
||||
scriptDeleted = true;
|
||||
// Delete script from the runningScripts array on its host serverIp
|
||||
const ip = workerScripts[i].serverIp;
|
||||
const name = workerScripts[i].name;
|
||||
|
||||
// Recalculate ram used
|
||||
AllServers[ip].ramUsed = 0;
|
||||
for (let j = 0; j < workerScripts.length; j++) {
|
||||
if (workerScripts[j].serverIp !== ip) {
|
||||
continue;
|
||||
}
|
||||
if (j === i) { // not this one
|
||||
continue;
|
||||
}
|
||||
AllServers[ip].ramUsed += workerScripts[j].ramUsage;
|
||||
}
|
||||
|
||||
// Delete script from Active Scripts
|
||||
deleteActiveScriptsItem(workerScripts[i]);
|
||||
|
||||
for (let j = 0; j < AllServers[ip].runningScripts.length; j++) {
|
||||
if (AllServers[ip].runningScripts[j].filename == name &&
|
||||
compareArrays(AllServers[ip].runningScripts[j].args, workerScripts[i].args)) {
|
||||
AllServers[ip].runningScripts.splice(j, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Delete script from workerScripts
|
||||
workerScripts.splice(i, 1);
|
||||
}
|
||||
}
|
||||
if (scriptDeleted) { updateActiveScriptsItems(); } // Force Update
|
||||
|
||||
|
||||
// Run any scripts that haven't been started
|
||||
for (let i = 0; i < workerScripts.length; i++) {
|
||||
// If it isn't running, start the script
|
||||
@ -520,24 +482,6 @@ export function runScriptsLoop() {
|
||||
setTimeoutRef(runScriptsLoop, 3e3);
|
||||
}
|
||||
|
||||
/**
|
||||
* Queues a script to be killed by setting its stop flag to true. This
|
||||
* kills and timed/blocking Netscript functions (like hack(), sleep(), etc.) and
|
||||
* prevents any further execution of Netscript functions.
|
||||
* The runScriptsLoop() handles the actual deletion of the WorkerScript
|
||||
*/
|
||||
export function killWorkerScript(runningScriptObj, serverIp) {
|
||||
for (var i = 0; i < workerScripts.length; i++) {
|
||||
if (workerScripts[i].name == runningScriptObj.filename && workerScripts[i].serverIp == serverIp &&
|
||||
compareArrays(workerScripts[i].args, runningScriptObj.args)) {
|
||||
workerScripts[i].env.stopFlag = true;
|
||||
killNetscriptDelay(workerScripts[i]);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a RunningScript object, queues that script to be run
|
||||
*/
|
||||
|
@ -53,7 +53,8 @@ import {
|
||||
import { showLiterature } from "./Literature";
|
||||
import { Message } from "./Message/Message";
|
||||
import { showMessage } from "./Message/MessageHelpers";
|
||||
import { killWorkerScript, addWorkerScript } from "./NetscriptWorker";
|
||||
import { addWorkerScript } from "./NetscriptWorker";
|
||||
import { killWorkerScript } from "./Netscript/killWorkerScript";
|
||||
import { Player } from "./Player";
|
||||
import { hackWorldDaemon } from "./RedPill";
|
||||
import { RunningScript } from "./Script/RunningScript";
|
||||
|
@ -1,3 +1,8 @@
|
||||
/**
|
||||
* Game engine. Handles the main game loop as well as the main UI pages
|
||||
*
|
||||
* TODO: Separate UI functionality into its own component
|
||||
*/
|
||||
import {
|
||||
convertTimeMsToTimeElapsedString,
|
||||
replaceAt
|
||||
|
@ -9,6 +9,7 @@ import "../css/characteroverview.scss";
|
||||
import "../css/terminal.scss";
|
||||
import "../css/scripteditor.scss";
|
||||
import "../css/codemirror-overrides.scss";
|
||||
import "../css/activescripts.scss";
|
||||
import "../css/hacknetnodes.scss";
|
||||
import "../css/menupages.scss";
|
||||
import "../css/augmentations.scss";
|
||||
|
31
src/ui/ActiveScripts/Root.tsx
Normal file
31
src/ui/ActiveScripts/Root.tsx
Normal file
@ -0,0 +1,31 @@
|
||||
/**
|
||||
* Root React Component for the "Active Scripts" UI page. This page displays
|
||||
* and provides information about all of the player's scripts that are currently running
|
||||
*/
|
||||
import * as React from "react";
|
||||
|
||||
import { WorkerScript } from "../../Netscript/WorkerScript";
|
||||
|
||||
type IProps = {
|
||||
workerScripts: WorkerScript[];
|
||||
}
|
||||
|
||||
export class ActiveScriptsRoot extends React.Component<IProps, any> {
|
||||
constructor(props: IProps) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<>
|
||||
<p>
|
||||
This page displays a list of all of your scripts that are currently
|
||||
running across every machine. It also provides information about each
|
||||
script's production. The scripts are categorized by the hostname of
|
||||
the servers on which they are running.
|
||||
</p>
|
||||
|
||||
</>
|
||||
)
|
||||
}
|
||||
}
|
40
src/ui/ActiveScripts/WorkerScriptAccordion.tsx
Normal file
40
src/ui/ActiveScripts/WorkerScriptAccordion.tsx
Normal file
@ -0,0 +1,40 @@
|
||||
/**
|
||||
* React Component for displaying a single WorkerScript's info as an
|
||||
* Accordion element
|
||||
*/
|
||||
import * as React from "react";
|
||||
|
||||
import { Accordion } from "../React/Accordion";
|
||||
|
||||
import { WorkerScript } from "../../Netscript/WorkerScript";
|
||||
|
||||
import { arrayToString } from "../../../utils/helpers/arrayToString";
|
||||
|
||||
type IProps = {
|
||||
workerScript: WorkerScript;
|
||||
}
|
||||
|
||||
export function WorkerScriptAccordion(props: IProps): React.ReactElement {
|
||||
|
||||
|
||||
return (
|
||||
<Accordion
|
||||
headerClass="active-scripts-script-header"
|
||||
headerContent={
|
||||
<>
|
||||
</>
|
||||
}
|
||||
panelClass="active-scripts-script-panel"
|
||||
panelContent={
|
||||
<>
|
||||
<p>
|
||||
Threads: {props.workerScript.scriptRef.threads}
|
||||
</p>
|
||||
<p>
|
||||
Args: {arrayToString(props.workerScript.args)}
|
||||
</p>
|
||||
</>
|
||||
}
|
||||
/>
|
||||
)
|
||||
}
|
@ -4,7 +4,9 @@
|
||||
import * as React from "react";
|
||||
|
||||
type IProps = {
|
||||
headerClass?: string; // Override default class
|
||||
headerContent: React.ReactElement;
|
||||
panelClass?: string; // Override default class
|
||||
panelContent: React.ReactElement;
|
||||
panelInitiallyOpened?: boolean;
|
||||
}
|
||||
@ -44,12 +46,21 @@ export class Accordion extends React.Component<IProps, IState> {
|
||||
}
|
||||
|
||||
render() {
|
||||
let className = "accordion-header";
|
||||
if (typeof this.props.headerClass === "string") {
|
||||
className = this.props.headerClass;
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<button className={"accordion-header"} onClick={this.handleHeaderClick}>
|
||||
<button className={className} onClick={this.handleHeaderClick}>
|
||||
{this.props.headerContent}
|
||||
</button>
|
||||
<AccordionPanel opened={this.state.panelOpened} panelContent={this.props.panelContent} />
|
||||
<AccordionPanel
|
||||
opened={this.state.panelOpened}
|
||||
panelClass={this.props.panelClass}
|
||||
panelContent={this.props.panelContent}
|
||||
/>
|
||||
</>
|
||||
)
|
||||
}
|
||||
@ -57,6 +68,7 @@ export class Accordion extends React.Component<IProps, IState> {
|
||||
|
||||
type IPanelProps = {
|
||||
opened: boolean;
|
||||
panelClass?: string; // Override default class
|
||||
panelContent: React.ReactElement;
|
||||
}
|
||||
|
||||
@ -66,8 +78,13 @@ class AccordionPanel extends React.Component<IPanelProps, any> {
|
||||
}
|
||||
|
||||
render() {
|
||||
let className = "accordion-panel"
|
||||
if (typeof this.props.panelClass === "string") {
|
||||
className = this.props.panelClass;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={"accordion-panel"}>
|
||||
<div className={className}>
|
||||
{this.props.panelContent}
|
||||
</div>
|
||||
)
|
||||
|
50
src/utils/EventEmitter.ts
Normal file
50
src/utils/EventEmitter.ts
Normal file
@ -0,0 +1,50 @@
|
||||
/**
|
||||
* Generic Event Emitter class following a subscribe/publish paradigm.
|
||||
*/
|
||||
import { IMap } from "../types";
|
||||
|
||||
type cbFn = (...args: any[]) => any;
|
||||
|
||||
export interface ISubscriber {
|
||||
/**
|
||||
* Callback function that will be run when an event is emitted
|
||||
*/
|
||||
cb: cbFn;
|
||||
|
||||
/**
|
||||
* Name/identifier for this subscriber
|
||||
*/
|
||||
id: string;
|
||||
}
|
||||
|
||||
export class EventEmitter {
|
||||
/**
|
||||
* Map of Subscriber name -> Callback function
|
||||
*/
|
||||
subscribers: IMap<cbFn> = {};
|
||||
|
||||
constructor(subs?: ISubscriber[]) {
|
||||
if (Array.isArray(subs)) {
|
||||
for (const s of subs) {
|
||||
this.addSubscriber(s);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
addSubscriber(s: ISubscriber) {
|
||||
this.subscribers[s.id] = s.cb;
|
||||
}
|
||||
|
||||
emitEvent(...args: any[]): void {
|
||||
for (const s in this.subscribers) {
|
||||
const cb = this.subscribers[s];
|
||||
|
||||
cb(args);
|
||||
}
|
||||
}
|
||||
|
||||
removeSubscriber(id: string) {
|
||||
delete this.subscribers[id];
|
||||
}
|
||||
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
import {killWorkerScript} from "../src/NetscriptWorker";
|
||||
import {clearEventListeners} from "./uiHelpers/clearEventListeners";
|
||||
import {arrayToString} from "./helpers/arrayToString";
|
||||
import { killWorkerScript } from "../src/Netscript/killWorkerScript";
|
||||
import { clearEventListeners } from "./uiHelpers/clearEventListeners";
|
||||
import { arrayToString } from "./helpers/arrayToString";
|
||||
|
||||
$(document).keydown(function(event) {
|
||||
if (logBoxOpened && event.keyCode == 27) {
|
||||
|
Loading…
Reference in New Issue
Block a user