From 9e416e829c932c8a77b1f55282eee8c9bafe1672 Mon Sep 17 00:00:00 2001 From: Paul Bottein Date: Fri, 16 Sep 2022 13:38:31 +0200 Subject: [PATCH] Do not recreate entities list at each re-order (#13751) --- .../lovelace/components/hui-entity-editor.ts | 132 +++++------- .../editor/hui-entities-card-row-editor.ts | 196 ++++++++---------- 2 files changed, 142 insertions(+), 186 deletions(-) diff --git a/src/panels/lovelace/components/hui-entity-editor.ts b/src/panels/lovelace/components/hui-entity-editor.ts index e5219ca990..dbfa9b1eaf 100644 --- a/src/panels/lovelace/components/hui-entity-editor.ts +++ b/src/panels/lovelace/components/hui-entity-editor.ts @@ -1,14 +1,7 @@ import { mdiDrag } from "@mdi/js"; -import { - css, - CSSResultGroup, - html, - LitElement, - PropertyValues, - TemplateResult, -} from "lit"; -import { customElement, property, state } from "lit/decorators"; -import { guard } from "lit/directives/guard"; +import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import { customElement, property } from "lit/decorators"; +import { repeat } from "lit/directives/repeat"; import type { SortableEvent } from "sortablejs"; import { fireEvent } from "../../../common/dom/fire_event"; import "../../../components/entity/ha-entity-picker"; @@ -30,20 +23,20 @@ export class HuiEntityEditor extends LitElement { @property() protected label?: string; - @state() private _attached = false; - - @state() private _renderEmptySortable = false; + private _entityKeys = new WeakMap(); private _sortable?: SortableInstance; - public connectedCallback() { - super.connectedCallback(); - this._attached = true; + public disconnectedCallback() { + this._destroySortable(); } - public disconnectedCallback() { - super.disconnectedCallback(); - this._attached = false; + private _getKey(action: EntityConfig) { + if (!this._entityKeys.has(action)) { + this._entityKeys.set(action, Math.random().toString()); + } + + return this._entityKeys.get(action)!; } protected render(): TemplateResult { @@ -60,23 +53,23 @@ export class HuiEntityEditor extends LitElement { ")"}
- ${guard([this.entities, this._renderEmptySortable], () => - this._renderEmptySortable - ? "" - : this.entities!.map( - (entityConf, index) => html` -
- - -
- ` - ) + ${repeat( + this.entities, + (entityConf) => this._getKey(entityConf), + (entityConf, index) => html` +
+
+ +
+ +
+ ` )}
this._entityMoved(evt), + onChoose: (evt: SortableEvent) => { + (evt.item as any).placeholder = + document.createComment("sort-placeholder"); + evt.item.after((evt.item as any).placeholder); + }, + onEnd: (evt: SortableEvent) => { + // put back in original location + if ((evt.item as any).placeholder) { + (evt.item as any).placeholder.replaceWith(evt.item); + delete (evt.item as any).placeholder; + } + this._entityMoved(evt); + }, } ); } + private _destroySortable() { + this._sortable?.destroy(); + this._sortable = undefined; + } + private async _addEntity(ev: CustomEvent): Promise { const value = ev.detail.value; if (value === "") { @@ -198,9 +174,15 @@ export class HuiEntityEditor extends LitElement { display: flex; align-items: center; } - .entity ha-svg-icon { + .entity .handle { padding-right: 8px; cursor: move; + padding-inline-end: 8px; + padding-inline-start: initial; + direction: var(--direction); + } + .entity .handle > * { + pointer-events: none; } .entity ha-entity-picker { flex-grow: 1; diff --git a/src/panels/lovelace/editor/hui-entities-card-row-editor.ts b/src/panels/lovelace/editor/hui-entities-card-row-editor.ts index 3d3925054c..eaf7b4c78b 100644 --- a/src/panels/lovelace/editor/hui-entities-card-row-editor.ts +++ b/src/panels/lovelace/editor/hui-entities-card-row-editor.ts @@ -1,14 +1,7 @@ import { mdiClose, mdiDrag, mdiPencil } from "@mdi/js"; -import { - css, - CSSResultGroup, - html, - LitElement, - PropertyValues, - TemplateResult, -} from "lit"; -import { customElement, property, state } from "lit/decorators"; -import { guard } from "lit/directives/guard"; +import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import { customElement, property } from "lit/decorators"; +import { repeat } from "lit/directives/repeat"; import type { SortableEvent } from "sortablejs"; import { fireEvent } from "../../../common/dom/fire_event"; import "../../../components/entity/ha-entity-picker"; @@ -39,20 +32,20 @@ export class HuiEntitiesCardRowEditor extends LitElement { @property() protected label?: string; - @state() private _attached = false; - - @state() private _renderEmptySortable = false; + private _entityKeys = new WeakMap(); private _sortable?: SortableInstance; - public connectedCallback() { - super.connectedCallback(); - this._attached = true; + public disconnectedCallback() { + this._destroySortable(); } - public disconnectedCallback() { - super.disconnectedCallback(); - this._attached = false; + private _getKey(action: LovelaceRowConfig) { + if (!this._entityKeys.has(action)) { + this._entityKeys.set(action, Math.random().toString()); + } + + return this._entityKeys.get(action)!; } protected render(): TemplateResult { @@ -70,63 +63,61 @@ export class HuiEntitiesCardRowEditor extends LitElement { )})`}
- ${guard([this.entities, this._renderEmptySortable], () => - this._renderEmptySortable - ? "" - : this.entities!.map( - (entityConf, index) => html` -
-
- + ${repeat( + this.entities, + (entityConf) => this._getKey(entityConf), + (entityConf, index) => html` +
+
+ +
+ ${entityConf.type + ? html` +
+
+ + ${this.hass!.localize( + `ui.panel.lovelace.editor.card.entities.entity_row.${entityConf.type}` + )} + + ${this.hass!.localize( + "ui.panel.lovelace.editor.card.entities.edit_special_row" + )} +
- ${entityConf.type - ? html` -
-
- - ${this.hass!.localize( - `ui.panel.lovelace.editor.card.entities.entity_row.${entityConf.type}` - )} - - ${this.hass!.localize( - "ui.panel.lovelace.editor.card.entities.edit_special_row" - )} -
-
- ` - : html` - - `} - - -
- ` - ) + @value-changed=${this._valueChanged} + > + `} + + +
+ ` )}
this._rowMoved(evt), + onChoose: (evt: SortableEvent) => { + (evt.item as any).placeholder = + document.createComment("sort-placeholder"); + evt.item.after((evt.item as any).placeholder); + }, + onEnd: (evt: SortableEvent) => { + // put back in original location + if ((evt.item as any).placeholder) { + (evt.item as any).placeholder.replaceWith(evt.item); + delete (evt.item as any).placeholder; + } + this._rowMoved(evt); + }, } ); } + private _destroySortable() { + this._sortable?.destroy(); + this._sortable = undefined; + } + private async _addEntity(ev: CustomEvent): Promise { const value = ev.detail.value; if (value === "") {