Fix multiple sortable (#13522)

This commit is contained in:
Paul Bottein 2022-08-31 12:01:36 +02:00 committed by GitHub
parent 1e19799da9
commit c116ad67ed
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 98 additions and 81 deletions

View File

@ -49,6 +49,7 @@ import { subscribeRepairsIssueRegistry } from "../data/repairs";
import { updateCanInstall, UpdateEntity } from "../data/update";
import { SubscribeMixin } from "../mixins/subscribe-mixin";
import { actionHandler } from "../panels/lovelace/common/directives/action-handler-directive";
import { loadSortable, SortableInstance } from "../resources/sortable.ondemand";
import { haStyleScrollbar } from "../resources/styles";
import type { HomeAssistant, PanelInfo, Route } from "../types";
import "./ha-icon";
@ -177,8 +178,6 @@ const computePanels = memoizeOne(
}
);
let Sortable;
@customElement("ha-sidebar")
class HaSidebar extends SubscribeMixin(LitElement) {
@property({ attribute: false }) public hass!: HomeAssistant;
@ -205,6 +204,8 @@ class HaSidebar extends SubscribeMixin(LitElement) {
private _recentKeydownActiveUntil = 0;
private sortableStyleLoaded = false;
// @ts-ignore
@LocalStorage("sidebarPanelOrder", true, {
attribute: false,
@ -217,7 +218,7 @@ class HaSidebar extends SubscribeMixin(LitElement) {
})
private _hiddenPanels: string[] = [];
private _sortable?;
private _sortable?: SortableInstance;
public hassSubscribe(): UnsubscribeFunc[] {
return [
@ -658,36 +659,36 @@ class HaSidebar extends SubscribeMixin(LitElement) {
}
private async _activateEditMode() {
if (!Sortable) {
const [sortableImport, sortStylesImport] = await Promise.all([
import("sortablejs/modular/sortable.core.esm"),
import("../resources/ha-sortable-style"),
]);
await Promise.all([this._loadSortableStyle(), this._createSortable()]);
}
private async _loadSortableStyle() {
if (this.sortableStyleLoaded) return;
const sortStylesImport = await import("../resources/ha-sortable-style");
const style = document.createElement("style");
style.innerHTML = (sortStylesImport.sortableStyles as CSSResult).cssText;
this.shadowRoot!.appendChild(style);
Sortable = sortableImport.Sortable;
Sortable.mount(sortableImport.OnSpill);
Sortable.mount(sortableImport.AutoScroll());
}
this.sortableStyleLoaded = true;
await this.updateComplete;
this._createSortable();
}
private _createSortable() {
this._sortable = new Sortable(this.shadowRoot!.getElementById("sortable"), {
private async _createSortable() {
const Sortable = await loadSortable();
this._sortable = new Sortable(
this.shadowRoot!.getElementById("sortable")!,
{
animation: 150,
fallbackClass: "sortable-fallback",
dataIdAttr: "data-panel",
handle: "paper-icon-item",
onSort: async () => {
this._panelOrder = this._sortable.toArray();
this._panelOrder = this._sortable!.toArray();
},
});
}
);
}
private _deactivateEditMode() {

View File

@ -41,7 +41,7 @@ export const addItem = (
export const reorderItems = (
hass: HomeAssistant,
itemIds: [string]
itemIds: string[]
): Promise<ShoppingListItem> =>
hass.callWS({
type: "shopping_list/items/reorder",

View File

@ -30,8 +30,10 @@ import { HomeAssistant } from "../../../types";
import { LovelaceCard, LovelaceCardEditor } from "../types";
import { SensorCardConfig, ShoppingListCardConfig } from "./types";
import type { HaTextField } from "../../../components/ha-textfield";
let Sortable;
import {
loadSortable,
SortableInstance,
} from "../../../resources/sortable.ondemand";
@customElement("hui-shopping-list-card")
class HuiShoppingListCard
@ -59,7 +61,7 @@ class HuiShoppingListCard
@state() private _renderEmptySortable = false;
private _sortable?;
private _sortable?: SortableInstance;
@query("#sortable") private _sortableEl?: HTMLElement;
@ -299,12 +301,6 @@ class HuiShoppingListCard
}
private async _toggleReorder() {
if (!Sortable) {
const sortableImport = await import(
"sortablejs/modular/sortable.core.esm"
);
Sortable = sortableImport.Sortable;
}
this._reordering = !this._reordering;
await this.updateComplete;
if (this._reordering) {
@ -315,18 +311,22 @@ class HuiShoppingListCard
}
}
private _createSortable() {
private async _createSortable() {
const Sortable = await loadSortable();
const sortableEl = this._sortableEl;
this._sortable = new Sortable(sortableEl, {
this._sortable = new Sortable(sortableEl!, {
animation: 150,
fallbackClass: "sortable-fallback",
dataIdAttr: "item-id",
handle: "ha-svg-icon",
onEnd: async (evt) => {
if (evt.newIndex === undefined || evt.oldIndex === undefined) {
return;
}
// Since this is `onEnd` event, it's possible that
// an item wa dragged away and was put back to its original position.
if (evt.oldIndex !== evt.newIndex) {
reorderItems(this.hass!, this._sortable.toArray()).catch(() =>
reorderItems(this.hass!, this._sortable!.toArray()).catch(() =>
this._fetchData()
);
// Move the shopping list item in memory.

View File

@ -15,11 +15,13 @@ import "../../../components/entity/ha-entity-picker";
import type { HaEntityPicker } from "../../../components/entity/ha-entity-picker";
import "../../../components/ha-icon-button";
import { sortableStyles } from "../../../resources/ha-sortable-style";
import {
loadSortable,
SortableInstance,
} from "../../../resources/sortable.ondemand";
import { HomeAssistant } from "../../../types";
import { EntityConfig } from "../entity-rows/types";
let Sortable;
@customElement("hui-entity-editor")
export class HuiEntityEditor extends LitElement {
@property({ attribute: false }) protected hass?: HomeAssistant;
@ -32,7 +34,7 @@ export class HuiEntityEditor extends LitElement {
@state() private _renderEmptySortable = false;
private _sortable?;
private _sortable?: SortableInstance;
public connectedCallback() {
super.connectedCallback();
@ -123,23 +125,18 @@ export class HuiEntityEditor extends LitElement {
}
private async _createSortable() {
if (!Sortable) {
const sortableImport = await import(
"sortablejs/modular/sortable.core.esm"
);
const Sortable = await loadSortable();
Sortable = sortableImport.Sortable;
Sortable.mount(sortableImport.OnSpill);
Sortable.mount(sortableImport.AutoScroll());
}
this._sortable = new Sortable(this.shadowRoot!.querySelector(".entities"), {
this._sortable = new Sortable(
this.shadowRoot!.querySelector(".entities")!,
{
animation: 150,
fallbackClass: "sortable-fallback",
handle: "ha-svg-icon",
dataIdAttr: "data-entity-id",
onEnd: async (evt: SortableEvent) => this._entityMoved(evt),
});
}
);
}
private async _addEntity(ev: CustomEvent): Promise<void> {

View File

@ -16,11 +16,13 @@ import type { HaEntityPicker } from "../../../components/entity/ha-entity-picker
import "../../../components/ha-icon-button";
import "../../../components/ha-svg-icon";
import { sortableStyles } from "../../../resources/ha-sortable-style";
import {
loadSortable,
SortableInstance,
} from "../../../resources/sortable.ondemand";
import { HomeAssistant } from "../../../types";
import { EntityConfig, LovelaceRowConfig } from "../entity-rows/types";
let Sortable;
declare global {
interface HASSDomEvents {
"entities-changed": {
@ -41,7 +43,7 @@ export class HuiEntitiesCardRowEditor extends LitElement {
@state() private _renderEmptySortable = false;
private _sortable?;
private _sortable?: SortableInstance;
public connectedCallback() {
super.connectedCallback();
@ -173,22 +175,17 @@ export class HuiEntitiesCardRowEditor extends LitElement {
}
private async _createSortable() {
if (!Sortable) {
const sortableImport = await import(
"sortablejs/modular/sortable.core.esm"
);
const Sortable = await loadSortable();
Sortable = sortableImport.Sortable;
Sortable.mount(sortableImport.OnSpill);
Sortable.mount(sortableImport.AutoScroll());
}
this._sortable = new Sortable(this.shadowRoot!.querySelector(".entities"), {
this._sortable = new Sortable(
this.shadowRoot!.querySelector(".entities")!,
{
animation: 150,
fallbackClass: "sortable-fallback",
handle: ".handle",
onEnd: async (evt: SortableEvent) => this._rowMoved(evt),
});
}
);
}
private async _addEntity(ev: CustomEvent): Promise<void> {

View File

@ -0,0 +1,11 @@
let loaded: typeof import("./sortable").default;
export type { SortableInstance } from "./sortable";
export const loadSortable = async (): Promise<
typeof import("./sortable").default
> => {
if (!loaded) {
loaded = (await import("./sortable")).default;
}
return loaded;
};

11
src/resources/sortable.ts Normal file
View File

@ -0,0 +1,11 @@
import Sortable from "sortablejs";
import SortableCore, {
OnSpill,
AutoScroll,
} from "sortablejs/modular/sortable.core.esm";
SortableCore.mount(OnSpill, new AutoScroll());
export default SortableCore as typeof Sortable;
export type { Sortable as SortableInstance };