mirror of
https://github.com/tobspr/shapez.io.git
synced 2025-12-14 10:41:52 +00:00
Basic JSX support in states
Quite hacky considering the complex indirection and minor differences in the appearance of each state, as well as legacy code and need to support HTML strings for now. Some methods could be improved, refactored or deleted, but no major changes were made. Mods and puzzles menu states are broken in this commit.
This commit is contained in:
parent
a2b21cc6dd
commit
69ce8ffc17
@ -1,14 +1,11 @@
|
|||||||
/* typehints:start */
|
import { MUSIC } from "@/platform/sound";
|
||||||
import { Application } from "../application";
|
import type { Application } from "../application";
|
||||||
import { StateManager } from "./state_manager";
|
|
||||||
/* typehints:end */
|
|
||||||
|
|
||||||
import { MUSIC } from "../platform/sound";
|
|
||||||
import { ClickDetector } from "./click_detector";
|
import { ClickDetector } from "./click_detector";
|
||||||
import { globalConfig } from "./config";
|
import { globalConfig } from "./config";
|
||||||
import { InputReceiver } from "./input_receiver";
|
import { InputReceiver } from "./input_receiver";
|
||||||
import { createLogger, logSection } from "./logging";
|
import { createLogger, logSection } from "./logging";
|
||||||
import { RequestChannel } from "./request_channel";
|
import { RequestChannel } from "./request_channel";
|
||||||
|
import type { StateManager } from "./state_manager";
|
||||||
import { waitNextFrame } from "./utils";
|
import { waitNextFrame } from "./utils";
|
||||||
|
|
||||||
const logger = createLogger("game_state");
|
const logger = createLogger("game_state");
|
||||||
@ -17,49 +14,41 @@ const logger = createLogger("game_state");
|
|||||||
* Basic state of the game state machine. This is the base of the whole game
|
* Basic state of the game state machine. This is the base of the whole game
|
||||||
*/
|
*/
|
||||||
export class GameState {
|
export class GameState {
|
||||||
|
public app: Application = null;
|
||||||
|
public readonly key: string;
|
||||||
|
public inputReceiver: InputReceiver;
|
||||||
|
|
||||||
|
/** A channel we can use to perform async ops */
|
||||||
|
protected asyncChannel = new RequestChannel();
|
||||||
|
protected clickDetectors: ClickDetector[] = [];
|
||||||
|
|
||||||
|
/** @todo review this */
|
||||||
|
protected htmlElement: HTMLElement | undefined;
|
||||||
|
|
||||||
|
private stateManager: StateManager = null;
|
||||||
|
|
||||||
|
/** Store if we are currently fading out */
|
||||||
|
private fadingOut = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs a new state with the given id
|
* Constructs a new state with the given id
|
||||||
* @param {string} key The id of the state. We use ids to refer to states because otherwise we get
|
* @param key The id of the state. We use ids to refer to states because otherwise we get
|
||||||
* circular references
|
* circular references
|
||||||
*/
|
*/
|
||||||
constructor(key) {
|
constructor(key: string) {
|
||||||
this.key = key;
|
this.key = key;
|
||||||
|
|
||||||
/** @type {StateManager} */
|
|
||||||
this.stateManager = null;
|
|
||||||
|
|
||||||
/** @type {Application} */
|
|
||||||
this.app = null;
|
|
||||||
|
|
||||||
// Store if we are currently fading out
|
|
||||||
this.fadingOut = false;
|
|
||||||
|
|
||||||
/** @type {Array<ClickDetector>} */
|
|
||||||
this.clickDetectors = [];
|
|
||||||
|
|
||||||
// Every state captures keyboard events by default
|
// Every state captures keyboard events by default
|
||||||
this.inputReceiver = new InputReceiver("state-" + key);
|
this.inputReceiver = new InputReceiver("state-" + key);
|
||||||
this.inputReceiver.backButton.add(this.onBackButton, this);
|
this.inputReceiver.backButton.add(this.onBackButton, this);
|
||||||
|
|
||||||
// A channel we can use to perform async ops
|
|
||||||
this.asyncChannel = new RequestChannel();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//// GETTERS / HELPER METHODS ////
|
//// GETTERS / HELPER METHODS ////
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the states key
|
|
||||||
* @returns {string}
|
|
||||||
*/
|
|
||||||
getKey() {
|
|
||||||
return this.key;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the html element of the state
|
* Returns the html element of the state
|
||||||
* @returns {HTMLElement}
|
|
||||||
*/
|
*/
|
||||||
getDivElement() {
|
getDivElement(): HTMLElement {
|
||||||
return document.getElementById("state_" + this.key);
|
return document.getElementById("state_" + this.key);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -120,9 +109,9 @@ export class GameState {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Callback when entering the state, to be overriddemn
|
* Callback when entering the state, to be overriddemn
|
||||||
* @param {any} payload Arbitrary data passed from the state which we are transferring from
|
* @param payload Arbitrary data passed from the state which we are transferring from
|
||||||
*/
|
*/
|
||||||
onEnter(payload) {}
|
onEnter(payload: {}) {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Callback when leaving the state
|
* Callback when leaving the state
|
||||||
@ -141,22 +130,22 @@ export class GameState {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Render callback
|
* Render callback
|
||||||
* @param {number} dt Delta time in ms since last render
|
* @param dt Delta time in ms since last render
|
||||||
*/
|
*/
|
||||||
onRender(dt) {}
|
onRender(dt: number) {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Background tick callback, called while the game is inactiev
|
* Background tick callback, called while the game is inactiev
|
||||||
* @param {number} dt Delta time in ms since last tick
|
* @param dt Delta time in ms since last tick
|
||||||
*/
|
*/
|
||||||
onBackgroundTick(dt) {}
|
onBackgroundTick(dt: number) {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called when the screen resized
|
* Called when the screen resized
|
||||||
* @param {number} w window/screen width
|
* @param w window/screen width
|
||||||
* @param {number} h window/screen height
|
* @param h window/screen height
|
||||||
*/
|
*/
|
||||||
onResized(w, h) {}
|
onResized(w: number, h: number) {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Internal backbutton handler, called when the hardware back button is pressed or
|
* Internal backbutton handler, called when the hardware back button is pressed or
|
||||||
@ -168,9 +157,9 @@ export class GameState {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Should return how many mulliseconds to fade in / out the state. Not recommended to override!
|
* Should return how many mulliseconds to fade in / out the state. Not recommended to override!
|
||||||
* @returns {number} Time in milliseconds to fade out
|
* @returns Time in milliseconds to fade out
|
||||||
*/
|
*/
|
||||||
getInOutFadeTime() {
|
getInOutFadeTime(): number {
|
||||||
if (globalConfig.debug.noArtificialDelays) {
|
if (globalConfig.debug.noArtificialDelays) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -180,39 +169,43 @@ export class GameState {
|
|||||||
/**
|
/**
|
||||||
* Should return whether to fade in the game state. This will then apply the right css classes
|
* Should return whether to fade in the game state. This will then apply the right css classes
|
||||||
* for the fadein.
|
* for the fadein.
|
||||||
* @returns {boolean}
|
|
||||||
*/
|
*/
|
||||||
getHasFadeIn() {
|
getHasFadeIn(): boolean {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Should return whether to fade out the game state. This will then apply the right css classes
|
* Should return whether to fade out the game state. This will then apply the right css classes
|
||||||
* for the fadeout and wait the delay before moving states
|
* for the fadeout and wait the delay before moving states
|
||||||
* @returns {boolean}
|
|
||||||
*/
|
*/
|
||||||
getHasFadeOut() {
|
getHasFadeOut(): boolean {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns if this state should get paused if it does not have focus
|
* Returns if this state should get paused if it does not have focus
|
||||||
* @returns {boolean} true to pause the updating of the game
|
* @returns true to pause the updating of the game
|
||||||
*/
|
*/
|
||||||
getPauseOnFocusLost() {
|
getPauseOnFocusLost(): boolean {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Should return the html code of the state.
|
* Should return the html code of the state.
|
||||||
* @returns {string}
|
* @deprecated use {@link getContentLayout} instead
|
||||||
* @abstract
|
|
||||||
*/
|
*/
|
||||||
getInnerHTML() {
|
getInnerHTML(): string {
|
||||||
abstract;
|
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Should return the element(s) to be displayed in the state.
|
||||||
|
* If null, {@link getInnerHTML} will be used instead.
|
||||||
|
*/
|
||||||
|
protected getContentLayout(): Node {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns if the state has an unload confirmation, this is the
|
* Returns if the state has an unload confirmation, this is the
|
||||||
* "Are you sure you want to leave the page" message.
|
* "Are you sure you want to leave the page" message.
|
||||||
@ -223,25 +216,22 @@ export class GameState {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Should return the theme music for this state
|
* Should return the theme music for this state
|
||||||
* @returns {string|null}
|
|
||||||
*/
|
*/
|
||||||
getThemeMusic() {
|
getThemeMusic(): string | null {
|
||||||
return MUSIC.menu;
|
return MUSIC.menu;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Should return true if the player is currently ingame
|
* Should return true if the player is currently ingame
|
||||||
* @returns {boolean}
|
|
||||||
*/
|
*/
|
||||||
getIsIngame() {
|
getIsIngame(): boolean {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Should return whether to clear the whole body content before entering the state.
|
* Should return whether to clear the whole body content before entering the state.
|
||||||
* @returns {boolean}
|
|
||||||
*/
|
*/
|
||||||
getRemovePreviousContent() {
|
getRemovePreviousContent(): boolean {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -251,9 +241,8 @@ export class GameState {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Internal callback from the manager. Do not override!
|
* Internal callback from the manager. Do not override!
|
||||||
* @param {StateManager} stateManager
|
|
||||||
*/
|
*/
|
||||||
internalRegisterCallback(stateManager, app) {
|
internalRegisterCallback(stateManager: StateManager, app: Application) {
|
||||||
assert(stateManager, "No state manager");
|
assert(stateManager, "No state manager");
|
||||||
assert(app, "No app");
|
assert(app, "No app");
|
||||||
this.stateManager = stateManager;
|
this.stateManager = stateManager;
|
||||||
@ -262,10 +251,10 @@ export class GameState {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Internal callback when entering the state. Do not override!
|
* Internal callback when entering the state. Do not override!
|
||||||
* @param {any} payload Arbitrary data passed from the state which we are transferring from
|
* @param payload Arbitrary data passed from the state which we are transferring from
|
||||||
* @param {boolean} callCallback Whether to call the onEnter callback
|
* @param callCallback Whether to call the onEnter callback
|
||||||
*/
|
*/
|
||||||
internalEnterCallback(payload, callCallback = true) {
|
internalEnterCallback(payload: any, callCallback = true) {
|
||||||
logSection(this.key, "#26a69a");
|
logSection(this.key, "#26a69a");
|
||||||
this.app.inputMgr.pushReceiver(this.inputReceiver);
|
this.app.inputMgr.pushReceiver(this.inputReceiver);
|
||||||
|
|
||||||
@ -325,18 +314,33 @@ export class GameState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Internal method to get the HTML of the game state.
|
* Internal method to get all elements of the game state. Can be
|
||||||
* @returns {string}
|
* called from subclasses to provide support for both HTMLElements
|
||||||
|
* and HTML strings.
|
||||||
*/
|
*/
|
||||||
internalGetFullHtml() {
|
internalGetWrappedContent(): Node {
|
||||||
return this.getInnerHTML();
|
const elements = this.getContentLayout();
|
||||||
|
if (elements instanceof Node) {
|
||||||
|
return elements;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Array.isArray(elements)) {
|
||||||
|
const fragment = document.createDocumentFragment();
|
||||||
|
fragment.append(...(elements as Node[]));
|
||||||
|
return fragment;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fall back to deprecated HTML strings solution
|
||||||
|
const template = document.createElement("template");
|
||||||
|
template.innerHTML = this.getInnerHTML();
|
||||||
|
return template.content;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Internal method to compute the time to fade in / out
|
* Internal method to compute the time to fade in / out
|
||||||
* @returns {number} time to fade in / out in ms
|
* @returns time to fade in / out in ms
|
||||||
*/
|
*/
|
||||||
internalGetFadeInOutTime() {
|
internalGetFadeInOutTime(): number {
|
||||||
if (G_IS_DEV && globalConfig.debug.fastGameEnter) {
|
if (G_IS_DEV && globalConfig.debug.fastGameEnter) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,10 +2,10 @@
|
|||||||
import { Application } from "../application";
|
import { Application } from "../application";
|
||||||
/* typehints:end*/
|
/* typehints:end*/
|
||||||
|
|
||||||
|
import { MOD_SIGNALS } from "../mods/mod_signals";
|
||||||
import { GameState } from "./game_state";
|
import { GameState } from "./game_state";
|
||||||
import { createLogger } from "./logging";
|
import { createLogger } from "./logging";
|
||||||
import { waitNextFrame, removeAllChildren } from "./utils";
|
import { removeAllChildren, waitNextFrame } from "./utils";
|
||||||
import { MOD_SIGNALS } from "../mods/mod_signals";
|
|
||||||
|
|
||||||
const logger = createLogger("state_manager");
|
const logger = createLogger("state_manager");
|
||||||
|
|
||||||
@ -34,7 +34,7 @@ export class StateManager {
|
|||||||
// Create a dummy to retrieve the key
|
// Create a dummy to retrieve the key
|
||||||
const dummy = new stateClass();
|
const dummy = new stateClass();
|
||||||
assert(dummy instanceof GameState, "Not a state!");
|
assert(dummy instanceof GameState, "Not a state!");
|
||||||
const key = dummy.getKey();
|
const key = dummy.key;
|
||||||
assert(!this.stateClasses[key], `State '${key}' is already registered!`);
|
assert(!this.stateClasses[key], `State '${key}' is already registered!`);
|
||||||
this.stateClasses[key] = stateClass;
|
this.stateClasses[key] = stateClass;
|
||||||
}
|
}
|
||||||
@ -61,7 +61,7 @@ export class StateManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (this.currentState) {
|
if (this.currentState) {
|
||||||
if (key === this.currentState.getKey()) {
|
if (key === this.currentState.key) {
|
||||||
logger.error(`State '${key}' is already active!`);
|
logger.error(`State '${key}' is already active!`);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -88,7 +88,8 @@ export class StateManager {
|
|||||||
document.body.id = "state_" + key;
|
document.body.id = "state_" + key;
|
||||||
|
|
||||||
if (this.currentState.getRemovePreviousContent()) {
|
if (this.currentState.getRemovePreviousContent()) {
|
||||||
document.body.innerHTML = this.currentState.internalGetFullHtml();
|
const content = this.currentState.internalGetWrappedContent();
|
||||||
|
document.body.append(content);
|
||||||
}
|
}
|
||||||
|
|
||||||
const dialogParent = document.createElement("div");
|
const dialogParent = document.createElement("div");
|
||||||
|
|||||||
@ -1,40 +1,76 @@
|
|||||||
import { HUDModalDialogs } from "../game/hud/parts/modal_dialogs";
|
import { HUDModalDialogs } from "../game/hud/parts/modal_dialogs";
|
||||||
import { GameState } from "./game_state";
|
import { GameState } from "./game_state";
|
||||||
import { T } from "../translations";
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Baseclass for all game states which are structured similary: A header with back button + some
|
* Baseclass for all game states which are structured similary: A header with back button + some
|
||||||
* scrollable content.
|
* scrollable content.
|
||||||
*/
|
*/
|
||||||
export class TextualGameState extends GameState {
|
export abstract class TextualGameState extends GameState {
|
||||||
///// INTERFACE ////
|
private backToStateId: string | null = null;
|
||||||
|
private backToStatePayload: {} | null = null;
|
||||||
|
|
||||||
|
protected headerElement: HTMLElement;
|
||||||
|
protected containerElement: HTMLElement;
|
||||||
|
protected dialogs: HUDModalDialogs;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Should return the states inner html. If not overriden, will create a scrollable container
|
* Should return the states inner html. If not overriden, will create a scrollable container
|
||||||
* with the content of getMainContentHTML()
|
* with the content of getMainContentHTML()
|
||||||
* @returns {string}
|
* @deprecated
|
||||||
*/
|
*/
|
||||||
getInnerHTML() {
|
getInnerHTML(): string {
|
||||||
return `
|
return "";
|
||||||
<div class="content mainContent">
|
|
||||||
${this.getMainContentHTML()}
|
|
||||||
</div>
|
|
||||||
`;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Should return the states HTML content.
|
* Should return the states HTML content.
|
||||||
|
* @deprecated
|
||||||
*/
|
*/
|
||||||
getMainContentHTML() {
|
getMainContentHTML(): string {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override getContentLayout(): Node {
|
||||||
|
let content = this.getInitialContent();
|
||||||
|
|
||||||
|
if (content === null) {
|
||||||
|
// Fall back either to getMainContentHTML or getInnerHTML (if not "")
|
||||||
|
let html = this.getInnerHTML();
|
||||||
|
if (html === "") {
|
||||||
|
html = `
|
||||||
|
<div class="content mainContent">
|
||||||
|
${this.getMainContentHTML()}
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
const template = document.createElement("template");
|
||||||
|
template.innerHTML = html;
|
||||||
|
content = template.content;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div class="headerBar">
|
||||||
|
<h1>
|
||||||
|
<button class="backButton"></button>
|
||||||
|
{this.getStateHeaderTitle() ?? ""}
|
||||||
|
</h1>
|
||||||
|
</div>
|
||||||
|
<div class="container">{content}</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected getInitialContent(): Node {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Should return the title of the game state. If null, no title and back button will
|
* Should return the title of the game state. If null, no title and back button will
|
||||||
* get created
|
* get created
|
||||||
* @returns {string|null}
|
|
||||||
*/
|
*/
|
||||||
getStateHeaderTitle() {
|
protected getStateHeaderTitle(): string | null {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -44,7 +80,7 @@ export class TextualGameState extends GameState {
|
|||||||
* Back button handler, can be overridden. Per default it goes back to the main menu,
|
* Back button handler, can be overridden. Per default it goes back to the main menu,
|
||||||
* or if coming from the game it moves back to the game again.
|
* or if coming from the game it moves back to the game again.
|
||||||
*/
|
*/
|
||||||
onBackButton() {
|
override onBackButton() {
|
||||||
if (this.backToStateId) {
|
if (this.backToStateId) {
|
||||||
this.moveToState(this.backToStateId, this.backToStatePayload);
|
this.moveToState(this.backToStateId, this.backToStatePayload);
|
||||||
} else {
|
} else {
|
||||||
@ -61,9 +97,9 @@ export class TextualGameState extends GameState {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Goes to a new state, telling him to go back to this state later
|
* Goes to a new state, telling him to go back to this state later
|
||||||
* @param {string} stateId
|
* @param stateId
|
||||||
*/
|
*/
|
||||||
moveToStateAddGoBack(stateId) {
|
moveToStateAddGoBack(stateId: string) {
|
||||||
this.moveToState(stateId, {
|
this.moveToState(stateId, {
|
||||||
backToStateId: this.key,
|
backToStateId: this.key,
|
||||||
backToStatePayload: {
|
backToStatePayload: {
|
||||||
@ -89,43 +125,20 @@ export class TextualGameState extends GameState {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Overrides the GameState implementation to provide our own html
|
|
||||||
*/
|
|
||||||
internalGetFullHtml() {
|
|
||||||
let headerHtml = "";
|
|
||||||
if (this.getStateHeaderTitle()) {
|
|
||||||
headerHtml = `
|
|
||||||
<div class="headerBar">
|
|
||||||
|
|
||||||
<h1><button class="backButton"></button> ${this.getStateHeaderTitle()}</h1>
|
|
||||||
</div>`;
|
|
||||||
}
|
|
||||||
|
|
||||||
return `
|
|
||||||
${headerHtml}
|
|
||||||
<div class="container">
|
|
||||||
${this.getInnerHTML()}
|
|
||||||
|
|
||||||
</div>
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
|
|
||||||
//// INTERNALS /////
|
//// INTERNALS /////
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Overrides the GameState leave callback to cleanup stuff
|
* Overrides the GameState leave callback to cleanup stuff
|
||||||
*/
|
*/
|
||||||
internalLeaveCallback() {
|
override internalLeaveCallback() {
|
||||||
super.internalLeaveCallback();
|
super.internalLeaveCallback();
|
||||||
this.dialogs.cleanup();
|
this.dialogs.cleanup();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Overrides the GameState enter callback to setup required stuff
|
* Overrides the GameState enter callback to setup required stuff
|
||||||
* @param {any} payload
|
|
||||||
*/
|
*/
|
||||||
internalEnterCallback(payload) {
|
override internalEnterCallback(payload: any) {
|
||||||
super.internalEnterCallback(payload, false);
|
super.internalEnterCallback(payload, false);
|
||||||
if (payload.backToStateId) {
|
if (payload.backToStateId) {
|
||||||
this.backToStateId = payload.backToStateId;
|
this.backToStateId = payload.backToStateId;
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user