mirror of
https://github.com/bitburner-official/bitburner-src.git
synced 2024-11-27 01:53:48 +01:00
Merge pull request #933 from danielyxie/dev
* .ns script no longer needlessly recompile * scping the exact same content over doesn't trigger an actual scp * world daemon can be backdoored * Coding contract title is click-to-copy * Sleeve memory covenant upgrade reacts better.
This commit is contained in:
commit
0c744d98b9
4
dist/engine.bundle.js
vendored
4
dist/engine.bundle.js
vendored
File diff suppressed because one or more lines are too long
34
dist/vendor.bundle.js
vendored
34
dist/vendor.bundle.js
vendored
File diff suppressed because one or more lines are too long
@ -14,8 +14,10 @@ import {
|
|||||||
} from "../utils/JSONReviver";
|
} from "../utils/JSONReviver";
|
||||||
import { KEY } from "../utils/helpers/keyCodes";
|
import { KEY } from "../utils/helpers/keyCodes";
|
||||||
import { createElement } from "../utils/uiHelpers/createElement";
|
import { createElement } from "../utils/uiHelpers/createElement";
|
||||||
import { createPopup } from "../utils/uiHelpers/createPopup";
|
import { createPopup, removePopup } from "./ui/React/createPopup";
|
||||||
import { removeElementById } from "../utils/uiHelpers/removeElementById";
|
import { removeElementById } from "../utils/uiHelpers/removeElementById";
|
||||||
|
import { CodingContractPopup } from "./ui/React/CodingContractPopup";
|
||||||
|
|
||||||
|
|
||||||
/* tslint:disable:no-magic-numbers completed-docs max-classes-per-file no-console */
|
/* tslint:disable:no-magic-numbers completed-docs max-classes-per-file no-console */
|
||||||
|
|
||||||
@ -171,57 +173,26 @@ export class CodingContract {
|
|||||||
* Creates a popup to prompt the player to solve the problem
|
* Creates a popup to prompt the player to solve the problem
|
||||||
*/
|
*/
|
||||||
async prompt(): Promise<CodingContractResult> {
|
async prompt(): Promise<CodingContractResult> {
|
||||||
// tslint:disable-next-line
|
|
||||||
return new Promise<CodingContractResult>((resolve) => {
|
|
||||||
const contractType: CodingContractType = CodingContractTypes[this.type];
|
|
||||||
const popupId = `coding-contract-prompt-popup-${this.fn}`;
|
const popupId = `coding-contract-prompt-popup-${this.fn}`;
|
||||||
const title: HTMLElement = createElement("h1", {
|
return new Promise<CodingContractResult>((resolve, reject) => {
|
||||||
innerHTML: this.type,
|
let popup = new CodingContractPopup({
|
||||||
});
|
c: this,
|
||||||
const txt: HTMLElement = createElement("p", {
|
popupId: popupId,
|
||||||
innerHTML: ["You are attempting to solve a Coding Contract. You have",
|
onClose: () => {
|
||||||
`${this.getMaxNumTries() - this.tries} tries remaining,`,
|
|
||||||
"after which the contract will self-destruct.<br><br>",
|
|
||||||
`${contractType.desc(this.data).replace(/\n/g, "<br>")}`].join(" "),
|
|
||||||
});
|
|
||||||
let solveBtn: HTMLElement;
|
|
||||||
const cancelBtn = createElement("a", {
|
|
||||||
class: "a-link-button",
|
|
||||||
clickListener: () => {
|
|
||||||
resolve(CodingContractResult.Cancelled);
|
resolve(CodingContractResult.Cancelled);
|
||||||
removeElementById(popupId);
|
removePopup(popupId);
|
||||||
},
|
},
|
||||||
innerText: "Cancel",
|
onAttempt: (val: string) => {
|
||||||
});
|
console.log(`top; ${val}`);
|
||||||
const answerInput = createElement("input", {
|
if (this.isSolution(val)) {
|
||||||
onkeydown: (e: any) => {
|
|
||||||
if (e.keyCode === KEY.ENTER && answerInput.value !== "") {
|
|
||||||
e.preventDefault();
|
|
||||||
solveBtn.click();
|
|
||||||
} else if (e.keyCode === KEY.ESC) {
|
|
||||||
e.preventDefault();
|
|
||||||
cancelBtn.click();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
placeholder: "Enter Solution here",
|
|
||||||
width: "50%",
|
|
||||||
}) as HTMLInputElement;
|
|
||||||
solveBtn = createElement("a", {
|
|
||||||
class: "a-link-button",
|
|
||||||
clickListener: () => {
|
|
||||||
const answer: string = answerInput.value;
|
|
||||||
if (this.isSolution(answer)) {
|
|
||||||
resolve(CodingContractResult.Success);
|
resolve(CodingContractResult.Success);
|
||||||
} else {
|
} else {
|
||||||
resolve(CodingContractResult.Failure);
|
resolve(CodingContractResult.Failure);
|
||||||
}
|
}
|
||||||
removeElementById(popupId);
|
removePopup(popupId);
|
||||||
},
|
}
|
||||||
innerText: "Solve",
|
|
||||||
});
|
});
|
||||||
const lineBreak: HTMLElement = createElement("br");
|
createPopup(popupId, CodingContractPopup, popup.props);
|
||||||
createPopup(popupId, [title, lineBreak, txt, lineBreak, lineBreak, answerInput, solveBtn, cancelBtn]);
|
|
||||||
answerInput.focus();
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1453,6 +1453,11 @@ function NetscriptFunctions(workerScript) {
|
|||||||
if (scriptname == destServer.scripts[i].filename) {
|
if (scriptname == destServer.scripts[i].filename) {
|
||||||
workerScript.log("scp", `WARNING: File '${scriptname}' overwritten on '${destServer.hostname}'`);
|
workerScript.log("scp", `WARNING: File '${scriptname}' overwritten on '${destServer.hostname}'`);
|
||||||
const oldScript = destServer.scripts[i];
|
const oldScript = destServer.scripts[i];
|
||||||
|
// If it's the exact same file don't actually perform the
|
||||||
|
// copy to avoid recompiling uselessly. Players tend to scp
|
||||||
|
// liberally.
|
||||||
|
if(oldScript.code === sourceScript.code)
|
||||||
|
return true;
|
||||||
oldScript.code = sourceScript.code;
|
oldScript.code = sourceScript.code;
|
||||||
oldScript.ramUsage = sourceScript.ramUsage;
|
oldScript.ramUsage = sourceScript.ramUsage;
|
||||||
oldScript.markUpdated();
|
oldScript.markUpdated();
|
||||||
|
@ -20,6 +20,7 @@ export async function executeJSScript(scripts = [], workerScript) {
|
|||||||
let urls = null;
|
let urls = null;
|
||||||
let script = workerScript.getScript();
|
let script = workerScript.getScript();
|
||||||
if (shouldCompile(script, scripts)) {
|
if (shouldCompile(script, scripts)) {
|
||||||
|
console.log("recompiling");
|
||||||
// The URL at the top is the one we want to import. It will
|
// The URL at the top is the one we want to import. It will
|
||||||
// recursively import all the other modules in the urlStack.
|
// recursively import all the other modules in the urlStack.
|
||||||
//
|
//
|
||||||
@ -27,6 +28,7 @@ export async function executeJSScript(scripts = [], workerScript) {
|
|||||||
// but not really behaves like import. Particularly, it cannot
|
// but not really behaves like import. Particularly, it cannot
|
||||||
// load fully dynamic content. So we hide the import from webpack
|
// load fully dynamic content. So we hide the import from webpack
|
||||||
// by placing it inside an eval call.
|
// by placing it inside an eval call.
|
||||||
|
script.markUpdated();
|
||||||
urls = _getScriptUrls(script, scripts, []);
|
urls = _getScriptUrls(script, scripts, []);
|
||||||
script.url = urls[urls.length - 1].url;
|
script.url = urls[urls.length - 1].url;
|
||||||
script.module = new Promise(resolve => resolve(eval('import(urls[urls.length - 1].url)')));
|
script.module = new Promise(resolve => resolve(eval('import(urls[urls.length - 1].url)')));
|
||||||
@ -58,14 +60,15 @@ export async function executeJSScript(scripts = [], workerScript) {
|
|||||||
*/
|
*/
|
||||||
function shouldCompile(script, scripts) {
|
function shouldCompile(script, scripts) {
|
||||||
if (script.module === "") return true;
|
if (script.module === "") return true;
|
||||||
|
console.log(script.dependencies);
|
||||||
return script.dependencies.some(dep => {
|
return script.dependencies.some(dep => {
|
||||||
const depScript = scripts.find(s => s.filename == dep.url);
|
const depScript = scripts.find(s => s.filename == dep.filename);
|
||||||
|
|
||||||
// If the script is not present on the server, we should recompile, if only to get any necessary
|
// If the script is not present on the server, we should recompile, if only to get any necessary
|
||||||
// compilation errors.
|
// compilation errors.
|
||||||
if (!depScript) return true;
|
if (!depScript) return true;
|
||||||
|
|
||||||
const depIsMoreRecent = depScript.moduleSequenceNumber > script.moduleSequenceNumber
|
const depIsMoreRecent = depScript.moduleSequenceNumber > script.moduleSequenceNumber;
|
||||||
return depIsMoreRecent;
|
return depIsMoreRecent;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -35,7 +35,11 @@ export class CovenantSleeveMemoryUpgrade extends React.Component<IProps, IState>
|
|||||||
}
|
}
|
||||||
|
|
||||||
changePurchaseAmount(e: React.ChangeEvent<HTMLInputElement>): void {
|
changePurchaseAmount(e: React.ChangeEvent<HTMLInputElement>): void {
|
||||||
const n: number = parseInt(e.target.value);
|
let n: number = parseInt(e.target.value);
|
||||||
|
|
||||||
|
if(isNaN(n)) n = 1;
|
||||||
|
const maxMemory = 100 - this.props.sleeve.memory;
|
||||||
|
if (n > maxMemory) n = maxMemory;
|
||||||
|
|
||||||
this.setState({
|
this.setState({
|
||||||
amt: n,
|
amt: n,
|
||||||
@ -89,7 +93,7 @@ export class CovenantSleeveMemoryUpgrade extends React.Component<IProps, IState>
|
|||||||
<label htmlFor={inputId}>
|
<label htmlFor={inputId}>
|
||||||
Amount of memory to purchase (must be an integer):
|
Amount of memory to purchase (must be an integer):
|
||||||
</label>
|
</label>
|
||||||
<input id={inputId} onChange={this.changePurchaseAmount} type={"number"} value={isNaN(this.state.amt) ? this.state.amt.toString() : this.state.amt} />
|
<input className="text-input" id={inputId} onChange={this.changePurchaseAmount} type={"number"} value={this.state.amt} />
|
||||||
<br />
|
<br />
|
||||||
<StdButton disabled={purchaseBtnDisabled} onClick={this.purchaseMemory} text={purchaseBtnContent} />
|
<StdButton disabled={purchaseBtnDisabled} onClick={this.purchaseMemory} text={purchaseBtnContent} />
|
||||||
</div>
|
</div>
|
||||||
|
@ -563,7 +563,15 @@ let Terminal = {
|
|||||||
|
|
||||||
finishBackdoor: function(cancelled = false) {
|
finishBackdoor: function(cancelled = false) {
|
||||||
if(!cancelled){
|
if(!cancelled){
|
||||||
let server = Player.getCurrentServer();
|
const server = Player.getCurrentServer();
|
||||||
|
if (SpecialServerIps[SpecialServerNames.WorldDaemon] &&
|
||||||
|
SpecialServerIps[SpecialServerNames.WorldDaemon] == server.ip) {
|
||||||
|
if (Player.bitNodeN == null) {
|
||||||
|
Player.bitNodeN = 1;
|
||||||
|
}
|
||||||
|
hackWorldDaemon(Player.bitNodeN);
|
||||||
|
return;
|
||||||
|
}
|
||||||
server.backdoorInstalled = true;
|
server.backdoorInstalled = true;
|
||||||
postElement(<>Backdoor successful!</>);
|
postElement(<>Backdoor successful!</>);
|
||||||
}
|
}
|
||||||
|
61
src/ui/React/CodingContractPopup.tsx
Normal file
61
src/ui/React/CodingContractPopup.tsx
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
import * as React from "react";
|
||||||
|
import { KEY } from "../../../utils/helpers/keyCodes";
|
||||||
|
|
||||||
|
import { CodingContract, CodingContractType, CodingContractTypes } from "../../CodingContracts";
|
||||||
|
import { ClickableTag, CopyableText } from "./CopyableText";
|
||||||
|
import { PopupCloseButton } from "./PopupCloseButton";
|
||||||
|
|
||||||
|
type IProps = {
|
||||||
|
c: CodingContract;
|
||||||
|
popupId: string;
|
||||||
|
onClose: () => void;
|
||||||
|
onAttempt: (answer: string) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
type IState = {
|
||||||
|
answer: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class CodingContractPopup extends React.Component<IProps, IState>{
|
||||||
|
constructor(props: IProps) {
|
||||||
|
super(props);
|
||||||
|
this.state = { answer: ''};
|
||||||
|
this.setAnswer = this.setAnswer.bind(this);
|
||||||
|
this.onInputKeydown = this.onInputKeydown.bind(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
setAnswer(event: any) {
|
||||||
|
this.setState({ answer: event.target.value });
|
||||||
|
}
|
||||||
|
|
||||||
|
onInputKeydown(e:any){
|
||||||
|
if (e.keyCode === KEY.ENTER && e.target.value !== "") {
|
||||||
|
e.preventDefault();
|
||||||
|
this.props.onAttempt(this.state.answer);
|
||||||
|
} else if (e.keyCode === KEY.ESC) {
|
||||||
|
e.preventDefault();
|
||||||
|
this.props.onClose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
render(): React.ReactNode {
|
||||||
|
const contractType: CodingContractType = CodingContractTypes[this.props.c.type];
|
||||||
|
let description = [];
|
||||||
|
for (const [i, value] of contractType.desc(this.props.c.data).split('\n').entries())
|
||||||
|
description.push(<span key={i}>{value}<br/></span>);
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<CopyableText value={this.props.c.type} tag={ClickableTag.Tag_h1} />
|
||||||
|
<br/><br/>
|
||||||
|
<p>You are attempting to solve a Coding Contract. You have {this.props.c.getMaxNumTries() - this.props.c.tries} tries remaining, after which the contract will self-destruct.</p>
|
||||||
|
<br/>
|
||||||
|
<p>{description}</p>
|
||||||
|
<br/>
|
||||||
|
<input className="text-input" style={{ width:"50%",marginTop:"8px" }} autoFocus={true} placeholder="Enter Solution here" value={this.state.answer}
|
||||||
|
onChange={this.setAnswer} onKeyDown={this.onInputKeydown} />
|
||||||
|
<PopupCloseButton popup={this.props.popupId} onClose={() => this.props.onAttempt(this.state.answer)} text={"Solve"} />
|
||||||
|
<PopupCloseButton popup={this.props.popupId} onClose={this.props.onClose} text={"Close"} />
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
@ -1,7 +1,13 @@
|
|||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
|
|
||||||
|
export enum ClickableTag{
|
||||||
|
Tag_span,
|
||||||
|
Tag_h1
|
||||||
|
}
|
||||||
|
|
||||||
type IProps = {
|
type IProps = {
|
||||||
value: string;
|
value: string;
|
||||||
|
tag: ClickableTag;
|
||||||
}
|
}
|
||||||
|
|
||||||
type IState = {
|
type IState = {
|
||||||
@ -9,6 +15,11 @@ type IState = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class CopyableText extends React.Component<IProps, IState> {
|
export class CopyableText extends React.Component<IProps, IState> {
|
||||||
|
public static defaultProps = {
|
||||||
|
//Default span to prevent destroying current clickables
|
||||||
|
tag: ClickableTag.Tag_span
|
||||||
|
};
|
||||||
|
|
||||||
constructor(props: IProps) {
|
constructor(props: IProps) {
|
||||||
super(props);
|
super(props);
|
||||||
|
|
||||||
@ -53,9 +64,19 @@ export class CopyableText extends React.Component<IProps, IState> {
|
|||||||
|
|
||||||
|
|
||||||
render(): React.ReactNode {
|
render(): React.ReactNode {
|
||||||
return (<span className={this.textClasses()} onClick={this.copy}>
|
switch (this.props.tag) {
|
||||||
|
case ClickableTag.Tag_h1:
|
||||||
|
return (
|
||||||
|
<h1 className={this.textClasses()} onClick={this.copy}>
|
||||||
|
{this.props.value}
|
||||||
|
<span className={this.tooltipClasses()}>Copied!</span>
|
||||||
|
</h1>)
|
||||||
|
case ClickableTag.Tag_span:
|
||||||
|
return (
|
||||||
|
<span className={this.textClasses()} onClick={this.copy}>
|
||||||
<b>{this.props.value}</b>
|
<b>{this.props.value}</b>
|
||||||
<span className={this.tooltipClasses()}>Copied!</span>
|
<span className={this.tooltipClasses()}>Copied!</span>
|
||||||
</span>);
|
</span>)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
72
src/ui/React/PopupButton.tsx
Normal file
72
src/ui/React/PopupButton.tsx
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
/**
|
||||||
|
* Basic button for popup dialog boxes
|
||||||
|
* It creates an event handler such that pressing Esc will perform the click handler.
|
||||||
|
*
|
||||||
|
* Should only be used in other React components, otherwise it may not be properly
|
||||||
|
* unmounted
|
||||||
|
*/
|
||||||
|
import * as React from "react";
|
||||||
|
import * as ReactDOM from "react-dom";
|
||||||
|
|
||||||
|
import { KEY } from "../../../utils/helpers/keyCodes";
|
||||||
|
import { removeElement } from "../../../utils/uiHelpers/removeElement";
|
||||||
|
|
||||||
|
export interface IPopupButtonProps {
|
||||||
|
class?: string;
|
||||||
|
popup: HTMLElement | string;
|
||||||
|
style?: object;
|
||||||
|
text: string;
|
||||||
|
onClose?: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class PopupButton extends React.Component<IPopupButtonProps, any> {
|
||||||
|
constructor(props: IPopupButtonProps) {
|
||||||
|
super(props);
|
||||||
|
this.handleClick = this.handleClick.bind(this);
|
||||||
|
this.keyListener = this.keyListener.bind(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
document.addEventListener("keydown", this.keyListener);
|
||||||
|
}
|
||||||
|
|
||||||
|
componentWillUnmount() {
|
||||||
|
document.removeEventListener("keydown", this.keyListener);
|
||||||
|
}
|
||||||
|
|
||||||
|
handleClick() {
|
||||||
|
if(this.props.onClose)
|
||||||
|
this.props.onClose();
|
||||||
|
//We might be able to remove this?
|
||||||
|
//Clickhandler from the props will override this anyhow.
|
||||||
|
let popup: HTMLElement | null;
|
||||||
|
if (typeof this.props.popup === "string") {
|
||||||
|
popup = document.getElementById(this.props.popup);
|
||||||
|
} else {
|
||||||
|
popup = this.props.popup;
|
||||||
|
}
|
||||||
|
// TODO Check if this is okay? This is essentially calling to unmount a parent component
|
||||||
|
if (popup instanceof HTMLElement) {
|
||||||
|
ReactDOM.unmountComponentAtNode(popup); // Removes everything inside the wrapper container
|
||||||
|
removeElement(popup); // Removes the wrapper container
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
keyListener(e: KeyboardEvent) {
|
||||||
|
//This doesn't really make sense, a button doesnt have to listen to escape IMO
|
||||||
|
//Too affraid to remove it since im not sure what it will break.. But yuck..
|
||||||
|
if (e.keyCode === KEY.ESC) {
|
||||||
|
this.handleClick();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
render(): React.ReactNode {
|
||||||
|
const className = this.props.class ? this.props.class : "std-button";
|
||||||
|
|
||||||
|
return (
|
||||||
|
<button className={className} onClick={this.handleClick} style={this.props.style}>
|
||||||
|
{this.props.text}
|
||||||
|
</button>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
@ -8,33 +8,27 @@
|
|||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
import * as ReactDOM from "react-dom";
|
import * as ReactDOM from "react-dom";
|
||||||
|
|
||||||
import { KEY } from "../../../utils/helpers/keyCodes";
|
|
||||||
import { removeElement } from "../../../utils/uiHelpers/removeElement";
|
import { removeElement } from "../../../utils/uiHelpers/removeElement";
|
||||||
|
import { IPopupButtonProps, PopupButton } from "./PopupButton";
|
||||||
|
|
||||||
export interface IPopupCloseButtonProps {
|
export interface IPopupCloseButtonProps extends IPopupButtonProps {
|
||||||
class?: string;
|
class?: string;
|
||||||
popup: HTMLElement | string;
|
popup: HTMLElement | string;
|
||||||
style?: any;
|
style?: any;
|
||||||
text: string;
|
text: string;
|
||||||
|
onClose: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class PopupCloseButton extends React.Component<IPopupCloseButtonProps, any> {
|
export class PopupCloseButton extends PopupButton {
|
||||||
constructor(props: IPopupCloseButtonProps) {
|
constructor(props: IPopupCloseButtonProps) {
|
||||||
super(props);
|
super(props);
|
||||||
|
|
||||||
this.closePopup = this.closePopup.bind(this);
|
this.closePopup = this.closePopup.bind(this);
|
||||||
this.keyListener = this.keyListener.bind(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
componentDidMount(): void {
|
|
||||||
document.addEventListener("keydown", this.keyListener);
|
|
||||||
}
|
|
||||||
|
|
||||||
componentWillUnmount(): void {
|
|
||||||
document.removeEventListener("keydown", this.keyListener);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
closePopup(): void {
|
closePopup(): void {
|
||||||
|
if(this.props.onClose)
|
||||||
|
this.props.onClose();
|
||||||
let popup: HTMLElement | null;
|
let popup: HTMLElement | null;
|
||||||
if (typeof this.props.popup === "string") {
|
if (typeof this.props.popup === "string") {
|
||||||
popup = document.getElementById(this.props.popup);
|
popup = document.getElementById(this.props.popup);
|
||||||
@ -42,24 +36,23 @@ export class PopupCloseButton extends React.Component<IPopupCloseButtonProps, an
|
|||||||
popup = this.props.popup;
|
popup = this.props.popup;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO Check if this is okay? This is essentially calling to unmount a parent component
|
// TODO Check if this is okay? This is essentially calling to unmount a
|
||||||
|
// parent component
|
||||||
if (popup instanceof HTMLElement) {
|
if (popup instanceof HTMLElement) {
|
||||||
ReactDOM.unmountComponentAtNode(popup); // Removes everything inside the wrapper container
|
// Removes everything inside the wrapper container
|
||||||
|
ReactDOM.unmountComponentAtNode(popup);
|
||||||
removeElement(popup); // Removes the wrapper container
|
removeElement(popup); // Removes the wrapper container
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
keyListener(e: KeyboardEvent): void {
|
|
||||||
if (e.keyCode === KEY.ESC) {
|
|
||||||
this.closePopup();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
render(): React.ReactNode {
|
render(): React.ReactNode {
|
||||||
const className = this.props.class ? this.props.class : "std-button";
|
const className = this.props.class ? this.props.class : "std-button";
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<button className={className} onClick={this.closePopup} style={this.props.style}>
|
<button
|
||||||
|
className={className}
|
||||||
|
onClick={this.closePopup}
|
||||||
|
style={this.props.style}>
|
||||||
{this.props.text}
|
{this.props.text}
|
||||||
</button>
|
</button>
|
||||||
)
|
)
|
||||||
|
Loading…
Reference in New Issue
Block a user