+
${this._renderItems(checkedItems, unavailable)}
`
- : ""}
+ : nothing}
`;
}
+ private _renderMenu(config: TodoListCardConfig, unavailable: boolean) {
+ return (!config.display_order ||
+ config.display_order === TodoSortMode.NONE) &&
+ this._todoListSupportsFeature(TodoListEntityFeature.MOVE_TODO_ITEM)
+ ? html`
+
+
+ ${this.hass!.localize(
+ this._reordering
+ ? "ui.panel.lovelace.cards.todo-list.exit_reorder_items"
+ : "ui.panel.lovelace.cards.todo-list.reorder_items"
+ )}
+
+
+
+ `
+ : nothing;
+ }
+
private _getDueDate(item: TodoItem): Date | undefined {
return item.due
? item.due.includes("T")
@@ -397,16 +467,19 @@ export class HuiTodoListCard extends LitElement implements LovelaceCard {
left
.hasMeta=${showReorder || showDelete}
class="editRow ${classMap({
- draggable: item.status === TodoItemStatus.NeedsAction,
+ draggable: item.status !== TodoItemStatus.Completed,
completed: item.status === TodoItemStatus.Completed,
multiline: Boolean(item.description || item.due),
})}"
.selected=${item.status === TodoItemStatus.Completed}
- .disabled=${unavailable ||
- !this._todoListSupportsFeature(
+ .disabled=${unavailable}
+ .checkboxDisabled=${!this._todoListSupportsFeature(
+ TodoListEntityFeature.UPDATE_TODO_ITEM
+ )}
+ .indeterminate=${!item.status}
+ .noninteractive=${!this._todoListSupportsFeature(
TodoListEntityFeature.UPDATE_TODO_ITEM
)}
- item-id=${item.uid}
.itemId=${item.uid}
@change=${this._completeItem}
@click=${this._openItem}
@@ -631,35 +704,53 @@ export class HuiTodoListCard extends LitElement implements LovelaceCard {
this._moveItem(oldIndex, newIndex);
}
- private async _moveItem(oldIndex: number, newIndex: number) {
- // correct index for header
- oldIndex -= 1;
- newIndex -= 1;
- const uncheckedItems = this._getUncheckedItems(this._items);
- const item = uncheckedItems[oldIndex];
- let prevItem: TodoItem | undefined;
- if (newIndex > 0) {
- if (newIndex < oldIndex) {
- prevItem = uncheckedItems[newIndex - 1];
- } else {
- prevItem = uncheckedItems[newIndex];
+ private _findFirstItem(
+ items: HTMLCollection,
+ start: number,
+ direction: "up" | "down"
+ ) {
+ let item: Element | undefined;
+ let index = direction === "up" ? start - 1 : start;
+ while (item?.localName !== "ha-check-list-item") {
+ item = items[index];
+ index = direction === "up" ? index - 1 : index + 1;
+ if (!item) {
+ break;
}
}
+ return item;
+ }
+
+ private async _moveItem(oldIndex: number, newIndex: number) {
+ await this.updateComplete;
+
+ const list = this.renderRoot.querySelector("ha-list")!;
+
+ const items = list.children;
+
+ const itemId = (items[oldIndex] as any).itemId as string;
+
+ const prevItemId = (
+ this._findFirstItem(
+ items,
+ newIndex,
+ newIndex < oldIndex ? "up" : "down"
+ ) as any
+ )?.itemId;
// Optimistic change
- const itemIndex = this._items!.findIndex((itm) => itm.uid === item.uid);
- this._items!.splice(itemIndex, 1);
- if (newIndex === 0) {
+ const itemIndex = this._items!.findIndex((itm) => itm.uid === itemId);
+ const item = this._items!.splice(itemIndex, 1)[0];
+
+ if (!prevItemId) {
this._items!.unshift(item);
} else {
- const prevIndex = this._items!.findIndex(
- (itm) => itm.uid === prevItem!.uid
- );
+ const prevIndex = this._items!.findIndex((itm) => itm.uid === prevItemId);
this._items!.splice(prevIndex + 1, 0, item);
}
this._items = [...this._items!];
- await moveItem(this.hass!, this._entityId!, item.uid, prevItem?.uid);
+ await moveItem(this.hass!, this._entityId!, itemId, prevItemId);
}
static styles = css`
diff --git a/src/translations/en.json b/src/translations/en.json
index 754e42f2a4..8f950019b8 100644
--- a/src/translations/en.json
+++ b/src/translations/en.json
@@ -6529,6 +6529,7 @@
"unchecked_items": "Active",
"no_unchecked_items": "You have no to-do items!",
"checked_items": "Completed",
+ "no_status_items": "No status",
"clear_items": "Remove completed items",
"add_item": "Add item",
"today": "Today",