From 2758e86fab92bf97fda22cc1f042691e5beb1dd4 Mon Sep 17 00:00:00 2001 From: Ian Richardson Date: Fri, 26 Oct 2018 20:24:12 -0500 Subject: [PATCH 1/6] Convert hui-icon-element to TypeScript/LitElement and extract ElementClick mixin functions --- src/common/dom/handle-click.ts | 44 ++++++++++++ src/common/string/compute-tooltip.ts | 38 +++++++++++ .../lovelace/common/create-hui-element.js | 2 +- .../lovelace/elements/hui-icon-element.js | 53 --------------- .../lovelace/elements/hui-icon-element.ts | 67 ++++++++++++++++++ src/panels/lovelace/elements/types.ts | 6 ++ .../lovelace/mixins/element-click-mixin.js | 68 ++----------------- 7 files changed, 163 insertions(+), 115 deletions(-) create mode 100644 src/common/dom/handle-click.ts create mode 100644 src/common/string/compute-tooltip.ts delete mode 100644 src/panels/lovelace/elements/hui-icon-element.js create mode 100644 src/panels/lovelace/elements/hui-icon-element.ts diff --git a/src/common/dom/handle-click.ts b/src/common/dom/handle-click.ts new file mode 100644 index 0000000000..284644070a --- /dev/null +++ b/src/common/dom/handle-click.ts @@ -0,0 +1,44 @@ +import { HomeAssistant } from "../../types"; +import { LovelaceElementConfig } from "../../panels/lovelace/elements/types"; +import { fireEvent } from "../dom/fire_event.js"; +import toggleEntity from "../../../src/panels/lovelace/common/entity/toggle-entity"; + +export const handleClick = ( + node: HTMLElement, + hass: HomeAssistant, + config: LovelaceElementConfig, + hold: boolean +): void => { + let action = config.tap_action || "more-info"; + + if (hold && config.hold_action) { + action = config.hold_action; + } + + if (action === "none") { + return; + } + + switch (action) { + case "more-info": + fireEvent(node, "hass-more-info", { entityId: config.entity }); + break; + case "navigate": + // this.navigate(config.navigation_path); // TODO wait for balloob's navigate function + break; + case "toggle": + toggleEntity(hass, config.entity); + break; + case "call-service": { + if (config.service) { + const [domain, service] = config.service.split(".", 2); + const serviceData = Object.assign( + {}, + { entity_id: config.entity }, + config.service_data + ); + hass.callService(domain, service, serviceData); + } + } + } +}; diff --git a/src/common/string/compute-tooltip.ts b/src/common/string/compute-tooltip.ts new file mode 100644 index 0000000000..4346e97234 --- /dev/null +++ b/src/common/string/compute-tooltip.ts @@ -0,0 +1,38 @@ +import computeStateName from "../../common/entity/compute_state_name"; +import { HomeAssistant } from "../../types"; +import { LovelaceElementConfig } from "../../panels/lovelace/elements/types"; + +export const computeTooltip = ( + hass: HomeAssistant, + config: LovelaceElementConfig +): string => { + if (config.title) { + return config.title; + } + + let stateName = ""; + let tooltip: string; + + if (config.entity) { + stateName = + config.entity in hass.states + ? computeStateName(hass.states[config.entity]) + : config.entity; + } + + switch (config.tap_action) { + case "navigate": + tooltip = `Navigate to ${config.navigation_path}`; + break; + case "toggle": + tooltip = `Toggle ${stateName}`; + break; + case "call-service": + tooltip = `Call service ${config.service}`; + break; + default: + tooltip = `Show more-info: ${stateName}`; + } + + return tooltip; +}; diff --git a/src/panels/lovelace/common/create-hui-element.js b/src/panels/lovelace/common/create-hui-element.js index e74985ca13..8394c12115 100644 --- a/src/panels/lovelace/common/create-hui-element.js +++ b/src/panels/lovelace/common/create-hui-element.js @@ -1,4 +1,4 @@ -import "../elements/hui-icon-element.js"; +import "../elements/hui-icon-element"; import "../elements/hui-image-element.js"; import "../elements/hui-service-button-element.js"; import "../elements/hui-state-badge-element.js"; diff --git a/src/panels/lovelace/elements/hui-icon-element.js b/src/panels/lovelace/elements/hui-icon-element.js deleted file mode 100644 index 5eb2bb2631..0000000000 --- a/src/panels/lovelace/elements/hui-icon-element.js +++ /dev/null @@ -1,53 +0,0 @@ -import { html } from "@polymer/polymer/lib/utils/html-tag.js"; -import { PolymerElement } from "@polymer/polymer/polymer-element.js"; - -import "../../../components/ha-icon.js"; - -import ElementClickMixin from "../mixins/element-click-mixin.js"; -import { longPressBind } from "../common/directives/long-press-directive"; - -/* - * @appliesMixin ElementClickMixin - */ -class HuiIconElement extends ElementClickMixin(PolymerElement) { - static get template() { - return html` - - - `; - } - - static get properties() { - return { - hass: Object, - _config: Object, - }; - } - - ready() { - super.ready(); - longPressBind(this); - this.addEventListener("ha-click", () => - this.handleClick(this.hass, this._config, false) - ); - this.addEventListener("ha-hold", () => - this.handleClick(this.hass, this._config, true) - ); - } - - setConfig(config) { - if (!config || !config.icon) { - throw Error("Error in element configuration"); - } - - this._config = config; - } -} -customElements.define("hui-icon-element", HuiIconElement); diff --git a/src/panels/lovelace/elements/hui-icon-element.ts b/src/panels/lovelace/elements/hui-icon-element.ts new file mode 100644 index 0000000000..8fc4236c01 --- /dev/null +++ b/src/panels/lovelace/elements/hui-icon-element.ts @@ -0,0 +1,67 @@ +import { html, LitElement } from "@polymer/lit-element"; + +import "../../../components/ha-icon.js"; + +import { computeTooltip } from "../../../common/string/compute-tooltip"; +import { handleClick } from "../../../common/dom/handle-click"; +import { longPress } from "../common/directives/long-press-directive"; +import { hassLocalizeLitMixin } from "../../../mixins/lit-localize-mixin"; +import { LovelaceElement, LovelaceElementConfig } from "./types.js"; +import { HomeAssistant } from "../../../types.js"; + +interface Config extends LovelaceElementConfig { + icon: string; +} + +export class HuiIconElement extends hassLocalizeLitMixin(LitElement) + implements LovelaceElement { + public hass?: HomeAssistant; + private _config?: Config; + + static get properties() { + return { hass: {}, _config: {} }; + } + + public setConfig(config: Config) { + if (!config.icon) { + throw Error("Invalid Configuration: 'icon' required"); + } + + this._config = config; + } + + protected render() { + if (!this._config) { + return html``; + } + + return html` + ${this.renderStyle()} + + `; + } + + private renderStyle() { + return html` + + `; + } +} + +declare global { + interface HTMLElementTagNameMap { + "hui-icon-element": HuiIconElement; + } +} + +customElements.define("hui-icon-element", HuiIconElement); diff --git a/src/panels/lovelace/elements/types.ts b/src/panels/lovelace/elements/types.ts index 7b8b2c59cd..71407adf19 100644 --- a/src/panels/lovelace/elements/types.ts +++ b/src/panels/lovelace/elements/types.ts @@ -4,6 +4,12 @@ export interface LovelaceElementConfig { type: string; entity?: string; style: object; + tap_action?: string; + navigation_path?: string; + service?: string; + title?: string; + hold_action?: string; + service_data?: object; } export interface LovelaceElement extends HTMLElement { diff --git a/src/panels/lovelace/mixins/element-click-mixin.js b/src/panels/lovelace/mixins/element-click-mixin.js index 02a7cdb9fd..0832139f0f 100644 --- a/src/panels/lovelace/mixins/element-click-mixin.js +++ b/src/panels/lovelace/mixins/element-click-mixin.js @@ -1,70 +1,16 @@ import { dedupingMixin } from "@polymer/polymer/lib/utils/mixin.js"; -import toggleEntity from "../common/entity/toggle-entity.js"; -import NavigateMixin from "../../../mixins/navigate-mixin"; -import EventsMixin from "../../../mixins/events-mixin.js"; -import computeStateName from "../../../common/entity/compute_state_name"; +import { computeTooltip } from "../../../common/string/compute-tooltip"; +import { handleClick } from "../../../common/dom/handle-click"; -/* - * @polymerMixin - * @appliesMixin EventsMixin - * @appliesMixin NavigateMixin - */ export default dedupingMixin( (superClass) => - class extends NavigateMixin(EventsMixin(superClass)) { - handleClick(hass, config, hold) { - let action = config.tap_action || "more-info"; - if (hold) { - action = config.hold_action; - } - if (action === "none") return; - - switch (action) { - case "more-info": - this.fire("hass-more-info", { entityId: config.entity }); - break; - case "navigate": - this.navigate(config.navigation_path); - break; - case "toggle": - toggleEntity(hass, config.entity); - break; - case "call-service": { - const [domain, service] = config.service.split(".", 2); - const serviceData = Object.assign( - {}, - { entity_id: config.entity }, - config.service_data - ); - hass.callService(domain, service, serviceData); - } - } + class extends superClass { + handleClick(...args) { + handleClick(this, ...args); } - computeTooltip(hass, config) { - if (config.title) return config.title; - - const stateName = - config.entity in hass.states - ? computeStateName(hass.states[config.entity]) - : config.entity; - - let tooltip; - switch (config.tap_action) { - case "navigate": - tooltip = `Navigate to ${config.navigation_path}`; - break; - case "toggle": - tooltip = `Toggle ${stateName}`; - break; - case "call-service": - tooltip = `Call service ${config.service}`; - break; - default: - tooltip = `Show more-info: ${stateName}`; - } - - return tooltip; + computeTooltip(...args) { + computeTooltip(...args); } } ); From 5a7841e6bf7eed35e00a5593740a45b6eaf75ebd Mon Sep 17 00:00:00 2001 From: Ian Richardson Date: Fri, 26 Oct 2018 20:37:32 -0500 Subject: [PATCH 2/6] Pass correct node to handleClick --- src/panels/lovelace/elements/hui-icon-element.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/panels/lovelace/elements/hui-icon-element.ts b/src/panels/lovelace/elements/hui-icon-element.ts index 8fc4236c01..4cb714bb5c 100644 --- a/src/panels/lovelace/elements/hui-icon-element.ts +++ b/src/panels/lovelace/elements/hui-icon-element.ts @@ -40,8 +40,8 @@ export class HuiIconElement extends hassLocalizeLitMixin(LitElement) `; From 8afc3812b7fcf677d189a7df5a5f7f16b9d68960 Mon Sep 17 00:00:00 2001 From: Ian Richardson Date: Sat, 27 Oct 2018 16:40:43 -0500 Subject: [PATCH 3/6] Remove element-click refactor Was unable to get computeTooltip to work for non-converted elements. There are not many elements that use this so will just remove this mixin once conversion of all to TS has been completed. --- .../lovelace/mixins/element-click-mixin.js | 68 +++++++++++++++++-- 1 file changed, 61 insertions(+), 7 deletions(-) diff --git a/src/panels/lovelace/mixins/element-click-mixin.js b/src/panels/lovelace/mixins/element-click-mixin.js index 0832139f0f..02a7cdb9fd 100644 --- a/src/panels/lovelace/mixins/element-click-mixin.js +++ b/src/panels/lovelace/mixins/element-click-mixin.js @@ -1,16 +1,70 @@ import { dedupingMixin } from "@polymer/polymer/lib/utils/mixin.js"; -import { computeTooltip } from "../../../common/string/compute-tooltip"; -import { handleClick } from "../../../common/dom/handle-click"; +import toggleEntity from "../common/entity/toggle-entity.js"; +import NavigateMixin from "../../../mixins/navigate-mixin"; +import EventsMixin from "../../../mixins/events-mixin.js"; +import computeStateName from "../../../common/entity/compute_state_name"; +/* + * @polymerMixin + * @appliesMixin EventsMixin + * @appliesMixin NavigateMixin + */ export default dedupingMixin( (superClass) => - class extends superClass { - handleClick(...args) { - handleClick(this, ...args); + class extends NavigateMixin(EventsMixin(superClass)) { + handleClick(hass, config, hold) { + let action = config.tap_action || "more-info"; + if (hold) { + action = config.hold_action; + } + if (action === "none") return; + + switch (action) { + case "more-info": + this.fire("hass-more-info", { entityId: config.entity }); + break; + case "navigate": + this.navigate(config.navigation_path); + break; + case "toggle": + toggleEntity(hass, config.entity); + break; + case "call-service": { + const [domain, service] = config.service.split(".", 2); + const serviceData = Object.assign( + {}, + { entity_id: config.entity }, + config.service_data + ); + hass.callService(domain, service, serviceData); + } + } } - computeTooltip(...args) { - computeTooltip(...args); + computeTooltip(hass, config) { + if (config.title) return config.title; + + const stateName = + config.entity in hass.states + ? computeStateName(hass.states[config.entity]) + : config.entity; + + let tooltip; + switch (config.tap_action) { + case "navigate": + tooltip = `Navigate to ${config.navigation_path}`; + break; + case "toggle": + tooltip = `Toggle ${stateName}`; + break; + case "call-service": + tooltip = `Call service ${config.service}`; + break; + default: + tooltip = `Show more-info: ${stateName}`; + } + + return tooltip; } } ); From bf0eb798d9b0e4d6477d901329a9cfe9b63b4370 Mon Sep 17 00:00:00 2001 From: Ian Richardson Date: Sat, 27 Oct 2018 16:51:44 -0500 Subject: [PATCH 4/6] Implemented navigate function Fix linting error --- src/common/dom/handle-click.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/common/dom/handle-click.ts b/src/common/dom/handle-click.ts index 284644070a..99bd776524 100644 --- a/src/common/dom/handle-click.ts +++ b/src/common/dom/handle-click.ts @@ -1,6 +1,7 @@ import { HomeAssistant } from "../../types"; import { LovelaceElementConfig } from "../../panels/lovelace/elements/types"; import { fireEvent } from "../dom/fire_event.js"; +import { navigate } from "../../common/navigate"; import toggleEntity from "../../../src/panels/lovelace/common/entity/toggle-entity"; export const handleClick = ( @@ -24,7 +25,7 @@ export const handleClick = ( fireEvent(node, "hass-more-info", { entityId: config.entity }); break; case "navigate": - // this.navigate(config.navigation_path); // TODO wait for balloob's navigate function + navigate(node, config.navigation_path ? config.navigation_path : ""); break; case "toggle": toggleEntity(hass, config.entity); @@ -32,11 +33,10 @@ export const handleClick = ( case "call-service": { if (config.service) { const [domain, service] = config.service.split(".", 2); - const serviceData = Object.assign( - {}, - { entity_id: config.entity }, - config.service_data - ); + const serviceData = { + entity_id: config.entity, + ...config.service_data, + }; hass.callService(domain, service, serviceData); } } From 5617416932de3904cd9fb5ef4daabd1f0faf9457 Mon Sep 17 00:00:00 2001 From: Ian Richardson Date: Sat, 27 Oct 2018 16:54:27 -0500 Subject: [PATCH 5/6] cleaned up elementconfig type order --- src/panels/lovelace/elements/types.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/panels/lovelace/elements/types.ts b/src/panels/lovelace/elements/types.ts index 71407adf19..105ac3d2d9 100644 --- a/src/panels/lovelace/elements/types.ts +++ b/src/panels/lovelace/elements/types.ts @@ -2,14 +2,14 @@ import { HomeAssistant } from "../../../types"; export interface LovelaceElementConfig { type: string; - entity?: string; style: object; - tap_action?: string; + entity?: string; + hold_action?: string; navigation_path?: string; service?: string; - title?: string; - hold_action?: string; service_data?: object; + tap_action?: string; + title?: string; } export interface LovelaceElement extends HTMLElement { From d0acef3ecbb87165ea84878846da220ad94ea6ee Mon Sep 17 00:00:00 2001 From: Ian Richardson Date: Sat, 27 Oct 2018 18:01:07 -0500 Subject: [PATCH 6/6] Add return types --- src/panels/lovelace/elements/hui-icon-element.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/panels/lovelace/elements/hui-icon-element.ts b/src/panels/lovelace/elements/hui-icon-element.ts index 4cb714bb5c..00c291a0c2 100644 --- a/src/panels/lovelace/elements/hui-icon-element.ts +++ b/src/panels/lovelace/elements/hui-icon-element.ts @@ -8,6 +8,7 @@ import { longPress } from "../common/directives/long-press-directive"; import { hassLocalizeLitMixin } from "../../../mixins/lit-localize-mixin"; import { LovelaceElement, LovelaceElementConfig } from "./types.js"; import { HomeAssistant } from "../../../types.js"; +import { TemplateResult } from "lit-html"; interface Config extends LovelaceElementConfig { icon: string; @@ -22,7 +23,7 @@ export class HuiIconElement extends hassLocalizeLitMixin(LitElement) return { hass: {}, _config: {} }; } - public setConfig(config: Config) { + public setConfig(config: Config): void { if (!config.icon) { throw Error("Invalid Configuration: 'icon' required"); } @@ -30,7 +31,7 @@ export class HuiIconElement extends hassLocalizeLitMixin(LitElement) this._config = config; } - protected render() { + protected render(): TemplateResult { if (!this._config) { return html``; } @@ -47,7 +48,7 @@ export class HuiIconElement extends hassLocalizeLitMixin(LitElement) `; } - private renderStyle() { + private renderStyle(): TemplateResult { return html`