mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-16 13:56:35 +00:00
Prevent leaving the editor if there are unsaved changes (#23170)
* Prevent leaving the editor if there are unsaved changes * Process code review * use first composePath target * fix function calls * Use query instead * Remove id on sidebar * suggestions --------- Co-authored-by: Bram Kragten <mail@bramkragten.nl>
This commit is contained in:
commit
c8f58c7bc9
@ -48,6 +48,7 @@ import "./ha-menu-button";
|
||||
import "./ha-sortable";
|
||||
import "./ha-svg-icon";
|
||||
import "./user/ha-user-badge";
|
||||
import { preventDefault } from "../common/dom/prevent_default";
|
||||
|
||||
const SHOW_AFTER_SPACER = ["config", "developer-tools"];
|
||||
|
||||
@ -404,6 +405,7 @@ class HaSidebar extends SubscribeMixin(LitElement) {
|
||||
@focusout=${this._listboxFocusOut}
|
||||
@scroll=${this._listboxScroll}
|
||||
@keydown=${this._listboxKeydown}
|
||||
@iron-activate=${preventDefault}
|
||||
>
|
||||
${this.editMode
|
||||
? this._renderPanelsEdit(beforeSpacer)
|
||||
|
57
src/mixins/prevent-unsaved-mixin.ts
Normal file
57
src/mixins/prevent-unsaved-mixin.ts
Normal file
@ -0,0 +1,57 @@
|
||||
import type { LitElement, PropertyValues } from "lit";
|
||||
import { isNavigationClick } from "../common/dom/is-navigation-click";
|
||||
import type { Constructor } from "../types";
|
||||
|
||||
export const PreventUnsavedMixin = <T extends Constructor<LitElement>>(
|
||||
superClass: T
|
||||
) =>
|
||||
class extends superClass {
|
||||
private _handleClick = async (e: MouseEvent) => {
|
||||
// get the right target, otherwise the composedPath would return <home-assistant> in the new event
|
||||
const target = e.composedPath()[0];
|
||||
if (!isNavigationClick(e)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const result = await this.promptDiscardChanges();
|
||||
if (result) {
|
||||
this._removeListeners();
|
||||
if (target) {
|
||||
const newEvent = new MouseEvent(e.type, e);
|
||||
target.dispatchEvent(newEvent);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
private _handleUnload = (e: BeforeUnloadEvent) => e.preventDefault();
|
||||
|
||||
private _removeListeners() {
|
||||
window.removeEventListener("click", this._handleClick, true);
|
||||
window.removeEventListener("beforeunload", this._handleUnload);
|
||||
}
|
||||
|
||||
public willUpdate(changedProperties: PropertyValues): void {
|
||||
super.willUpdate(changedProperties);
|
||||
|
||||
if (this.isDirty) {
|
||||
window.addEventListener("click", this._handleClick, true);
|
||||
window.addEventListener("beforeunload", this._handleUnload);
|
||||
} else {
|
||||
this._removeListeners();
|
||||
}
|
||||
}
|
||||
|
||||
public disconnectedCallback(): void {
|
||||
super.disconnectedCallback();
|
||||
|
||||
this._removeListeners();
|
||||
}
|
||||
|
||||
protected get isDirty(): boolean {
|
||||
return false;
|
||||
}
|
||||
|
||||
protected async promptDiscardChanges(): Promise<boolean> {
|
||||
return true;
|
||||
}
|
||||
};
|
@ -64,6 +64,7 @@ import { showAutomationModeDialog } from "./automation-mode-dialog/show-dialog-a
|
||||
import { showAutomationRenameDialog } from "./automation-rename-dialog/show-dialog-automation-rename";
|
||||
import "./blueprint-automation-editor";
|
||||
import "./manual-automation-editor";
|
||||
import { PreventUnsavedMixin } from "../../../mixins/prevent-unsaved-mixin";
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
@ -82,7 +83,9 @@ declare global {
|
||||
}
|
||||
}
|
||||
|
||||
export class HaAutomationEditor extends KeyboardShortcutMixin(LitElement) {
|
||||
export class HaAutomationEditor extends PreventUnsavedMixin(
|
||||
KeyboardShortcutMixin(LitElement)
|
||||
) {
|
||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||
|
||||
@property({ attribute: false }) public automationId: string | null = null;
|
||||
@ -847,6 +850,14 @@ export class HaAutomationEditor extends KeyboardShortcutMixin(LitElement) {
|
||||
};
|
||||
}
|
||||
|
||||
protected get isDirty() {
|
||||
return this._dirty;
|
||||
}
|
||||
|
||||
protected async promptDiscardChanges() {
|
||||
return this._confirmUnsavedChanged();
|
||||
}
|
||||
|
||||
static get styles(): CSSResultGroup {
|
||||
return [
|
||||
haStyle,
|
||||
|
@ -77,6 +77,7 @@ import { haStyle } from "../../../resources/styles";
|
||||
import type { HomeAssistant, Route } from "../../../types";
|
||||
import { showToast } from "../../../util/toast";
|
||||
import "../ha-config-section";
|
||||
import { PreventUnsavedMixin } from "../../../mixins/prevent-unsaved-mixin";
|
||||
|
||||
interface DeviceEntities {
|
||||
id: string;
|
||||
@ -89,8 +90,8 @@ interface DeviceEntitiesLookup {
|
||||
}
|
||||
|
||||
@customElement("ha-scene-editor")
|
||||
export class HaSceneEditor extends SubscribeMixin(
|
||||
KeyboardShortcutMixin(LitElement)
|
||||
export class HaSceneEditor extends PreventUnsavedMixin(
|
||||
SubscribeMixin(KeyboardShortcutMixin(LitElement))
|
||||
) {
|
||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||
|
||||
@ -1225,6 +1226,14 @@ export class HaSceneEditor extends SubscribeMixin(
|
||||
});
|
||||
}
|
||||
|
||||
protected get isDirty() {
|
||||
return this._dirty;
|
||||
}
|
||||
|
||||
protected async promptDiscardChanges() {
|
||||
return this._confirmUnsavedChanged();
|
||||
}
|
||||
|
||||
static get styles(): CSSResultGroup {
|
||||
return [
|
||||
haStyle,
|
||||
|
@ -57,8 +57,11 @@ import "./blueprint-script-editor";
|
||||
import "./manual-script-editor";
|
||||
import type { HaManualScriptEditor } from "./manual-script-editor";
|
||||
import { substituteBlueprint } from "../../../data/blueprint";
|
||||
import { PreventUnsavedMixin } from "../../../mixins/prevent-unsaved-mixin";
|
||||
|
||||
export class HaScriptEditor extends KeyboardShortcutMixin(LitElement) {
|
||||
export class HaScriptEditor extends PreventUnsavedMixin(
|
||||
KeyboardShortcutMixin(LitElement)
|
||||
) {
|
||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||
|
||||
@property({ attribute: false }) public scriptId: string | null = null;
|
||||
@ -813,6 +816,14 @@ export class HaScriptEditor extends KeyboardShortcutMixin(LitElement) {
|
||||
};
|
||||
}
|
||||
|
||||
protected get isDirty() {
|
||||
return this._dirty;
|
||||
}
|
||||
|
||||
protected async promptDiscardChanges() {
|
||||
return this._confirmUnsavedChanged();
|
||||
}
|
||||
|
||||
static get styles(): CSSResultGroup {
|
||||
return [
|
||||
haStyle,
|
||||
|
Loading…
x
Reference in New Issue
Block a user