Wait with navigate until history.back is done (#11152)

Co-authored-by: Paulus Schoutsen <balloob@gmail.com>
This commit is contained in:
Bram Kragten 2022-01-11 00:30:21 +01:00 committed by Paulus Schoutsen
parent 0ab8f8fd7c
commit 204ccf8b40
3 changed files with 39 additions and 10 deletions

View File

@ -1,3 +1,4 @@
import { historyPromise } from "../state/url-sync-mixin";
import { fireEvent } from "./dom/fire_event"; import { fireEvent } from "./dom/fire_event";
import { mainWindow } from "./dom/get_main_window"; import { mainWindow } from "./dom/get_main_window";
@ -15,6 +16,11 @@ export interface NavigateOptions {
export const navigate = (path: string, options?: NavigateOptions) => { export const navigate = (path: string, options?: NavigateOptions) => {
const replace = options?.replace || false; const replace = options?.replace || false;
if (historyPromise) {
historyPromise.then(() => navigate(path, options));
return;
}
if (__DEMO__) { if (__DEMO__) {
if (replace) { if (replace) {
mainWindow.history.replaceState( mainWindow.history.replaceState(

View File

@ -2,7 +2,6 @@ import "@material/mwc-button";
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
import { customElement, property, state } from "lit/decorators"; import { customElement, property, state } from "lit/decorators";
import { fireEvent } from "../../../common/dom/fire_event"; import { fireEvent } from "../../../common/dom/fire_event";
import { nextRender } from "../../../common/util/render-status";
import "../../../components/ha-blueprint-picker"; import "../../../components/ha-blueprint-picker";
import "../../../components/ha-card"; import "../../../components/ha-card";
import "../../../components/ha-circular-progress"; import "../../../components/ha-circular-progress";
@ -26,9 +25,11 @@ class DialogNewAutomation extends LitElement implements HassDialog {
} }
public closeDialog(): void { public closeDialog(): void {
this._opened = false; if (this._opened) {
fireEvent(this, "dialog-closed", { dialog: this.localName }); fireEvent(this, "dialog-closed", { dialog: this.localName });
} }
this._opened = false;
}
protected render(): TemplateResult { protected render(): TemplateResult {
if (!this._opened) { if (!this._opened) {
@ -66,8 +67,8 @@ class DialogNewAutomation extends LitElement implements HassDialog {
"ui.panel.config.automation.dialog_new.start_empty_description" "ui.panel.config.automation.dialog_new.start_empty_description"
)} )}
</span> </span>
<ha-icon-next slot="meta"></ha-icon-next <ha-icon-next slot="meta"></ha-icon-next>
></mwc-list-item> </mwc-list-item>
</mwc-list> </mwc-list>
</ha-dialog> </ha-dialog>
`; `;
@ -75,7 +76,6 @@ class DialogNewAutomation extends LitElement implements HassDialog {
private async _blueprintPicked(ev: CustomEvent) { private async _blueprintPicked(ev: CustomEvent) {
this.closeDialog(); this.closeDialog();
await nextRender();
showAutomationEditor({ use_blueprint: { path: ev.detail.value } }); showAutomationEditor({ use_blueprint: { path: ev.detail.value } });
} }
@ -85,7 +85,6 @@ class DialogNewAutomation extends LitElement implements HassDialog {
private async _blank() { private async _blank() {
this.closeDialog(); this.closeDialog();
await nextRender();
showAutomationEditor(); showAutomationEditor();
} }

View File

@ -13,6 +13,11 @@ import { Constructor } from "../types";
const DEBUG = false; const DEBUG = false;
// eslint-disable-next-line import/no-mutable-exports
export let historyPromise: Promise<void> | undefined;
let historyResolve: undefined | (() => void);
export const urlSyncMixin = < export const urlSyncMixin = <
T extends Constructor<ReactiveElement & ProvideHassElement> T extends Constructor<ReactiveElement & ProvideHassElement>
>( >(
@ -62,16 +67,26 @@ export const urlSyncMixin = <
if (DEBUG) { if (DEBUG) {
console.log("remove state", ev.detail.dialog); console.log("remove state", ev.detail.dialog);
} }
if (history.length) {
this._ignoreNextPopState = true; this._ignoreNextPopState = true;
historyPromise = new Promise((resolve) => {
historyResolve = () => {
resolve();
historyResolve = undefined;
historyPromise = undefined;
};
mainWindow.history.back(); mainWindow.history.back();
});
}
} }
}; };
private _popstateChangeListener = (ev: PopStateEvent) => { private _popstateChangeListener = (ev: PopStateEvent) => {
if (this._ignoreNextPopState) { if (this._ignoreNextPopState) {
if ( if (
ev.state?.oldState?.replaced || history.length &&
ev.state?.oldState?.dialogParams === null (ev.state?.oldState?.replaced ||
ev.state?.oldState?.dialogParams === null)
) { ) {
// if the previous dialog was replaced, or we could not copy the params, and the current dialog is closed, we should also remove the previous dialog from history // if the previous dialog was replaced, or we could not copy the params, and the current dialog is closed, we should also remove the previous dialog from history
if (DEBUG) { if (DEBUG) {
@ -80,7 +95,13 @@ export const urlSyncMixin = <
mainWindow.history.back(); mainWindow.history.back();
return; return;
} }
if (DEBUG) {
console.log("ignore popstate");
}
this._ignoreNextPopState = false; this._ignoreNextPopState = false;
if (historyResolve) {
historyResolve();
}
return; return;
} }
if (ev.state && "dialog" in ev.state) { if (ev.state && "dialog" in ev.state) {
@ -89,6 +110,9 @@ export const urlSyncMixin = <
} }
this._handleDialogStateChange(ev.state); this._handleDialogStateChange(ev.state);
} }
if (historyResolve) {
historyResolve();
}
}; };
private async _handleDialogStateChange(state: DialogState) { private async _handleDialogStateChange(state: DialogState) {