From 767307ef4795c5bb67cff3b91ca138fdc3a75b9c Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Tue, 11 Dec 2018 19:47:19 +0100 Subject: [PATCH] Convert hui-view to Lit (#2265) * Convert hui-view to Lit * Add super call to updated * Update src/panels/lovelace/hui-view.ts Co-Authored-By: balloob * Apply suggestions from code review Co-Authored-By: balloob * Address comments" * Fix things --- .../lovelace/components/hui-card-options.ts | 6 +- src/panels/lovelace/hui-root.ts | 7 +- .../lovelace/{hui-view.js => hui-view.ts} | 219 +++++++++++------- .../lovelace/editor/config-util.spec.ts | 2 +- 4 files changed, 140 insertions(+), 94 deletions(-) rename src/panels/lovelace/{hui-view.js => hui-view.ts} (54%) diff --git a/src/panels/lovelace/components/hui-card-options.ts b/src/panels/lovelace/components/hui-card-options.ts index 26c0d4b707..2386fa8d1a 100644 --- a/src/panels/lovelace/components/hui-card-options.ts +++ b/src/panels/lovelace/components/hui-card-options.ts @@ -14,9 +14,9 @@ import { swapCard, moveCard } from "../editor/config-util"; export class HuiCardOptions extends hassLocalizeLitMixin(LitElement) { public cardConfig?: LovelaceCardConfig; - protected hass?: HomeAssistant; - protected lovelace?: Lovelace; - protected path?: [number, number]; + public hass?: HomeAssistant; + public lovelace?: Lovelace; + public path?: [number, number]; static get properties(): PropertyDeclarations { return { hass: {}, lovelace: {}, path: {} }; diff --git a/src/panels/lovelace/hui-root.ts b/src/panels/lovelace/hui-root.ts index a18cbb3dfd..f794001823 100644 --- a/src/panels/lovelace/hui-root.ts +++ b/src/panels/lovelace/hui-root.ts @@ -38,6 +38,9 @@ import "./components/notifications/hui-notification-drawer"; import "./components/notifications/hui-notifications-button"; import "./hui-unused-entities"; import "./hui-view"; +// Not a duplicate import, this one is for type +// tslint:disable-next-line +import { HUIView } from "./hui-view"; import createCardElement from "./common/create-card-element"; import { showEditViewDialog } from "./editor/view-editor/show-edit-view-dialog"; import { Lovelace } from "./types"; @@ -336,10 +339,10 @@ class HUIRoot extends hassLocalizeLitMixin(LitElement) { super.updated(changedProperties); const view = this._view; - const huiView = view.lastChild as any; + const huiView = view.lastChild as HUIView; if (changedProperties.has("columns") && huiView) { - (this._view.lastChild as any).columns = this.columns; + huiView.columns = this.columns; } if (changedProperties.has("hass") && huiView) { diff --git a/src/panels/lovelace/hui-view.js b/src/panels/lovelace/hui-view.ts similarity index 54% rename from src/panels/lovelace/hui-view.js rename to src/panels/lovelace/hui-view.ts index e068eee53e..52093225a1 100644 --- a/src/panels/lovelace/hui-view.js +++ b/src/panels/lovelace/hui-view.ts @@ -1,20 +1,75 @@ -import { html } from "@polymer/polymer/lib/utils/html-tag"; -import { PolymerElement } from "@polymer/polymer/polymer-element"; +import { + html, + LitElement, + PropertyValues, + PropertyDeclarations, +} from "@polymer/lit-element"; +import { TemplateResult } from "lit-html"; +import { PolymerElement } from "@polymer/polymer"; import "../../components/entity/ha-state-label-badge"; import applyThemesOnElement from "../../common/dom/apply_themes_on_element"; -import EventsMixin from "../../mixins/events-mixin"; -import localizeMixin from "../../mixins/localize-mixin"; +import { hassLocalizeLitMixin } from "../../mixins/lit-localize-mixin"; +import { LovelaceViewConfig } from "../../data/lovelace"; +import { HomeAssistant } from "../../types"; + +import { Lovelace, LovelaceCard } from "./types"; import createCardElement from "./common/create-card-element"; import { computeCardSize } from "./common/compute-card-size"; import { showEditCardDialog } from "./editor/card-editor/show-edit-card-dialog"; let editCodeLoaded = false; -class HUIView extends localizeMixin(EventsMixin(PolymerElement)) { - static get template() { +export class HUIView extends hassLocalizeLitMixin(LitElement) { + public hass?: HomeAssistant; + public lovelace?: Lovelace; + public columns?: number; + public index?: number; + private _cards: LovelaceCard[]; + private _badges: Array<{ element: PolymerElement; entityId: string }>; + + static get properties(): PropertyDeclarations { + return { + hass: {}, + lovelace: {}, + columns: {}, + index: {}, + _cards: {}, + _badges: {}, + }; + } + + constructor() { + super(); + this._cards = []; + this._badges = []; + } + + protected render(): TemplateResult { + return html` + ${this.renderStyles()} +
+
+ ${ + this.lovelace!.editMode + ? html` + + ` + : "" + } + `; + } + + protected renderStyles(): TemplateResult { return html` -
-
- `; } - static get properties() { - return { - hass: { - type: Object, - observer: "_hassChanged", - }, - lovelace: { - type: Object, - observer: "_lovelaceChanged", - }, - config: Object, - columns: Number, - editMode: Boolean, - index: Number, - }; + protected updated(changedProperties: PropertyValues): void { + super.updated(changedProperties); + + const lovelace = this.lovelace!; + + if (lovelace.editMode && !editCodeLoaded) { + editCodeLoaded = true; + import(/* webpackChunkName: "hui-view-editable" */ "./hui-view-editable"); + } + + let editModeChanged = false; + let configChanged = false; + + if (changedProperties.has("lovelace")) { + const oldLovelace = changedProperties.get("lovelace") as Lovelace; + editModeChanged = + !oldLovelace || lovelace.editMode !== oldLovelace.editMode; + configChanged = !oldLovelace || lovelace.config !== oldLovelace.config; + } + + if (configChanged) { + this._createBadges(lovelace.config.views[this.index!]); + } else if (changedProperties.has("hass")) { + this._badges.forEach((badge) => { + const { element, entityId } = badge; + element.setProperties({ + hass: this.hass, + state: this.hass!.states[entityId], + }); + }); + } + + if (configChanged || editModeChanged || changedProperties.has("columns")) { + this._createCards(lovelace.config.views[this.index!]); + } else if (changedProperties.has("hass")) { + this._cards.forEach((element) => { + element.hass = this.hass; + }); + } } - static get observers() { - return [ - // Put all properties in 1 observer so we only call configChanged once - "_createBadges(config)", - "_createCards(config, columns, editMode)", - ]; - } - - constructor() { - super(); - this._cards = []; - this._badges = []; - } - - _addCard() { + private _addCard(): void { showEditCardDialog(this, { - lovelace: this.lovelace, - path: [this.index], + lovelace: this.lovelace!, + path: [this.index!], }); } - _createBadges(config) { - const root = this.$.badges; + private _createBadges(config: LovelaceViewConfig): void { + const root = this.shadowRoot!.getElementById("badges")!; + while (root.lastChild) { root.removeChild(root.lastChild); } @@ -141,14 +194,18 @@ class HUIView extends localizeMixin(EventsMixin(PolymerElement)) { return; } - const elements = []; + const elements: HUIView["_badges"] = []; for (const entityId of config.badges) { - if (!(entityId in this.hass.states)) continue; + if (!(entityId in this.hass!.states)) { + continue; + } - const element = document.createElement("ha-state-label-badge"); + const element = document.createElement( + "ha-state-label-badge" + ) as PolymerElement; element.setProperties({ hass: this.hass, - state: this.hass.states[entityId], + state: this.hass!.states[entityId], }); elements.push({ element, entityId }); root.appendChild(element); @@ -157,8 +214,8 @@ class HUIView extends localizeMixin(EventsMixin(PolymerElement)) { root.style.display = elements.length > 0 ? "block" : "none"; } - _createCards(config) { - const root = this.$.columns; + private _createCards(config: LovelaceViewConfig): void { + const root = this.shadowRoot!.getElementById("columns")!; while (root.lastChild) { root.removeChild(root.lastChild); @@ -169,14 +226,14 @@ class HUIView extends localizeMixin(EventsMixin(PolymerElement)) { return; } - const elements = []; - const elementsToAppend = []; + const elements: LovelaceCard[] = []; + const elementsToAppend: HTMLElement[] = []; config.cards.forEach((cardConfig, cardIndex) => { - const element = createCardElement(cardConfig); + const element = createCardElement(cardConfig) as LovelaceCard; element.hass = this.hass; elements.push(element); - if (!this.lovelace.editMode) { + if (!this.lovelace!.editMode) { elementsToAppend.push(element); return; } @@ -184,14 +241,14 @@ class HUIView extends localizeMixin(EventsMixin(PolymerElement)) { const wrapper = document.createElement("hui-card-options"); wrapper.hass = this.hass; wrapper.lovelace = this.lovelace; - wrapper.path = [this.index, cardIndex]; + wrapper.path = [this.index!, cardIndex]; wrapper.appendChild(element); elementsToAppend.push(wrapper); }); - let columns = []; - const columnEntityCount = []; - for (let i = 0; i < this.columns; i++) { + let columns: HTMLElement[][] = []; + const columnEntityCount: number[] = []; + for (let i = 0; i < this.columns!; i++) { columns.push([]); columnEntityCount.push(0); } @@ -233,29 +290,15 @@ class HUIView extends localizeMixin(EventsMixin(PolymerElement)) { this._cards = elements; if ("theme" in config) { - applyThemesOnElement(root, this.hass.themes, config.theme); - } - } - - _hassChanged(hass) { - this._badges.forEach((badge) => { - const { element, entityId } = badge; - element.setProperties({ - hass, - state: hass.states[entityId], - }); - }); - this._cards.forEach((element) => { - element.hass = hass; - }); - } - - _lovelaceChanged(lovelace) { - if (lovelace.editMode && !editCodeLoaded) { - editCodeLoaded = true; - import(/* webpackChunkName: "hui-view-editable" */ "./hui-view-editable"); + applyThemesOnElement(root, this.hass!.themes, config.theme); } } } +declare global { + interface HTMLElementTagNameMap { + "hui-view": HUIView; + } +} + customElements.define("hui-view", HUIView); diff --git a/test-mocha/panels/lovelace/editor/config-util.spec.ts b/test-mocha/panels/lovelace/editor/config-util.spec.ts index dac981de04..fc417e2ca1 100644 --- a/test-mocha/panels/lovelace/editor/config-util.spec.ts +++ b/test-mocha/panels/lovelace/editor/config-util.spec.ts @@ -119,7 +119,7 @@ describe("moveCard", () => { ], }; - const result = function() { + const result = () => { moveCard(config, [1, 0], [1]); }; assert.throws(