From 92b1dc9eed78893b002d3c6ffda991125faa948a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20W?= Date: Sun, 21 Apr 2019 20:50:44 +0200 Subject: [PATCH] Support for long press / hold action (#106) --- README.md | 5 +++-- button-card.js | 39 ++++++++++++++++++++++++++------------- 2 files changed, 29 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index b258616..ab20f9f 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ Lovelace Button card for your entities. ## Features - works with any toggleable entity -- 5 actions on tap `none`, `toggle`, `more-info`, `navigate` and `call-service` +- 6 available actions on **tap** and/or **hold**: `none`, `toggle`, `more-info`, `navigate`, `url` and `call-service` - state display (optional) - custom color (optional), or based on light rgb value - custom state definition with customizable color, icon and style (optional) @@ -46,7 +46,8 @@ Lovelace Button card for your entities. | `color_type` | string | `icon` | `icon` \| `card` \| `blank-card` \| `label-card` | Color either the background of the card or the icon inside the card. Setting this to `card` enable automatic `font` and `icon` color. This allows the text/icon to be readable even if the background color is bright/dark. Additional color-type options `blank-card` and `label-card` can be used for organisation (see examples). | | `color` | string | optional | `auto` \| `rgb(28, 128, 199)` | Color of the icon/card. `auto` sets the color based on the color of a light. By default, if the entity state is `off`, the color will be `var(--paper-item-icon-active-color)`, for `on` it will be `var(--paper-item-icon-color)` and for any other state it will be `var(--primary-text-color)`. You can redefine each colors using `state` | | `size` | string | `40%` | `20px` | Size of the icon. Can be percentage or pixel | -| `tap_action` | object | optional | See [Service](#Action) | Define the type of action, if undefined, toggle will be used. | +| `tap_action` | object | optional | See [Action](#Action) | Define the type of action on click, if undefined, toggle will be used. | +| `hold_action` | object | optional | See [Action](#Action) | Define the type of action on hold, if undefined, nothing happens. | | `name` | string | optional | `Air conditioner` | Define an optional text to show below the icon | | `show_name` | boolean | `true` | `true` \| `false` | Wether to show the name or not. Will pick entity_id's name by default, unless redefined in the `name` property or in any state `name` property | | `show_state` | boolean | `false` | `true` \| `false` | Show the state on the card. defaults to false if not set | diff --git a/button-card.js b/button-card.js index b6a492b..05b38c6 100644 --- a/button-card.js +++ b/button-card.js @@ -186,6 +186,18 @@ export default function domainIcon(domain, state) { `; } + longpress(element) { + customElements.whenDefined("long-press").then(() => { + const longpress = document.body.querySelector("long-press"); + longpress.bind(element); + }); + return element; + } + + firstUpdated() { + this.longpress(this.shadowRoot.querySelector('ha-card')); + } + render() { const state = this.__hass.states[this.config.entity]; const configState = this.testConfigState(state, this.config) @@ -387,7 +399,7 @@ export default function domainIcon(domain, state) { clickable = false } } else { - clickable = !(config.tap_action.action == 'none') + clickable = (config.tap_action.action != 'none' || config.hold_action && config.hold_action.action != 'none') } return clickable; } @@ -412,7 +424,7 @@ export default function domainIcon(domain, state) { const style = this.buildStyle(state, config, configState); const name = this.buildName(state, configState); return html` - +
${config.show_icon && icon ? html`` : ''} @@ -431,7 +443,7 @@ export default function domainIcon(domain, state) { const style = this.buildStyle(state, config, configState); const name = this.buildName(state, configState); return html` - +
${config.show_icon && icon ? html`` : ''} @@ -450,7 +462,7 @@ export default function domainIcon(domain, state) { const style = this.buildStyle(state, config, configState); const name = this.buildName(state, configState); return html` - +
${config.show_icon && icon ? html`` : ''} ${config.show_name && name ? html`
${name}
` : ''} @@ -482,15 +494,16 @@ export default function domainIcon(domain, state) { return 3; } - _handleTap(state, config) { + _handleTap(state, config, hold) { if (config.confirmation && !confirm("Confirm tap")) { return; } - if (config.tap_action) { + let action = hold ? config.hold_action : config.tap_action; + if (action) { let event; - switch (config.tap_action.action) { + switch (action.action) { case 'none': break; case 'more-info': @@ -503,8 +516,8 @@ export default function domainIcon(domain, state) { this.shadowRoot.dispatchEvent(event); break; case 'navigate': - if (!config.tap_action.navigation_path) break; - history.pushState(null, "", config.tap_action.navigation_path); + if (!action.navigation_path) break; + history.pushState(null, "", action.navigation_path); event = new Event('location-changed', { bubbles: true, cancelable: false, @@ -515,14 +528,14 @@ export default function domainIcon(domain, state) { break; case 'service': case 'call-service': - if (!config.tap_action.service) { + if (!action.service) { return; } - const [domain, service] = config.tap_action.service.split('.', 2); - this.hass.callService(domain, service, config.tap_action.service_data); + const [domain, service] = action.service.split('.', 2); + this.hass.callService(domain, service, action.service_data); break; case 'url': - config.tap_action.url && window.open(config.tap_action.url); + action.url && window.open(action.url); break; case 'toggle': default: