Close dialogs on history back (#6354)

This commit is contained in:
Bram Kragten 2020-07-12 22:19:26 +02:00 committed by GitHub
parent 3bc54aa9e0
commit 3d32e6310d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 236 additions and 146 deletions

View File

@ -35,6 +35,7 @@ import "./step-flow-external";
import "./step-flow-form"; import "./step-flow-form";
import "./step-flow-loading"; import "./step-flow-loading";
import "./step-flow-pick-handler"; import "./step-flow-pick-handler";
import { fireEvent } from "../../common/dom/fire_event";
import { computeRTL } from "../../common/util/compute_rtl"; import { computeRTL } from "../../common/util/compute_rtl";
let instance = 0; let instance = 0;
@ -114,6 +115,17 @@ class DataEntryFlowDialog extends LitElement {
this._loading = false; this._loading = false;
} }
public closeDialog() {
if (this._step) {
this._flowDone();
} else if (this._step === null) {
// Flow aborted during picking flow
this._step = undefined;
this._params = undefined;
}
fireEvent(this, "dialog-closed", { dialog: this.localName });
}
protected render(): TemplateResult { protected render(): TemplateResult {
if (!this._params) { if (!this._params) {
return html``; return html``;
@ -122,7 +134,7 @@ class DataEntryFlowDialog extends LitElement {
return html` return html`
<ha-dialog <ha-dialog
open open
@closing=${this._close} @closed=${this.closeDialog}
scrimClickAction scrimClickAction
escapeKeyAction escapeKeyAction
hideActions hideActions
@ -297,16 +309,6 @@ class DataEntryFlowDialog extends LitElement {
} }
} }
private _close(): void {
if (this._step) {
this._flowDone();
} else if (this._step === null) {
// Flow aborted during picking flow
this._step = undefined;
this._params = undefined;
}
}
static get styles(): CSSResultArray { static get styles(): CSSResultArray {
return [ return [
haStyleDialog, haStyleDialog,

View File

@ -16,6 +16,7 @@ import { PolymerChangedEvent } from "../../polymer-types";
import { haStyleDialog } from "../../resources/styles"; import { haStyleDialog } from "../../resources/styles";
import { HomeAssistant } from "../../types"; import { HomeAssistant } from "../../types";
import { DialogParams } from "./show-dialog-box"; import { DialogParams } from "./show-dialog-box";
import { fireEvent } from "../../common/dom/fire_event";
@customElement("dialog-box") @customElement("dialog-box")
class DialogBox extends LitElement { class DialogBox extends LitElement {
@ -32,6 +33,17 @@ class DialogBox extends LitElement {
} }
} }
public closeDialog(): boolean {
if (this._params?.confirmation || this._params?.prompt) {
this._dismiss();
return true;
}
if (this._params) {
return false;
}
return true;
}
protected render(): TemplateResult { protected render(): TemplateResult {
if (!this._params) { if (!this._params) {
return html``; return html``;
@ -100,11 +112,11 @@ class DialogBox extends LitElement {
this._value = ev.detail.value; this._value = ev.detail.value;
} }
private async _dismiss(): Promise<void> { private _dismiss(): void {
if (this._params!.cancel) { if (this._params!.cancel) {
this._params!.cancel(); this._params!.cancel();
} }
this._params = undefined; this._close();
} }
private _handleKeyUp(ev: KeyboardEvent) { private _handleKeyUp(ev: KeyboardEvent) {
@ -113,15 +125,16 @@ class DialogBox extends LitElement {
} }
} }
private async _confirm(): Promise<void> { private _confirm(): void {
if (this._params!.confirm) { if (this._params!.confirm) {
this._params!.confirm(this._value); this._params!.confirm(this._value);
} }
this._dismiss(); this._close();
} }
private _close(): void { private _close(): void {
this._params = undefined; this._params = undefined;
fireEvent(this, "dialog-closed", { dialog: this.localName });
} }
static get styles(): CSSResult[] { static get styles(): CSSResult[] {

View File

@ -6,15 +6,18 @@ declare global {
interface HASSDomEvents { interface HASSDomEvents {
"show-dialog": ShowDialogParams<unknown>; "show-dialog": ShowDialogParams<unknown>;
"close-dialog": undefined; "close-dialog": undefined;
"dialog-closed": DialogClosedParams;
} }
// for add event listener // for add event listener
interface HTMLElementEventMap { interface HTMLElementEventMap {
"show-dialog": HASSDomEvent<ShowDialogParams<unknown>>; "show-dialog": HASSDomEvent<ShowDialogParams<unknown>>;
"dialog-closed": HASSDomEvent<DialogClosedParams>;
} }
} }
interface HassDialog<T = HASSDomEvents[ValidHassDomEvent]> extends HTMLElement { interface HassDialog<T = HASSDomEvents[ValidHassDomEvent]> extends HTMLElement {
showDialog(params: T); showDialog(params: T);
closeDialog?: () => boolean | void;
} }
interface ShowDialogParams<T> { interface ShowDialogParams<T> {
@ -23,16 +26,30 @@ interface ShowDialogParams<T> {
dialogParams: T; dialogParams: T;
} }
export interface DialogClosedParams {
dialog: string;
}
export interface DialogState {
dialog: string;
open: boolean;
oldState: null | DialogState;
dialogParams?: unknown;
}
const LOADED = {}; const LOADED = {};
export const showDialog = async ( export const showDialog = async (
element: HTMLElement & ProvideHassElement, element: HTMLElement & ProvideHassElement,
root: ShadowRoot | HTMLElement, root: ShadowRoot | HTMLElement,
dialogImport: () => Promise<unknown>,
dialogTag: string, dialogTag: string,
dialogParams: unknown dialogParams: unknown,
dialogImport?: () => Promise<unknown>
) => { ) => {
if (!(dialogTag in LOADED)) { if (!(dialogTag in LOADED)) {
if (!dialogImport) {
return;
}
LOADED[dialogTag] = dialogImport().then(() => { LOADED[dialogTag] = dialogImport().then(() => {
const dialogEl = document.createElement(dialogTag) as HassDialog; const dialogEl = document.createElement(dialogTag) as HassDialog;
element.provideHass(dialogEl); element.provideHass(dialogEl);
@ -40,19 +57,55 @@ export const showDialog = async (
return dialogEl; return dialogEl;
}); });
} }
history.replaceState(
{
dialog: dialogTag,
open: false,
oldState:
history.state?.open && history.state?.dialog !== dialogTag
? history.state
: null,
},
""
);
try {
history.pushState(
{ dialog: dialogTag, dialogParams: dialogParams, open: true },
""
);
} catch (err) {
// dialogParams could not be cloned, probably contains callback
history.pushState(
{ dialog: dialogTag, dialogParams: null, open: true },
""
);
}
const dialogElement = await LOADED[dialogTag]; const dialogElement = await LOADED[dialogTag];
dialogElement.showDialog(dialogParams); dialogElement.showDialog(dialogParams);
}; };
export const closeDialog = async (dialogTag: string): Promise<boolean> => {
if (!(dialogTag in LOADED)) {
return true;
}
const dialogElement = await LOADED[dialogTag];
if (dialogElement.closeDialog) {
return dialogElement.closeDialog() !== false;
}
return true;
};
export const makeDialogManager = ( export const makeDialogManager = (
element: HTMLElement & ProvideHassElement, element: HTMLElement & ProvideHassElement,
root: ShadowRoot | HTMLElement root: ShadowRoot | HTMLElement
) => { ) => {
element.addEventListener( element.addEventListener(
"show-dialog", "show-dialog",
async (e: HASSDomEvent<ShowDialogParams<unknown>>) => { (e: HASSDomEvent<ShowDialogParams<unknown>>) => {
const { dialogTag, dialogImport, dialogParams } = e.detail; const { dialogTag, dialogImport, dialogParams } = e.detail;
showDialog(element, root, dialogImport, dialogTag, dialogParams); showDialog(element, root, dialogTag, dialogParams, dialogImport);
} }
); );
}; };

View File

@ -8,6 +8,7 @@ import { isComponentLoaded } from "../../common/config/is_component_loaded";
import { DOMAINS_MORE_INFO_NO_HISTORY } from "../../common/const"; import { DOMAINS_MORE_INFO_NO_HISTORY } from "../../common/const";
import { computeStateName } from "../../common/entity/compute_state_name"; import { computeStateName } from "../../common/entity/compute_state_name";
import { navigate } from "../../common/navigate"; import { navigate } from "../../common/navigate";
import { fireEvent } from "../../common/dom/fire_event";
import "../../components/state-history-charts"; import "../../components/state-history-charts";
import { removeEntityRegistryEntry } from "../../data/entity_registry"; import { removeEntityRegistryEntry } from "../../data/entity_registry";
import { showEntityEditorDialog } from "../../panels/config/entities/show-dialog-entity-editor"; import { showEntityEditorDialog } from "../../panels/config/entities/show-dialog-entity-editor";
@ -24,7 +25,6 @@ import {
} from "lit-element"; } from "lit-element";
import { haStyleDialog } from "../../resources/styles"; import { haStyleDialog } from "../../resources/styles";
import { HomeAssistant } from "../../types"; import { HomeAssistant } from "../../types";
import { fireEvent } from "../../common/dom/fire_event";
import { getRecentWithCache } from "../../data/cached-history"; import { getRecentWithCache } from "../../data/cached-history";
import { computeDomain } from "../../common/entity/compute_domain"; import { computeDomain } from "../../common/entity/compute_domain";
import { mdiClose, mdiCog, mdiPencil } from "@mdi/js"; import { mdiClose, mdiCog, mdiPencil } from "@mdi/js";
@ -34,6 +34,10 @@ const DOMAINS_NO_INFO = ["camera", "configurator", "history_graph"];
const EDITABLE_DOMAINS_WITH_ID = ["scene", "automation"]; const EDITABLE_DOMAINS_WITH_ID = ["scene", "automation"];
const EDITABLE_DOMAINS = ["script"]; const EDITABLE_DOMAINS = ["script"];
export interface MoreInfoDialogParams {
entityId: string | null;
}
@customElement("ha-more-info-dialog") @customElement("ha-more-info-dialog")
export class MoreInfoDialog extends LitElement { export class MoreInfoDialog extends LitElement {
@property() public hass!: HomeAssistant; @property() public hass!: HomeAssistant;
@ -42,39 +46,39 @@ export class MoreInfoDialog extends LitElement {
@internalProperty() private _stateHistory?: HistoryResult; @internalProperty() private _stateHistory?: HistoryResult;
@internalProperty() private _entityId?: string | null;
private _historyRefreshInterval?: number; private _historyRefreshInterval?: number;
protected updated(changedProperties) { public showDialog(params: MoreInfoDialogParams) {
super.updated(changedProperties); this._entityId = params.entityId;
if (!changedProperties.has("hass")) { if (!this._entityId) {
return; this.closeDialog();
} }
const oldHass = changedProperties.get("hass"); this.large = false;
if (oldHass && oldHass.moreInfoEntityId === this.hass.moreInfoEntityId) { this._stateHistory = undefined;
return; if (this._computeShowHistoryComponent(this._entityId)) {
} this._getStateHistory();
if (this.hass.moreInfoEntityId) {
this.large = false;
this._stateHistory = undefined;
if (this._computeShowHistoryComponent(this.hass.moreInfoEntityId)) {
this._getStateHistory();
clearInterval(this._historyRefreshInterval);
this._historyRefreshInterval = window.setInterval(() => {
this._getStateHistory();
}, 60 * 1000);
}
} else {
this._stateHistory = undefined;
clearInterval(this._historyRefreshInterval); clearInterval(this._historyRefreshInterval);
this._historyRefreshInterval = undefined; this._historyRefreshInterval = window.setInterval(() => {
this._getStateHistory();
}, 60 * 1000);
} }
} }
public closeDialog() {
this._entityId = undefined;
this._stateHistory = undefined;
clearInterval(this._historyRefreshInterval);
this._historyRefreshInterval = undefined;
fireEvent(this, "dialog-closed", { dialog: this.localName });
}
protected render() { protected render() {
if (!this.hass.moreInfoEntityId) { if (!this._entityId) {
return html``; return html``;
} }
const entityId = this.hass.moreInfoEntityId; const entityId = this._entityId;
const stateObj = this.hass.states[entityId]; const stateObj = this.hass.states[entityId];
const domain = computeDomain(entityId); const domain = computeDomain(entityId);
@ -85,7 +89,7 @@ export class MoreInfoDialog extends LitElement {
return html` return html`
<ha-dialog <ha-dialog
open open
@closed=${this._close} @closed=${this.closeDialog}
.heading=${true} .heading=${true}
hideActions hideActions
data-domain=${domain} data-domain=${domain}
@ -174,15 +178,15 @@ export class MoreInfoDialog extends LitElement {
} }
private async _getStateHistory(): Promise<void> { private async _getStateHistory(): Promise<void> {
if (!this.hass.moreInfoEntityId) { if (!this._entityId) {
return; return;
} }
this._stateHistory = await getRecentWithCache( this._stateHistory = await getRecentWithCache(
this.hass!, this.hass!,
this.hass.moreInfoEntityId, this._entityId,
{ {
refresh: 60, refresh: 60,
cacheKey: `more_info.${this.hass.moreInfoEntityId}`, cacheKey: `more_info.${this._entityId}`,
hoursToShow: 24, hoursToShow: 24,
}, },
this.hass!.localize, this.hass!.localize,
@ -198,7 +202,7 @@ export class MoreInfoDialog extends LitElement {
} }
private _removeEntity() { private _removeEntity() {
const entityId = this.hass.moreInfoEntityId!; const entityId = this._entityId!;
showConfirmationDialog(this, { showConfirmationDialog(this, {
title: this.hass.localize( title: this.hass.localize(
"ui.dialogs.more_info_control.restored.confirm_remove_title" "ui.dialogs.more_info_control.restored.confirm_remove_title"
@ -216,14 +220,14 @@ export class MoreInfoDialog extends LitElement {
private _gotoSettings() { private _gotoSettings() {
showEntityEditorDialog(this, { showEntityEditorDialog(this, {
entity_id: this.hass.moreInfoEntityId!, entity_id: this._entityId!,
}); });
fireEvent(this, "hass-more-info", { entityId: null }); this.closeDialog();
} }
private _gotoEdit() { private _gotoEdit() {
const stateObj = this.hass.states[this.hass.moreInfoEntityId!]; const stateObj = this.hass.states[this._entityId!];
const domain = computeDomain(this.hass.moreInfoEntityId!); const domain = computeDomain(this._entityId!);
navigate( navigate(
this, this,
`/config/${domain}/edit/${ `/config/${domain}/edit/${
@ -232,11 +236,7 @@ export class MoreInfoDialog extends LitElement {
: stateObj.entity_id : stateObj.entity_id
}` }`
); );
this._close(); this.closeDialog();
}
private _close() {
fireEvent(this, "hass-more-info", { entityId: null });
} }
static get styles() { static get styles() {
@ -274,7 +274,7 @@ export class MoreInfoDialog extends LitElement {
--mdc-dialog-max-width: 90vw; --mdc-dialog-max-width: 90vw;
} }
app-toolbar { ha-dialog:not([data-domain="camera"]) app-toolbar {
max-width: 368px; max-width: 368px;
} }

View File

@ -13,8 +13,8 @@ import {
TemplateResult, TemplateResult,
} from "lit-element"; } from "lit-element";
import { cache } from "lit-html/directives/cache"; import { cache } from "lit-html/directives/cache";
import { dynamicElement } from "../../../common/dom/dynamic-element-directive";
import { fireEvent } from "../../../common/dom/fire_event"; import { fireEvent } from "../../../common/dom/fire_event";
import { dynamicElement } from "../../../common/dom/dynamic-element-directive";
import { computeStateName } from "../../../common/entity/compute_state_name"; import { computeStateName } from "../../../common/entity/compute_state_name";
import "../../../components/ha-dialog"; import "../../../components/ha-dialog";
import "../../../components/ha-svg-icon"; import "../../../components/ha-svg-icon";
@ -72,6 +72,7 @@ export class DialogEntityEditor extends LitElement {
public closeDialog(): void { public closeDialog(): void {
this._params = undefined; this._params = undefined;
fireEvent(this, "dialog-closed", { dialog: this.localName });
} }
protected render(): TemplateResult { protected render(): TemplateResult {

View File

@ -20,6 +20,7 @@ import { haStyleDialog } from "../../../resources/styles";
import { HomeAssistant } from "../../../types"; import { HomeAssistant } from "../../../types";
import { SystemLogDetailDialogParams } from "./show-dialog-system-log-detail"; import { SystemLogDetailDialogParams } from "./show-dialog-system-log-detail";
import { formatSystemLogTime } from "./util"; import { formatSystemLogTime } from "./util";
import { fireEvent } from "../../../common/dom/fire_event";
class DialogSystemLogDetail extends LitElement { class DialogSystemLogDetail extends LitElement {
@property() public hass!: HomeAssistant; @property() public hass!: HomeAssistant;
@ -34,6 +35,11 @@ class DialogSystemLogDetail extends LitElement {
await this.updateComplete; await this.updateComplete;
} }
public closeDialog() {
this._params = undefined;
fireEvent(this, "dialog-closed", { dialog: this.localName });
}
protected updated(changedProps) { protected updated(changedProps) {
super.updated(changedProps); super.updated(changedProps);
if (!changedProps.has("_params") || !this._params) { if (!changedProps.has("_params") || !this._params) {
@ -137,7 +143,7 @@ class DialogSystemLogDetail extends LitElement {
private _openedChanged(ev: PolymerChangedEvent<boolean>): void { private _openedChanged(ev: PolymerChangedEvent<boolean>): void {
if (!(ev.detail as any).value) { if (!(ev.detail as any).value) {
this._params = undefined; this.closeDialog();
} }
} }

View File

@ -8,6 +8,7 @@ import {
property, property,
TemplateResult, TemplateResult,
} from "lit-element"; } from "lit-element";
import { fireEvent } from "../../../common/dom/fire_event";
import { addDistanceToCoord } from "../../../common/location/add_distance_to_coord"; import { addDistanceToCoord } from "../../../common/location/add_distance_to_coord";
import { createCloseHeading } from "../../../components/ha-dialog"; import { createCloseHeading } from "../../../components/ha-dialog";
import "../../../components/ha-switch"; import "../../../components/ha-switch";
@ -45,7 +46,7 @@ class DialogZoneDetail extends LitElement {
@property() private _submitting = false; @property() private _submitting = false;
public async showDialog(params: ZoneDetailDialogParams): Promise<void> { public showDialog(params: ZoneDetailDialogParams): void {
this._params = params; this._params = params;
this._error = undefined; this._error = undefined;
if (this._params.entry) { if (this._params.entry) {
@ -74,7 +75,11 @@ class DialogZoneDetail extends LitElement {
this._passive = false; this._passive = false;
this._radius = 100; this._radius = 100;
} }
await this.updateComplete; }
public closeDialog(): void {
this._params = undefined;
fireEvent(this, "dialog-closed", { dialog: this.localName });
} }
protected render(): TemplateResult { protected render(): TemplateResult {
@ -93,7 +98,7 @@ class DialogZoneDetail extends LitElement {
return html` return html`
<ha-dialog <ha-dialog
open open
@closing="${this._close}" @closed="${this.closeDialog}"
scrimClickAction="" scrimClickAction=""
escapeKeyAction="" escapeKeyAction=""
.heading=${createCloseHeading( .heading=${createCloseHeading(
@ -276,10 +281,6 @@ class DialogZoneDetail extends LitElement {
} }
} }
private _close(): void {
this._params = undefined;
}
static get styles(): CSSResult[] { static get styles(): CSSResult[] {
return [ return [
haStyleDialog, haStyleDialog,

View File

@ -2,6 +2,7 @@ import { HASSDomEvent } from "../common/dom/fire_event";
import { makeDialogManager, showDialog } from "../dialogs/make-dialog-manager"; import { makeDialogManager, showDialog } from "../dialogs/make-dialog-manager";
import { Constructor } from "../types"; import { Constructor } from "../types";
import { HassBaseEl } from "./hass-base-mixin"; import { HassBaseEl } from "./hass-base-mixin";
import { PropertyValues } from "lit-element";
interface RegisterDialogParams { interface RegisterDialogParams {
dialogShowEvent: keyof HASSDomEvents; dialogShowEvent: keyof HASSDomEvents;
@ -24,7 +25,7 @@ export const dialogManagerMixin = <T extends Constructor<HassBaseEl>>(
superClass: T superClass: T
) => ) =>
class extends superClass { class extends superClass {
protected firstUpdated(changedProps) { protected firstUpdated(changedProps: PropertyValues) {
super.firstUpdated(changedProps); super.firstUpdated(changedProps);
// deprecated // deprecated
this.addEventListener("register-dialog", (e) => this.addEventListener("register-dialog", (e) =>
@ -42,9 +43,9 @@ export const dialogManagerMixin = <T extends Constructor<HassBaseEl>>(
showDialog( showDialog(
this, this,
this.shadowRoot!, this.shadowRoot!,
dialogImport,
dialogTag, dialogTag,
(showEv as HASSDomEvent<unknown>).detail (showEv as HASSDomEvent<unknown>).detail,
dialogImport
); );
}); });
} }

View File

@ -1,35 +1,46 @@
import { Constructor } from "../types"; import { showDialog } from "../dialogs/make-dialog-manager";
import { HassBaseEl } from "./hass-base-mixin"; import type { Constructor } from "../types";
import type { HassBaseEl } from "./hass-base-mixin";
import type { MoreInfoDialogParams } from "../dialogs/more-info/ha-more-info-dialog";
import type { PropertyValues } from "lit-element";
import type { HASSDomEvent } from "../common/dom/fire_event";
declare global { declare global {
// for fire event // for fire event
interface HASSDomEvents { interface HASSDomEvents {
"hass-more-info": { "hass-more-info": MoreInfoDialogParams;
entityId: string | null;
};
} }
} }
let moreInfoImportPromise;
const importMoreInfo = () => {
if (!moreInfoImportPromise) {
moreInfoImportPromise = import(
/* webpackChunkName: "more-info-dialog" */ "../dialogs/more-info/ha-more-info-dialog"
);
}
return moreInfoImportPromise;
};
export default <T extends Constructor<HassBaseEl>>(superClass: T) => export default <T extends Constructor<HassBaseEl>>(superClass: T) =>
class extends superClass { class extends superClass {
private _moreInfoEl?: any; protected firstUpdated(changedProps: PropertyValues) {
protected firstUpdated(changedProps) {
super.firstUpdated(changedProps); super.firstUpdated(changedProps);
this.addEventListener("hass-more-info", (e) => this._handleMoreInfo(e)); this.addEventListener("hass-more-info", (ev) => this._handleMoreInfo(ev));
// Load it once we are having the initial rendering done. // Load it once we are having the initial rendering done.
import( importMoreInfo();
/* webpackChunkName: "more-info-dialog" */ "../dialogs/more-info/ha-more-info-dialog"
);
} }
private async _handleMoreInfo(ev) { private async _handleMoreInfo(ev: HASSDomEvent<MoreInfoDialogParams>) {
if (!this._moreInfoEl) { showDialog(
this._moreInfoEl = document.createElement("ha-more-info-dialog"); this,
this.shadowRoot!.appendChild(this._moreInfoEl); this.shadowRoot!,
this.provideHass(this._moreInfoEl); "ha-more-info-dialog",
} {
this._updateHass({ moreInfoEntityId: ev.detail.entityId }); entityId: ev.detail.entityId,
},
importMoreInfo
);
} }
}; };

View File

@ -1,9 +1,15 @@
/* eslint-disable no-console */ /* eslint-disable no-console */
import { fireEvent } from "../common/dom/fire_event"; import {
closeDialog,
showDialog,
DialogState,
DialogClosedParams,
} from "../dialogs/make-dialog-manager";
import { Constructor } from "../types"; import { Constructor } from "../types";
import { HassBaseEl } from "./hass-base-mixin"; import { HassBaseEl } from "./hass-base-mixin";
import { HASSDomEvent } from "../common/dom/fire_event";
const DEBUG = false; const DEBUG = true;
export const urlSyncMixin = <T extends Constructor<HassBaseEl>>( export const urlSyncMixin = <T extends Constructor<HassBaseEl>>(
superClass: T superClass: T
@ -12,81 +18,77 @@ export const urlSyncMixin = <T extends Constructor<HassBaseEl>>(
__DEMO__ __DEMO__
? superClass ? superClass
: class extends superClass { : class extends superClass {
private _ignoreNextHassChange = false; private _ignoreNextPopState = false;
private _ignoreNextPopstate = false;
private _moreInfoOpenedFromPath?: string;
public connectedCallback(): void { public connectedCallback(): void {
super.connectedCallback(); super.connectedCallback();
window.addEventListener("popstate", this._popstateChangeListener); window.addEventListener("popstate", this._popstateChangeListener);
this.addEventListener("dialog-closed", this._dialogClosedListener);
} }
public disconnectedCallback(): void { public disconnectedCallback(): void {
super.disconnectedCallback(); super.disconnectedCallback();
window.removeEventListener("popstate", this._popstateChangeListener); window.removeEventListener("popstate", this._popstateChangeListener);
this.removeEventListener("dialog-closed", this._dialogClosedListener);
} }
protected hassChanged(newHass, oldHass): void { private _dialogClosedListener = (
super.hassChanged(newHass, oldHass); ev: HASSDomEvent<DialogClosedParams>
) => {
if (this._ignoreNextHassChange) { // If not closed by navigating back, and not a new dialog is open, remove the open state from history
if (DEBUG) {
console.log("ignore hasschange");
}
this._ignoreNextHassChange = false;
return;
}
if ( if (
!oldHass || history.state?.open &&
oldHass.moreInfoEntityId === newHass.moreInfoEntityId history.state?.dialog === ev.detail.dialog
) { ) {
if (DEBUG) { this._ignoreNextPopState = true;
console.log("ignoring hass change");
}
return;
}
if (newHass.moreInfoEntityId) {
if (DEBUG) {
console.log("pushing state");
}
// We keep track of where we opened moreInfo from so that we don't
// pop the state when we close the modal if the modal has navigated
// us away.
this._moreInfoOpenedFromPath = window.location.pathname;
history.pushState(null, "", window.location.pathname);
} else if (
window.location.pathname === this._moreInfoOpenedFromPath
) {
if (DEBUG) {
console.log("history back");
}
this._ignoreNextPopstate = true;
history.back(); history.back();
} }
} };
private _popstateChangeListener = (ev) => { private _popstateChangeListener = (ev: PopStateEvent) => {
if (this._ignoreNextPopstate) { if (this._ignoreNextPopState) {
if (DEBUG) { this._ignoreNextPopState = false;
console.log("ignore popstate");
}
this._ignoreNextPopstate = false;
return; return;
} }
if (ev.state && "dialog" in ev.state) {
if (DEBUG) {
console.log("popstate", ev);
}
if (this.hass && this.hass.moreInfoEntityId) {
if (DEBUG) { if (DEBUG) {
console.log("deselect entity"); console.log("popstate", ev);
} }
this._ignoreNextHassChange = true; this._handleDialogStateChange(ev.state);
fireEvent(this, "hass-more-info", { entityId: null });
} }
}; };
private async _handleDialogStateChange(state: DialogState) {
if (DEBUG) {
console.log("handle state", state);
}
if (!state.open) {
const closed = await closeDialog(state.dialog);
if (!closed) {
// dialog could not be closed, push state again
history.pushState(
{
dialog: state.dialog,
open: true,
dialogParams: null,
oldState: null,
},
""
);
return;
}
if (state.oldState) {
this._handleDialogStateChange(state.oldState);
}
return;
}
if (state.dialogParams !== null) {
showDialog(
this,
this.shadowRoot!,
state.dialog,
state.dialogParams
);
}
}
}; };