From a9f27a64a2102f256314af836c8672406d80d2f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20W?= Date: Fri, 26 Jul 2019 21:27:18 +0200 Subject: [PATCH] 2.0.0 (#202) * _template deprecation and custom fields support (#199) * Update custom-card-helpers * _template deprecated and custom_fields support * Update dependencies * Add npm audit fix to circleci * Styles support templating * *_action support templates * Some linting * Fixes #200 * Fixing template eval if input is a number * State values support templating * Documentation update * Doc formating issue * Bump major version --- .circleci/config.yml | 4 +- README.md | 331 +++++++++---- dist/button-card.js | 873 +++++++++++++++++---------------- examples/custom_fields_1.gif | Bin 0 -> 9627 bytes examples/custom_fields_2.png | Bin 0 -> 13222 bytes package-lock.json | 913 +++++++++++++++++++++++------------ package.json | 32 +- src/button-card.ts | 288 +++++++---- src/compute_state_display.ts | 2 +- src/helpers.ts | 13 +- src/long-press.ts | 2 + src/types.ts | 18 +- 12 files changed, 1522 insertions(+), 954 deletions(-) create mode 100644 examples/custom_fields_1.gif create mode 100644 examples/custom_fields_2.png diff --git a/.circleci/config.yml b/.circleci/config.yml index 967b473..f724fd4 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -17,9 +17,7 @@ jobs: - restore_cache: keys: - deps-{{ .Environment.CACHE_VERSION }}-{{ checksum "package-lock.json" }} - - deps-{{ .Environment.CACHE_VERSION }}- - - run: rm -rf ~/repo/node_modules/custom-card-helpers/.git - - run: npm install + - run: npm install && npm audit fix - save_cache: paths: diff --git a/README.md b/README.md index e77ebfe..2cc70aa 100644 --- a/README.md +++ b/README.md @@ -27,6 +27,7 @@ Lovelace Button card for your entities. - [Easy styling options](#easy-styling-options) - [Light entity color variable](#light-entity-color-variable) - [ADVANCED styling options](#advanced-styling-options) + - [Custom Fields](#custom-fields) - [Configuration Templates](#configuration-templates) - [General](#general) - [Merging state by id](#merging-state-by-id) @@ -78,85 +79,83 @@ Lovelace Button card for your entities. ### Main Options -| Name | Type | Default | Supported options | Description | +| Name | Type | Default | Supported options | Description | | -------------- | ----------- | ------------ | ------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `type` | string | **Required** | `custom:button-card` | Type of the card | +| `type` | string | **Required** | `custom:button-card` | Type of the card | | `template` | string | optional | any valid template from `button_card_templates` | See [configuration template](#Configuration-Templates) | -| `entity` | string | optional | `switch.ac` | entity_id | -| `icon` | string | optional | `mdi:air-conditioner` | Icon to display. Will be overriden by the icon defined in a state (if present). Defaults to the entity icon. Hide with `show_icon: false` | -| `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). | +| `entity` | string | optional | `switch.ac` | entity_id | +| `icon` | string | optional | `mdi:air-conditioner` | Icon to display. Will be overriden by the icon defined in a state (if present). Defaults to the entity icon. Hide with `show_icon: false`. Supports templates, see [templates](#templates) | +| `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` \| `auto-no-temperature` \| `rgb(28, 128, 199)` | Color of the icon/card. `auto` sets the color based on the color of a light including the temperature of the light. Setting this to `auto-no-temperature` will behave like home-assistant's default ignoring the temperature of the 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 | +| `size` | string | `40%` | `20px` | Size of the icon. Can be percentage or pixel | | `aspect_ratio` | string | optional | `1/1`, `2/1`, `1/1.5`, ... | See [here](#aspect-ratio) for an example. Aspect ratio of the card. `1/1` being a square. This will auto adapt to your screen size | | `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. | | `dbltap_action` | object | optional | See [Action](#Action) | Define the type of action on double click, if undefined, nothing happens. | -| `name` | string | optional | `Air conditioner` | Define an optional text to show below the icon | -| `label` | string | optional | Any string that you want | Display a label below the card. See [Layouts](#layout) for more information. | -| `label_template` | string | optional | | See [templates](#templates). Any javascript code which returns a string. Overrides `label` | -| `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 | -| `name_template` | string | optional | | See [templates](#templates). Any javascript code which returns a string. Overrides `name` | -| `show_state` | boolean | `false` | `true` \| `false` | Show the state on the card. defaults to false if not set | -| `show_icon` | boolean | `true` | `true` \| `false` | Wether to show the icon or not. Unless redefined in `icon`, uses the default entity icon from hass | +| `name` | string | optional | `Air conditioner` | Define an optional text to show below the icon. Supports templates, see [templates](#templates) | +| `label` | string | optional | Any string that you want | Display a label below the card. See [Layouts](#layout) for more information. Supports templates, see [templates](#templates) | +| `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 | +| `show_icon` | boolean | `true` | `true` \| `false` | Wether to show the icon or not. Unless redefined in `icon`, uses the default entity icon from hass | | `show_units` | boolean | `true` | `true` \| `false` | Display or hide the units of a sensor, if any. | -| `show_label` | boolean | `false` | `true` \| `false` | Display or hide the `label`/`label_template` | +| `show_label` | boolean | `false` | `true` \| `false` | Display or hide the `label` | | `show_last_changed` | boolean | `false` | `true` \| `false` | Replace the label altogether and display the the `last_changed` attribute in a nice way (eg: `12 minutes ago`) | | `show_entity_picture` | boolean | `false` | `true` \| `false` | Replace the icon by the entity picture (if any) or the custom picture (if any). Falls back to using the icon if both are undefined | -| `entity_picture` | string | optional | Can be any of `/local/*` file or a URL | Will override the icon/the default entity_picture with your own image. Best is to use a square image. You can also define one per state | -| `entity_picture_template` | string | optional | | See [templates](#templates). Any javascript code which returns a path to a file or a url as a string. Overrides `entity_picture` | +| `entity_picture` | string | optional | Can be any of `/local/*` file or a URL | Will override the icon/the default entity_picture with your own image. Best is to use a square image. You can also define one per state. Supports templates, see [templates](#templates) | | `units` | string | optional | `Kb/s`, `lux`, ... | Override or define the units to display after the state of the entity. If omitted, it's using the entity's units | -| `styles` | object list | optional | | See [styles](#styles) | -| `state` | object list | optional | See [State](#State) | State to use for the color, icon and style of the button. Multiple states can be defined | -| `confirmation` | string | optional | Free-form text | Show a confirmation popup on tap with defined text | +| `styles` | object list | optional | | See [styles](#styles) | +| `state` | object list | optional | See [State](#State) | State to use for the color, icon and style of the button. Multiple states can be defined | +| `confirmation` | string | optional | Free-form text | Show a confirmation popup on tap with defined text | | `lock` | boolean | `false` | `true` \| `false` | See [lock](#lock). This will display a normal button with a lock symbol in the corner. Clicking the button will make the lock go away and enable the button to be manoeuvred for five seconds | | `unlock_users` | string list | optional | A list of users | List of users allowed to unlock the button when `lock: true`. If not defined, everyone is allowed to unlock the button | | `layout` | string | optional | See [Layout](#Layout) | The layout of the button can be modified using this option | +| `custom_fields` | object | optional | See [Custom Fields](#Custom-Fields) | ### Action -| Name | Type | Default | Supported options | Description | +All the fields support templates, see [templates](#templates). + +| Name | Type | Default | Supported options | Description | | ----------------- | ------ | -------- | ---------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------- | -| `action` | string | `toggle` | `more-info`, `toggle`, `call-service`, `none`, `navigate`, `url` | Action to perform | +| `action` | string | `toggle` | `more-info`, `toggle`, `call-service`, `none`, `navigate`, `url` | Action to perform | | `entity` | string | none | Any entity id | **Only valid for `action: more-info`** to override the entity on which you want to call `more-info` | -| `navigation_path` | string | none | Eg: `/lovelace/0/` | Path to navigate to (e.g. `/lovelace/0/`) when action defined as navigate | -| `url` | string | none | Eg: `https://www.google.fr` | URL to open on click when action is `url`. The URL will open in a new tab | -| `service` | string | none | Any service | Service to call (e.g. `media_player.media_play_pause`) when `action` defined as `call-service` | -| `service_data` | object | none | Any service data | Service data to include (e.g. `entity_id: media_player.bedroom`) when `action` defined as `call-service`. If your `service_data` requires an `entity_id`, you can use the keywork `entity`, this will actually call the service on the entity defined in the main configuration of this card. Useful for [configuration templates](#configuration-templates) | +| `navigation_path` | string | none | Eg: `/lovelace/0/` | Path to navigate to (e.g. `/lovelace/0/`) when action defined as navigate | +| `url` | string | none | Eg: `https://www.google.fr` | URL to open on click when action is `url`. The URL will open in a new tab | +| `service` | string | none | Any service | Service to call (e.g. `media_player.media_play_pause`) when `action` defined as `call-service` | +| `service_data` | object | none | Any service data | Service data to include (e.g. `entity_id: media_player.bedroom`) when `action` defined as `call-service`. If your `service_data` requires an `entity_id`, you can use the keywork `entity`, this will actually call the service on the entity defined in the main configuration of this card. Useful for [configuration templates](#configuration-templates) | | `haptic` | string | none | `success`, `warning`, `failure`, `light`, `medium`, `heavy`, `selection` | Haptic feedback for the [Beta IOS App](http://home-assistant.io/ios/beta) | | `repeat` | number | none | eg: `500` | For a hold_action, you can optionally configure the action to repeat while the button is being held down (for example, to repeatedly increase the volume of a media player). Define the number of milliseconds between repeat actions here. | ### State -| Name | Type | Default | Supported options | Description | +| Name | Type | Default | Supported options | Description | | ---------- | ------------- | ------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------- | -| `operator` | string | `==` | See [Available Operators](#Available-operators) | The operator used to compare the current state against the `value` | -| `value` | string/number | **required** (unless operator is `default`) | If your entity is a sensor with numbers, use a number directly, else use a string | The value which will be compared against the current state of the entity | -| `name` | string | optional | Any string, `'Alert'`, `'My little switch is on'`, ... | if `show_name` is `true`, the name to display for this state. If undefined, uses the general config `name`, and if undefined uses the entity name | -| `name_template` | string | optional | | See [templates](#templates). Any javascript code which returns a string. Overrides `name` | -| `icon` | string | optional | `mdi:battery` | The icon to display for this state. Defaults to the entity icon. Hide with `show_icon: false` | -| `color` | string | `var(--primary-text-color)` | Any color, eg: `rgb(28, 128, 199)` or `blue` | The color of the icon (if `color_type: icon`) or the background (if `color_type: card`) | -| `styles` | string | optional | | See [styles](#styles) | -| `spin` | boolean | `false` | `true` \| `false` | Should the icon spin for this state? | -| `entity_picture` | string | optional | Can be any of `/local/*` file or a URL | Will override the icon/the default entity_picture with your own image for this state. Best is to use a square image | -| `entity_picture_template` | string | optional | | See [templates](#templates). Any javascript code which returns a path to a file or a url as a string. Overrides `entity_picture` | -| `label` | string | optional | Any string that you want | Display a label below the card. See [Layouts](#layout) for more information. | -| `label_template` | string | optional | | See [templates](#templates). Any javascript code which returns a string. Overrides `label` | +| `operator` | string | `==` | See [Available Operators](#Available-operators) | The operator used to compare the current state against the `value` | +| `value` | string/number | **required** (unless operator is `default`) | If your entity is a sensor with numbers, use a number directly, else use a string | The value which will be compared against the current state of the entity | +| `name` | string | optional | Any string, `'Alert'`, `'My little switch is on'`, ... | if `show_name` is `true`, the name to display for this state. If undefined, uses the general config `name`, and if undefined uses the entity name. Supports templates, see [templates](#templates) | +| `icon` | string | optional | `mdi:battery` | The icon to display for this state. Defaults to the entity icon. Hide with `show_icon: false`. Supports templates, see [templates](#templates) | +| `color` | string | `var(--primary-text-color)` | Any color, eg: `rgb(28, 128, 199)` or `blue` | The color of the icon (if `color_type: icon`) or the background (if `color_type: card`) | +| `styles` | string | optional | | See [styles](#styles) | +| `spin` | boolean | `false` | `true` \| `false` | Should the icon spin for this state? | +| `entity_picture` | string | optional | Can be any of `/local/*` file or a URL | Will override the icon/the default entity_picture with your own image for this state. Best is to use a square image. Supports templates, see [templates](#templates) | +| `label` | string | optional | Any string that you want | Display a label below the card. See [Layouts](#layout) for more information. Supports templates, see [templates](#templates) | ### Available operators The order of your elements in the `state` object matters. The first one which is `true` will match. +The `value` field for all operators except `regex` support templating, see [templates](#templates) -| Operator | `value` example | Description | +| Operator | `value` example | Description | | :-------: | --------------- | -------------------------------------------------------------------------------------------------------- | -| `<` | `5` | Current state is inferior to `value` | -| `<=` | `4` | Current state is inferior or equal to `value` | -| `==` | `42` or `'on'` | **This is the default if no operator is specified.** Current state is equal (`==` javascript) to `value` | -| `>=` | `32` | Current state is superior or equal to `value` | -| `>` | `12` | Current state is superior to `value` | -| `!=` | `'normal'` | Current state is not equal (`!=` javascript) to `value` | -| `regex` | `'^norm.*$'` | `value` regex applied to current state does match | +| `<` | `5` | Current state is inferior to `value` | +| `<=` | `4` | Current state is inferior or equal to `value` | +| `==` | `42` or `'on'` | **This is the default if no operator is specified.** Current state is equal (`==` javascript) to `value` | +| `>=` | `32` | Current state is superior or equal to `value` | +| `>` | `12` | Current state is superior to `value` | +| `!=` | `'normal'` | Current state is not equal (`!=` javascript) to `value` | +| `regex` | `'^norm.*$'` | `value` regex applied to current state does match | | `template` | | See [templates](#templates) for examples. `value` needs to be a javascript expression which returns a boolean. If the boolean is true, it will match this state | -| `default` | N/A | If nothing matches, this is used | +| `default` | N/A | If nothing matches, this is used | ### Layout @@ -178,22 +177,31 @@ Multiple values are possible, see the image below for examples: ### Templates -`label_template`, `name_template`, `entity_picture_template` supports templating as well as `value` for `state` when `operator: template` -* `label_template`: It will be interpreted as javascript code and the code should return a string. - `label_template` supports inline HTML, so you can do stuff like: - ```yaml - label_template: > - return 'Connection: ' - + (states['switch.connection'].state === 'on' - ? 'enabled' - : 'disabled') - + ' / ' - + (states['binary_sensor.status'].state === 'on' ? 'connected' : 'disconnected') - ``` - ![label-template-example](examples/label_template.png) -* `name_template`: It will be interpreted as javascript code and the code should return a string. -* `entity_picture_template`: It will be interpreted as javascript code and the code should return a path to a file or a url as a string. -* `value` for `state` when `operator: template`: It will be interpreted as javascript code and the code should return a boolean (`true` or `false`) +The template rendering uses a special format. All the fields where template is supported also support plain text. To activate the templating feature for such a field, you'll need to enclose the javascript function inside 3 square brakets: +`[[[ javascript function here ]]]` + +Don't forget to quote if it's on one line: +```yaml +name: '[[[ if (entity.state > 42) return "Above 42"; else return "Below 42" ]]]' +name: > + [[[ + if (entity.state > 42) + return "Above 42; + else + return "Below 42; + ]]] +``` + +Those are the configuration fields which support templating: +* `name` (Supports also HTML rendering): This needs to return a string +* `label` (Supports also HTML rendering): This needs to return a string +* `entity_picture`: This needs to return a path to a file or a url as a string. +* `icon`: This needs to return a string in the format `mdi:icon` +* All the styles in the style object: This needs to return a string +* All the value of the state object, appart when the operator is `regex` + * `operator: template`: The function for `value` needs to return a boolean + * Else: The function for `value` needs to return a string or a number +* All the `custom_fields` (Support also HTML rendering) Inside the javascript code, you'll have access to those variables: * `entity`: The current entity object, if the entity is defined in the card @@ -201,23 +209,12 @@ Inside the javascript code, you'll have access to those variables: * `user`: The user object (equivalent to `hass.user`) * `hass`: The complete `hass` object -The value shouldn't be enclosed in quotes: -```yaml -label_template: > - return states['light.mylight'].attributes.brightness -``` -or -```yaml -state: - - operator: template - value: > - return states['input_select.light_mode'].state === 'night_mode' -``` - -See [here](#templates-support) for some examples. +See [here](#templates-support) for some examples or [here](#custom-fields) for some crazy advanced stuff using templates! ### Styles +All the styles entries, support Templating, see [here](#custom-fields) for some examples. + #### Easy styling options For each element in the card, styles can be defined in 2 places: @@ -372,6 +369,149 @@ Some examples: - filter: grayscale(100%) ``` +### Custom Fields + +Custom fields support, using the `custom_fields` object, enables you to create your own fields on top of the pre-defined ones (name, state, label and icon). +This is an advanced feature which leverages (if you require it) the CSS Grid. + +Each custom field supports its own styling config, the name needs to match between both objects needs to match: +```yaml +- type: custom:button-card + [...] + custom_element: + test_element: My test element + styles: + custom_fields: + test_element: + - color: red + - font-size: 13px +``` + +Examples are better than a long text, so here you go: +* Placing an element wherever you want (that means bypassing the grid). Set the grid to `position: relative` and set the element to `position: absolute` + + ![custom_fields_1](examples/custom_fields_1.gif) + + ```yaml + - type: custom:button-card + icon: mdi:lightbulb + aspect_ratio: 1/1 + name: Nb lights on + styles: + grid: + - position: relative + custom_fields: + notification: + - background-color: > + [[[ + if (states['input_number.test'].state == 0) + return "green"; + return "red"; + ]]] + - border-radius: 50% + - position: absolute + - left: 60% + - top: 10% + - height: 20px + - width: 20px + - font-size: 8px + - line-height: 20px + custom_fields: + notification: > + [[[ return Math.floor(states['input_number.test'].state / 10) ]]] + ``` +* Or you can use the grid. Each element will have it's name positioned as the `grid-area`: + + ![custom_fields_2](examples/custom_fields_2.png) + + ```yaml + - type: custom:button-card + entity: 'sensor.raspi_temp' + icon: 'mdi:raspberry-pi' + aspect_ratio: 1/1 + name: HassOS + styles: + card: + - background-color: '#000044' + - border-radius: 10% + - padding: 10% + - color: ivory + - font-size: 10px + - text-shadow: 0px 0px 5px black + - text-transform: capitalize + grid: + - grid-template-areas: '"i temp" "n n" "cpu cpu" "ram ram" "sd sd"' + - grid-template-columns: 1fr 1fr + - grid-template-rows: 1fr min-content min-content min-content min-content + name: + - font-weight: bold + - font-size: 13px + - color: white + - align-self: middle + - justify-self: start + - padding-bottom: 4px + img_cell: + - justify-content: start + - align-items: start + - margin: none + icon: + - color: > + [[[ + if (entity.state < 60) return 'lime'; + if (entity.state >= 60 && entity.state < 80) return 'orange'; + else return 'red'; + ]]] + - width: 70% + - margin-top: -10% + custom_fields: + temp: + - align-self: start + - justify-self: end + cpu: + - padding-bottom: 2px + - align-self: middle + - justify-self: start + - --text-color-sensor: '[[[ if (states["sensor.raspi_cpu"].state > 80) return "red"; ]]]' + ram: + - padding-bottom: 2px + - align-self: middle + - justify-self: start + - --text-color-sensor: '[[[ if (states["sensor.raspi_ram"].state > 80) return "red"; ]]]' + sd: + - align-self: middle + - justify-self: start + - --text-color-sensor: '[[[ if (states["sensor.raspi_sd"].state > 80) return "red"; ]]]' + custom_fields: + temp: > + [[[ + return ` + ${entity.state}°C` + ]]] + cpu: > + [[[ + return ` + CPU: ${states['sensor.raspi_cpu'].state}%` + ]]] + ram: > + [[[ + return ` + RAM: ${states['sensor.raspi_ram'].state}%` + ]]] + sd: > + [[[ + return ` + SD: ${states['sensor.raspi_sd'].state}%` + ]]] + ``` + ### Configuration Templates #### General @@ -843,9 +983,11 @@ If you specify a width for the card, it has to be in `px`. All the cards without - type: "custom:button-card" color_type: icon entity: light.test_light - label_template: > - var bri = states['light.test_light'].attributes.brightness; - return 'Brightness: ' + (bri ? bri : '0') + '%'; + label: > + [[[ + var bri = states['light.test_light'].attributes.brightness; + return 'Brightness: ' + (bri ? bri : '0') + '%'; + ]]] show_label: true size: 15% styles: @@ -855,8 +997,10 @@ If you specify a width for the card, it has to be in `px`. All the cards without color_type: icon entity: light.test_light layout: icon_label - label_template: > - return 'Other State: ' + states['switch.skylight'].state; + label: > + [[[ + return 'Other State: ' + states['switch.skylight'].state; + ]]] show_label: true show_name: false styles: @@ -878,8 +1022,10 @@ Example with `template`: state: - operator: template value: > - return states['light.test_light'].attributes - && (states['light.test_light'].attributes.brightness <= 100) + [[[ + return states['light.test_light'].attributes + && (states['light.test_light'].attributes.brightness <= 100) + ]]] icon: mdi:alert - operator: default icon: mdi:lightbulb @@ -890,7 +1036,7 @@ Example with `template`: state: - operator: template value: > - return states['input_select.light_mode'].state === 'night_mode' + [[[ return states['input_select.light_mode'].state === 'night_mode' ]]] icon: mdi:weather-night label: Night Mode - operator: default @@ -906,9 +1052,11 @@ Example with `template`: - type: "custom:button-card" color_type: icon entity: light.test_light - label_template: > - var bri = states['light.test_light'].attributes.brightness; - return 'Brightness: ' + (bri ? bri : '0') + '%'; + label: > + [[[ + var bri = states['light.test_light'].attributes.brightness; + return 'Brightness: ' + (bri ? bri : '0') + '%'; + ]]] show_label: true show_state: true size: 10% @@ -945,8 +1093,8 @@ Example with `template`: color_type: icon entity: light.test_light layout: icon_label - label_template: > - return 'Other State: ' + states['switch.skylight'].state; + label: > + [[[ return 'Other State: ' + states['switch.skylight'].state; ]]] show_label: true show_name: false size: 100% @@ -1032,7 +1180,8 @@ Example with `template`: ## Credits -- [ciotlosm](https://github.com/ciotlosm) for the readme template and the awesome examples +- [ciotlosm](https://github.com/ciotlosm) for the readme template and some awesome examples +- [iantrich](https://github.com/iantrich), [LbDab](https://github.com/lbdab) and [jimz011](https://github.com/jimz011) for the inspiration and the awesome templates and cards you've created. [commits-shield]: https://img.shields.io/github/commit-activity/y/custom-cards/button-card.svg?style=for-the-badge [commits]: https://github.com/custom-cards/button-card/commits/master diff --git a/dist/button-card.js b/dist/button-card.js index f2bd2ba..fcd1e48 100644 --- a/dist/button-card.js +++ b/dist/button-card.js @@ -1,7 +1,7 @@ function t(t, e, n, i) { - var r, - s = arguments.length, - a = s < 3 ? e : null === i ? i = Object.getOwnPropertyDescriptor(e, n) : i;if ("object" == typeof Reflect && "function" == typeof Reflect.decorate) a = Reflect.decorate(t, e, n, i);else for (var o = t.length - 1; o >= 0; o--) (r = t[o]) && (a = (s < 3 ? r(a) : s > 3 ? r(e, n, a) : r(e, n)) || a);return s > 3 && a && Object.defineProperty(e, n, a), a; + var s, + r = arguments.length, + a = r < 3 ? e : null === i ? i = Object.getOwnPropertyDescriptor(e, n) : i;if ("object" == typeof Reflect && "function" == typeof Reflect.decorate) a = Reflect.decorate(t, e, n, i);else for (var o = t.length - 1; o >= 0; o--) (s = t[o]) && (a = (r < 3 ? s(a) : r > 3 ? s(e, n, a) : s(e, n)) || a);return r > 3 && a && Object.defineProperty(e, n, a), a; /** * @license * Copyright (c) 2017 The Polymer Project Authors. All rights reserved. @@ -20,50 +20,60 @@ function t(t, e, n, i) { const i = t(...n);return e.set(i, !0), i; }, i = t => "function" == typeof t && e.has(t), - r = void 0 !== window.customElements && void 0 !== window.customElements.polyfillWrapFlushCallback, - s = (t, e, n = null) => { - let i = e;for (; i !== n;) { - const e = i.nextSibling;t.removeChild(i), i = e; + s = void 0 !== window.customElements && void 0 !== window.customElements.polyfillWrapFlushCallback, + r = (t, e, n = null) => { + for (; e !== n;) { + const n = e.nextSibling;t.removeChild(e), e = n; } }, a = {}, o = {}, - l = `{{lit-${String(Math.random()).slice(2)}}}`, - c = `\x3c!--${l}--\x3e`, - h = new RegExp(`${l}|${c}`), + c = `{{lit-${String(Math.random()).slice(2)}}}`, + l = `\x3c!--${c}--\x3e`, + h = new RegExp(`${c}|${l}`), d = "$lit$";class u { constructor(t, e) { - this.parts = [], this.element = e;let n = -1, - i = 0;const r = [], - s = e => { - const a = e.content, - o = document.createTreeWalker(a, 133, null, !1);let c = 0;for (; o.nextNode();) { - n++;const e = o.currentNode;if (1 === e.nodeType) { - if (e.hasAttributes()) { - const r = e.attributes;let s = 0;for (let t = 0; t < r.length; t++) r[t].value.indexOf(l) >= 0 && s++;for (; s-- > 0;) { - const r = t.strings[i], - s = m.exec(r)[2], - a = s.toLowerCase() + d, - o = e.getAttribute(a).split(h);this.parts.push({ type: "attribute", index: n, name: s, strings: o }), e.removeAttribute(a), i += o.length - 1; + this.parts = [], this.element = e;const n = [], + i = [], + s = document.createTreeWalker(e.content, 133, null, !1);let r = 0, + a = -1, + o = 0;const { strings: l, values: { length: u } } = t;for (; o < u;) { + const t = s.nextNode();if (null !== t) { + if (a++, 1 === t.nodeType) { + if (t.hasAttributes()) { + const e = t.attributes, + { length: n } = e;let i = 0;for (let t = 0; t < n; t++) p(e[t].name, d) && i++;for (; i-- > 0;) { + const e = l[o], + n = g.exec(e)[2], + i = n.toLowerCase() + d, + s = t.getAttribute(i);t.removeAttribute(i);const r = s.split(h);this.parts.push({ type: "attribute", index: a, name: n, strings: r }), o += r.length - 1; } - }"TEMPLATE" === e.tagName && s(e); - } else if (3 === e.nodeType) { - const t = e.data;if (t.indexOf(l) >= 0) { - const s = e.parentNode, - a = t.split(h), - o = a.length - 1;for (let t = 0; t < o; t++) s.insertBefore("" === a[t] ? f() : document.createTextNode(a[t]), e), this.parts.push({ type: "node", index: ++n });"" === a[o] ? (s.insertBefore(f(), e), r.push(e)) : e.data = a[o], i += o; + }"TEMPLATE" === t.tagName && (i.push(t), s.currentNode = t.content); + } else if (3 === t.nodeType) { + const e = t.data;if (e.indexOf(c) >= 0) { + const i = t.parentNode, + s = e.split(h), + r = s.length - 1;for (let e = 0; e < r; e++) { + let n, + r = s[e];if ("" === r) n = m();else { + const t = g.exec(r);null !== t && p(t[2], d) && (r = r.slice(0, t.index) + t[1] + t[2].slice(0, -d.length) + t[3]), n = document.createTextNode(r); + }i.insertBefore(n, t), this.parts.push({ type: "node", index: ++a }); + }"" === s[r] ? (i.insertBefore(m(), t), n.push(t)) : t.data = s[r], o += r; } - } else if (8 === e.nodeType) if (e.data === l) { - const t = e.parentNode;null !== e.previousSibling && n !== c || (n++, t.insertBefore(f(), e)), c = n, this.parts.push({ type: "node", index: n }), null === e.nextSibling ? e.data = "" : (r.push(e), n--), i++; + } else if (8 === t.nodeType) if (t.data === c) { + const e = t.parentNode;null !== t.previousSibling && a !== r || (a++, e.insertBefore(m(), t)), r = a, this.parts.push({ type: "node", index: a }), null === t.nextSibling ? t.data = "" : (n.push(t), a--), o++; } else { - let t = -1;for (; -1 !== (t = e.data.indexOf(l, t + 1));) this.parts.push({ type: "node", index: -1 }); + let e = -1;for (; -1 !== (e = t.data.indexOf(c, e + 1));) this.parts.push({ type: "node", index: -1 }), o++; } - } - };s(e);for (const t of r) t.parentNode.removeChild(t); + } else s.currentNode = i.pop(); + }for (const t of n) t.parentNode.removeChild(t); } -}const p = t => -1 !== t.index, - f = () => document.createComment(""), - m = /([ \x09\x0a\x0c\x0d])([^\0-\x1F\x7F-\x9F \x09\x0a\x0c\x0d"'>=\/]+)([ \x09\x0a\x0c\x0d]*=[ \x09\x0a\x0c\x0d]*(?:[^ \x09\x0a\x0c\x0d"'`<>=]*|"[^"]*|'[^']*))$/; +}const p = (t, e) => { + const n = t.length - e.length;return n >= 0 && t.slice(n) === e; +}, + f = t => -1 !== t.index, + m = () => document.createComment(""), + g = /([ \x09\x0a\x0c\x0d])([^\0-\x1F\x7F-\x9F "'>=\/]+)([ \x09\x0a\x0c\x0d]*=[ \x09\x0a\x0c\x0d]*(?:[^ \x09\x0a\x0c\x0d"'`<>=]*|"[^"]*|'[^']*))$/; /** * @license * Copyright (c) 2017 The Polymer Project Authors. All rights reserved. @@ -77,25 +87,23 @@ function t(t, e, n, i) { * subject to an additional IP rights grant found at * http://polymer.github.io/PATENTS.txt */ -class g { +class b { constructor(t, e, n) { - this._parts = [], this.template = t, this.processor = e, this.options = n; + this.__parts = [], this.template = t, this.processor = e, this.options = n; }update(t) { - let e = 0;for (const n of this._parts) void 0 !== n && n.setValue(t[e]), e++;for (const t of this._parts) void 0 !== t && t.commit(); + let e = 0;for (const n of this.__parts) void 0 !== n && n.setValue(t[e]), e++;for (const t of this.__parts) void 0 !== t && t.commit(); }_clone() { - const t = r ? this.template.element.content.cloneNode(!0) : document.importNode(this.template.element.content, !0), - e = this.template.parts;let n = 0, - i = 0;const s = t => { - const r = document.createTreeWalker(t, 133, null, !1);let a = r.nextNode();for (; n < e.length && null !== a;) { - const t = e[n];if (p(t)) { - if (i === t.index) { - if ("node" === t.type) { - const t = this.processor.handleTextExpression(this.options);t.insertAfterNode(a.previousSibling), this._parts.push(t); - } else this._parts.push(...this.processor.handleAttributeExpressions(a, t.name, t.strings, this.options));n++; - } else i++, "TEMPLATE" === a.nodeName && s(a.content), a = r.nextNode(); - } else this._parts.push(void 0), n++; - } - };return s(t), r && (document.adoptNode(t), customElements.upgrade(t)), t; + const t = s ? this.template.element.content.cloneNode(!0) : document.importNode(this.template.element.content, !0), + e = [], + n = this.template.parts, + i = document.createTreeWalker(t, 133, null, !1);let r, + a = 0, + o = 0, + c = i.nextNode();for (; a < n.length;) if (r = n[a], f(r)) { + for (; o < r.index;) o++, "TEMPLATE" === c.nodeName && (e.push(c), i.currentNode = c.content), null === (c = i.nextNode()) && (i.currentNode = e.pop(), c = i.nextNode());if ("node" === r.type) { + const t = this.processor.handleTextExpression(this.options);t.insertAfterNode(c.previousSibling), this.__parts.push(t); + } else this.__parts.push(...this.processor.handleAttributeExpressions(c, r.name, r.strings, this.options));a++; + } else this.__parts.push(void 0), a++;return s && (document.adoptNode(t), customElements.upgrade(t)), t; } } /** @@ -110,14 +118,15 @@ class g { * Code distributed by Google as part of the polymer project is also * subject to an additional IP rights grant found at * http://polymer.github.io/PATENTS.txt - */class b { + */class _ { constructor(t, e, n, i) { this.strings = t, this.values = e, this.type = n, this.processor = i; }getHTML() { - const t = this.strings.length - 1;let e = "";for (let n = 0; n < t; n++) { - const t = this.strings[n], - i = m.exec(t);e += i ? t.substr(0, i.index) + i[1] + i[2] + d + i[3] + l : t + c; - }return e + this.strings[t]; + const t = this.strings.length - 1;let e = "", + n = !1;for (let i = 0; i < t; i++) { + const t = this.strings[i], + s = t.lastIndexOf("\x3c!--");n = (s > -1 || n) && -1 === t.indexOf("--\x3e", s + 1);const r = g.exec(t);e += null === r ? t + (n ? c : l) : t.substr(0, r.index) + r[1] + r[2] + d + r[3] + c; + }return e += this.strings[t]; }getTemplateElement() { const t = document.createElement("template");return t.innerHTML = this.getHTML(), t; } @@ -134,22 +143,23 @@ class g { * Code distributed by Google as part of the polymer project is also * subject to an additional IP rights grant found at * http://polymer.github.io/PATENTS.txt - */const y = t => null === t || !("object" == typeof t || "function" == typeof t);class v { + */const y = t => null === t || !("object" == typeof t || "function" == typeof t), + v = t => Array.isArray(t) || !(!t || !t[Symbol.iterator]);class w { constructor(t, e, n) { this.dirty = !0, this.element = t, this.name = e, this.strings = n, this.parts = [];for (let t = 0; t < n.length - 1; t++) this.parts[t] = this._createPart(); }_createPart() { - return new _(this); + return new S(this); }_getValue() { const t = this.strings, e = t.length - 1;let n = "";for (let i = 0; i < e; i++) { n += t[i];const e = this.parts[i];if (void 0 !== e) { - const t = e.value;if (null != t && (Array.isArray(t) || "string" != typeof t && t[Symbol.iterator])) for (const e of t) n += "string" == typeof e ? e : String(e);else n += "string" == typeof t ? t : String(t); + const t = e.value;if (y(t) || !v(t)) n += "string" == typeof t ? t : String(t);else for (const e of t) n += "string" == typeof e ? e : String(e); } }return n += t[e]; }commit() { this.dirty && (this.dirty = !1, this.element.setAttribute(this.name, this._getValue())); } -}class _ { +}class S { constructor(t) { this.value = void 0, this.committer = t; }setValue(t) { @@ -159,80 +169,81 @@ class g { const t = this.value;this.value = a, t(this); }this.value !== a && this.committer.commit(); } -}class w { +}class x { constructor(t) { - this.value = void 0, this._pendingValue = void 0, this.options = t; + this.value = void 0, this.__pendingValue = void 0, this.options = t; }appendInto(t) { - this.startNode = t.appendChild(f()), this.endNode = t.appendChild(f()); + this.startNode = t.appendChild(m()), this.endNode = t.appendChild(m()); }insertAfterNode(t) { this.startNode = t, this.endNode = t.nextSibling; }appendIntoPart(t) { - t._insert(this.startNode = f()), t._insert(this.endNode = f()); + t.__insert(this.startNode = m()), t.__insert(this.endNode = m()); }insertAfterPart(t) { - t._insert(this.startNode = f()), this.endNode = t.endNode, t.endNode = this.startNode; + t.__insert(this.startNode = m()), this.endNode = t.endNode, t.endNode = this.startNode; }setValue(t) { - this._pendingValue = t; + this.__pendingValue = t; }commit() { - for (; i(this._pendingValue);) { - const t = this._pendingValue;this._pendingValue = a, t(this); - }const t = this._pendingValue;t !== a && (y(t) ? t !== this.value && this._commitText(t) : t instanceof b ? this._commitTemplateResult(t) : t instanceof Node ? this._commitNode(t) : Array.isArray(t) || t[Symbol.iterator] ? this._commitIterable(t) : t === o ? (this.value = o, this.clear()) : this._commitText(t)); - }_insert(t) { + for (; i(this.__pendingValue);) { + const t = this.__pendingValue;this.__pendingValue = a, t(this); + }const t = this.__pendingValue;t !== a && (y(t) ? t !== this.value && this.__commitText(t) : t instanceof _ ? this.__commitTemplateResult(t) : t instanceof Node ? this.__commitNode(t) : v(t) ? this.__commitIterable(t) : t === o ? (this.value = o, this.clear()) : this.__commitText(t)); + }__insert(t) { this.endNode.parentNode.insertBefore(t, this.endNode); - }_commitNode(t) { - this.value !== t && (this.clear(), this._insert(t), this.value = t); - }_commitText(t) { - const e = this.startNode.nextSibling;t = null == t ? "" : t, e === this.endNode.previousSibling && 3 === e.nodeType ? e.data = t : this._commitNode(document.createTextNode("string" == typeof t ? t : String(t))), this.value = t; - }_commitTemplateResult(t) { - const e = this.options.templateFactory(t);if (this.value instanceof g && this.value.template === e) this.value.update(t.values);else { - const n = new g(e, t.processor, this.options), - i = n._clone();n.update(t.values), this._commitNode(i), this.value = n; + }__commitNode(t) { + this.value !== t && (this.clear(), this.__insert(t), this.value = t); + }__commitText(t) { + const e = this.startNode.nextSibling, + n = "string" == typeof (t = null == t ? "" : t) ? t : String(t);e === this.endNode.previousSibling && 3 === e.nodeType ? e.data = n : this.__commitNode(document.createTextNode(n)), this.value = t; + }__commitTemplateResult(t) { + const e = this.options.templateFactory(t);if (this.value instanceof b && this.value.template === e) this.value.update(t.values);else { + const n = new b(e, t.processor, this.options), + i = n._clone();n.update(t.values), this.__commitNode(i), this.value = n; } - }_commitIterable(t) { + }__commitIterable(t) { Array.isArray(this.value) || (this.value = [], this.clear());const e = this.value;let n, - i = 0;for (const r of t) void 0 === (n = e[i]) && (n = new w(this.options), e.push(n), 0 === i ? n.appendIntoPart(this) : n.insertAfterPart(e[i - 1])), n.setValue(r), n.commit(), i++;i < e.length && (e.length = i, this.clear(n && n.endNode)); + i = 0;for (const s of t) void 0 === (n = e[i]) && (n = new x(this.options), e.push(n), 0 === i ? n.appendIntoPart(this) : n.insertAfterPart(e[i - 1])), n.setValue(s), n.commit(), i++;i < e.length && (e.length = i, this.clear(n && n.endNode)); }clear(t = this.startNode) { - s(this.startNode.parentNode, t.nextSibling, this.endNode); + r(this.startNode.parentNode, t.nextSibling, this.endNode); } -}class S { +}class k { constructor(t, e, n) { - if (this.value = void 0, this._pendingValue = void 0, 2 !== n.length || "" !== n[0] || "" !== n[1]) throw new Error("Boolean attributes can only contain a single expression");this.element = t, this.name = e, this.strings = n; + if (this.value = void 0, this.__pendingValue = void 0, 2 !== n.length || "" !== n[0] || "" !== n[1]) throw new Error("Boolean attributes can only contain a single expression");this.element = t, this.name = e, this.strings = n; }setValue(t) { - this._pendingValue = t; + this.__pendingValue = t; }commit() { - for (; i(this._pendingValue);) { - const t = this._pendingValue;this._pendingValue = a, t(this); - }if (this._pendingValue === a) return;const t = !!this._pendingValue;this.value !== t && (t ? this.element.setAttribute(this.name, "") : this.element.removeAttribute(this.name)), this.value = t, this._pendingValue = a; + for (; i(this.__pendingValue);) { + const t = this.__pendingValue;this.__pendingValue = a, t(this); + }if (this.__pendingValue === a) return;const t = !!this.__pendingValue;this.value !== t && (t ? this.element.setAttribute(this.name, "") : this.element.removeAttribute(this.name), this.value = t), this.__pendingValue = a; } -}class x extends v { +}class M extends w { constructor(t, e, n) { super(t, e, n), this.single = 2 === n.length && "" === n[0] && "" === n[1]; }_createPart() { - return new k(this); + return new E(this); }_getValue() { return this.single ? this.parts[0].value : super._getValue(); }commit() { this.dirty && (this.dirty = !1, this.element[this.name] = this._getValue()); } -}class k extends _ {}let M = !1;try { +}class E extends S {}let C = !1;try { const t = { get capture() { - return M = !0, !1; + return C = !0, !1; } };window.addEventListener("test", t, t), window.removeEventListener("test", t, t); -} catch (t) {}class C { +} catch (t) {}class T { constructor(t, e, n) { - this.value = void 0, this._pendingValue = void 0, this.element = t, this.eventName = e, this.eventContext = n, this._boundHandleEvent = t => this.handleEvent(t); + this.value = void 0, this.__pendingValue = void 0, this.element = t, this.eventName = e, this.eventContext = n, this.__boundHandleEvent = t => this.handleEvent(t); }setValue(t) { - this._pendingValue = t; + this.__pendingValue = t; }commit() { - for (; i(this._pendingValue);) { - const t = this._pendingValue;this._pendingValue = a, t(this); - }if (this._pendingValue === a) return;const t = this._pendingValue, + for (; i(this.__pendingValue);) { + const t = this.__pendingValue;this.__pendingValue = a, t(this); + }if (this.__pendingValue === a) return;const t = this.__pendingValue, e = this.value, n = null == t || null != e && (t.capture !== e.capture || t.once !== e.once || t.passive !== e.passive), - r = null != t && (null == e || n);n && this.element.removeEventListener(this.eventName, this._boundHandleEvent, this._options), r && (this._options = E(t), this.element.addEventListener(this.eventName, this._boundHandleEvent, this._options)), this.value = t, this._pendingValue = a; + s = null != t && (null == e || n);n && this.element.removeEventListener(this.eventName, this.__boundHandleEvent, this.__options), s && (this.__options = P(t), this.element.addEventListener(this.eventName, this.__boundHandleEvent, this.__options)), this.value = t, this.__pendingValue = a; }handleEvent(t) { "function" == typeof this.value ? this.value.call(this.eventContext || this.element, t) : this.value.handleEvent(t); } -}const E = t => t && (M ? { capture: t.capture, passive: t.passive, once: t.once } : t.capture); +}const P = t => t && (C ? { capture: t.capture, passive: t.passive, once: t.once } : t.capture); /** * @license * Copyright (c) 2017 The Polymer Project Authors. All rights reserved. @@ -245,11 +256,11 @@ class g { * Code distributed by Google as part of the polymer project is also * subject to an additional IP rights grant found at * http://polymer.github.io/PATENTS.txt - */const P = new class { + */const N = new class { handleAttributeExpressions(t, e, n, i) { - const r = e[0];return "." === r ? new x(t, e.slice(1), n).parts : "@" === r ? [new C(t, e.slice(1), i.eventContext)] : "?" === r ? [new S(t, e.slice(1), n)] : new v(t, e, n).parts; + const s = e[0];return "." === s ? new M(t, e.slice(1), n).parts : "@" === s ? [new T(t, e.slice(1), i.eventContext)] : "?" === s ? [new k(t, e.slice(1), n)] : new w(t, e, n).parts; }handleTextExpression(t) { - return new w(t); + return new x(t); } }(); /** @@ -265,9 +276,9 @@ class g { * subject to an additional IP rights grant found at * http://polymer.github.io/PATENTS.txt */function A(t) { - let e = T.get(t.type);void 0 === e && (e = { stringsArray: new WeakMap(), keyString: new Map() }, T.set(t.type, e));let n = e.stringsArray.get(t.strings);if (void 0 !== n) return n;const i = t.strings.join(l);return void 0 === (n = e.keyString.get(i)) && (n = new u(t, t.getTemplateElement()), e.keyString.set(i, n)), e.stringsArray.set(t.strings, n), n; -}const T = new Map(), - N = new WeakMap(); + let e = O.get(t.type);void 0 === e && (e = { stringsArray: new WeakMap(), keyString: new Map() }, O.set(t.type, e));let n = e.stringsArray.get(t.strings);if (void 0 !== n) return n;const i = t.strings.join(c);return void 0 === (n = e.keyString.get(i)) && (n = new u(t, t.getTemplateElement()), e.keyString.set(i, n)), e.stringsArray.set(t.strings, n), n; +}const O = new Map(), + R = new WeakMap(); /** * @license * Copyright (c) 2017 The Polymer Project Authors. All rights reserved. @@ -294,8 +305,8 @@ class g { * subject to an additional IP rights grant found at * http://polymer.github.io/PATENTS.txt */ -(window.litHtmlVersions || (window.litHtmlVersions = [])).push("1.0.0");const R = (t, ...e) => new b(t, e, "html", P), - $ = 133; +(window.litHtmlVersions || (window.litHtmlVersions = [])).push("1.1.1");const $ = (t, ...e) => new _(t, e, "html", N), + H = 133; /** * @license * Copyright (c) 2017 The Polymer Project Authors. All rights reserved. @@ -308,20 +319,20 @@ class g { * Code distributed by Google as part of the polymer project is also * subject to an additional IP rights grant found at * http://polymer.github.io/PATENTS.txt - */function H(t, e) { + */function D(t, e) { const { element: { content: n }, parts: i } = t, - r = document.createTreeWalker(n, $, null, !1);let s = O(i), - a = i[s], + s = document.createTreeWalker(n, H, null, !1);let r = L(i), + a = i[r], o = -1, - l = 0;const c = [];let h = null;for (; r.nextNode();) { - o++;const t = r.currentNode;for (t.previousSibling === h && (h = null), e.has(t) && (c.push(t), null === h && (h = t)), null !== h && l++; void 0 !== a && a.index === o;) a.index = null !== h ? -1 : a.index - l, a = i[s = O(i, s)]; - }c.forEach(t => t.parentNode.removeChild(t)); -}const D = t => { - let e = 11 === t.nodeType ? 0 : 1;const n = document.createTreeWalker(t, $, null, !1);for (; n.nextNode();) e++;return e; + c = 0;const l = [];let h = null;for (; s.nextNode();) { + o++;const t = s.currentNode;for (t.previousSibling === h && (h = null), e.has(t) && (l.push(t), null === h && (h = t)), null !== h && c++; void 0 !== a && a.index === o;) a.index = null !== h ? -1 : a.index - c, a = i[r = L(i, r)]; + }l.forEach(t => t.parentNode.removeChild(t)); +}const j = t => { + let e = 11 === t.nodeType ? 0 : 1;const n = document.createTreeWalker(t, H, null, !1);for (; n.nextNode();) e++;return e; }, - O = (t, e = -1) => { + L = (t, e = -1) => { for (let n = e + 1; n < t.length; n++) { - const e = t[n];if (p(e)) return n; + const e = t[n];if (f(e)) return n; }return -1; }; /** @@ -337,37 +348,37 @@ class g { * subject to an additional IP rights grant found at * http://polymer.github.io/PATENTS.txt */ -const L = (t, e) => `${t}--${e}`;let V = !0;void 0 === window.ShadyCSS ? V = !1 : void 0 === window.ShadyCSS.prepareTemplateDom && (console.warn("Incompatible ShadyCSS version detected.Please update to at least @webcomponents/webcomponentsjs@2.0.2 and@webcomponents/shadycss@1.3.1."), V = !1);const j = t => e => { - const n = L(e.type, t);let i = T.get(n);void 0 === i && (i = { stringsArray: new WeakMap(), keyString: new Map() }, T.set(n, i));let r = i.stringsArray.get(e.strings);if (void 0 !== r) return r;const s = e.strings.join(l);if (void 0 === (r = i.keyString.get(s))) { - const n = e.getTemplateElement();V && window.ShadyCSS.prepareTemplateDom(n, t), r = new u(e, n), i.keyString.set(s, r); - }return i.stringsArray.set(e.strings, r), r; +const V = (t, e) => `${t}--${e}`;let I = !0;void 0 === window.ShadyCSS ? I = !1 : void 0 === window.ShadyCSS.prepareTemplateDom && (console.warn("Incompatible ShadyCSS version detected. Please update to at least @webcomponents/webcomponentsjs@2.0.2 and @webcomponents/shadycss@1.3.1."), I = !1);const F = t => e => { + const n = V(e.type, t);let i = O.get(n);void 0 === i && (i = { stringsArray: new WeakMap(), keyString: new Map() }, O.set(n, i));let s = i.stringsArray.get(e.strings);if (void 0 !== s) return s;const r = e.strings.join(c);if (void 0 === (s = i.keyString.get(r))) { + const n = e.getTemplateElement();I && window.ShadyCSS.prepareTemplateDom(n, t), s = new u(e, n), i.keyString.set(r, s); + }return i.stringsArray.set(e.strings, s), s; }, - I = ["html", "svg"], - F = new Set(), - Y = (t, e, n) => { - F.add(n);const i = t.querySelectorAll("style");if (0 === i.length) return void window.ShadyCSS.prepareTemplateStyles(e.element, n);const r = document.createElement("style");for (let t = 0; t < i.length; t++) { - const e = i[t];e.parentNode.removeChild(e), r.textContent += e.textContent; - }if ((t => { - I.forEach(e => { - const n = T.get(L(e, t));void 0 !== n && n.keyString.forEach(t => { + Y = ["html", "svg"], + z = new Set(), + q = (t, e, n) => { + z.add(t);const i = n ? n.element : document.createElement("template"), + s = e.querySelectorAll("style"), + { length: r } = s;if (0 === r) return void window.ShadyCSS.prepareTemplateStyles(i, t);const a = document.createElement("style");for (let t = 0; t < r; t++) { + const e = s[t];e.parentNode.removeChild(e), a.textContent += e.textContent; + }(t => { + Y.forEach(e => { + const n = O.get(V(e, t));void 0 !== n && n.keyString.forEach(t => { const { element: { content: e } } = t, n = new Set();Array.from(e.querySelectorAll("style")).forEach(t => { n.add(t); - }), H(t, n); + }), D(t, n); }); }); - })(n), function (t, e, n = null) { - const { element: { content: i }, parts: r } = t;if (null == n) return void i.appendChild(e);const s = document.createTreeWalker(i, $, null, !1);let a = O(r), + })(t);const o = i.content;n ? function (t, e, n = null) { + const { element: { content: i }, parts: s } = t;if (null == n) return void i.appendChild(e);const r = document.createTreeWalker(i, H, null, !1);let a = L(s), o = 0, - l = -1;for (; s.nextNode();) for (l++, s.currentNode === n && (o = D(e), n.parentNode.insertBefore(e, n)); -1 !== a && r[a].index === l;) { + c = -1;for (; r.nextNode();) for (c++, r.currentNode === n && (o = j(e), n.parentNode.insertBefore(e, n)); -1 !== a && s[a].index === c;) { if (o > 0) { - for (; -1 !== a;) r[a].index += o, a = O(r, a);return; - }a = O(r, a); + for (; -1 !== a;) s[a].index += o, a = L(s, a);return; + }a = L(s, a); } - }(e, r, e.element.content.firstChild), window.ShadyCSS.prepareTemplateStyles(e.element, n), window.ShadyCSS.nativeShadow) { - const n = e.element.content.querySelector("style");t.insertBefore(n.cloneNode(!0), t.firstChild); - } else { - e.element.content.insertBefore(r, e.element.content.firstChild);const t = new Set();t.add(r), H(e, t); + }(n, a, o.firstChild) : o.insertBefore(a, o.firstChild), window.ShadyCSS.prepareTemplateStyles(i, t);const c = o.querySelector("style");if (window.ShadyCSS.nativeShadow && null !== c) e.insertBefore(c.cloneNode(!0), e.firstChild);else if (n) { + o.insertBefore(a, o.firstChild);const t = new Set();t.add(a), D(n, t); } }; /** @@ -383,7 +394,7 @@ const L = (t, e) => `${t}--${e}`;let V = !0;void 0 === window.ShadyCSS ? V = !1 * subject to an additional IP rights grant found at * http://polymer.github.io/PATENTS.txt */ -window.JSCompiler_renameProperty = (t, e) => t;const z = { toAttribute(t, e) { +window.JSCompiler_renameProperty = (t, e) => t;const U = { toAttribute(t, e) { switch (e) {case Boolean: return t ? "" : null;case Object:case Array: return null == t ? t : JSON.stringify(t);}return t; @@ -393,16 +404,16 @@ window.JSCompiler_renameProperty = (t, e) => t;const z = { toAttribute(t, e) { return null === t ? null : Number(t);case Object:case Array: return JSON.parse(t);}return t; } }, - q = (t, e) => e !== t && (e == e || t == t), - U = { attribute: !0, type: String, converter: z, reflect: !1, hasChanged: q }, - B = Promise.resolve(!0), - W = 1, - G = 4, - J = 8, - Z = 16, - X = 32;class K extends HTMLElement { + B = (t, e) => e !== t && (e == e || t == t), + W = { attribute: !0, type: String, converter: U, reflect: !1, hasChanged: B }, + G = Promise.resolve(!0), + J = 1, + Z = 4, + X = 8, + K = 16, + Q = 32;class tt extends HTMLElement { constructor() { - super(), this._updateState = 0, this._instanceProperties = void 0, this._updatePromise = B, this._hasConnectedResolver = void 0, this._changedProperties = new Map(), this._reflectingProperties = void 0, this.initialize(); + super(), this._updateState = 0, this._instanceProperties = void 0, this._updatePromise = G, this._hasConnectedResolver = void 0, this._changedProperties = new Map(), this._reflectingProperties = void 0, this.initialize(); }static get observedAttributes() { this.finalize();const t = [];return this._classProperties.forEach((e, n) => { const i = this._attributeNameForProperty(n, e);void 0 !== i && (this._attributeToPropertyMap.set(i, n), t.push(i)); @@ -411,7 +422,7 @@ window.JSCompiler_renameProperty = (t, e) => t;const z = { toAttribute(t, e) { if (!this.hasOwnProperty(JSCompiler_renameProperty("_classProperties", this))) { this._classProperties = new Map();const t = Object.getPrototypeOf(this)._classProperties;void 0 !== t && t.forEach((t, e) => this._classProperties.set(e, t)); } - }static createProperty(t, e = U) { + }static createProperty(t, e = W) { if (this._ensureClassProperties(), this._classProperties.set(t, e), e.noAccessor || this.prototype.hasOwnProperty(t)) return;const n = "symbol" == typeof t ? Symbol() : `__${t}`;Object.defineProperty(this.prototype, t, { get() { return this[n]; }, set(e) { @@ -424,15 +435,15 @@ window.JSCompiler_renameProperty = (t, e) => t;const z = { toAttribute(t, e) { } }static _attributeNameForProperty(t, e) { const n = e.attribute;return !1 === n ? void 0 : "string" == typeof n ? n : "string" == typeof t ? t.toLowerCase() : void 0; - }static _valueHasChanged(t, e, n = q) { + }static _valueHasChanged(t, e, n = B) { return n(t, e); }static _propertyValueFromAttribute(t, e) { const n = e.type, - i = e.converter || z, - r = "function" == typeof i ? i : i.fromAttribute;return r ? r(t, n) : t; + i = e.converter || U, + s = "function" == typeof i ? i : i.fromAttribute;return s ? s(t, n) : t; }static _propertyValueToAttribute(t, e) { if (void 0 === e.reflect) return;const n = e.type, - i = e.converter;return (i && i.toAttribute || z.toAttribute)(t, n); + i = e.converter;return (i && i.toAttribute || U.toAttribute)(t, n); }initialize() { this._saveInstanceProperties(), this._requestUpdate(); }_saveInstanceProperties() { @@ -444,28 +455,28 @@ window.JSCompiler_renameProperty = (t, e) => t;const z = { toAttribute(t, e) { }_applyInstanceProperties() { this._instanceProperties.forEach((t, e) => this[e] = t), this._instanceProperties = void 0; }connectedCallback() { - this._updateState = this._updateState | X, this._hasConnectedResolver && (this._hasConnectedResolver(), this._hasConnectedResolver = void 0); + this._updateState = this._updateState | Q, this._hasConnectedResolver && (this._hasConnectedResolver(), this._hasConnectedResolver = void 0); }disconnectedCallback() {}attributeChangedCallback(t, e, n) { e !== n && this._attributeToProperty(t, n); - }_propertyToAttribute(t, e, n = U) { + }_propertyToAttribute(t, e, n = W) { const i = this.constructor, - r = i._attributeNameForProperty(t, n);if (void 0 !== r) { - const t = i._propertyValueToAttribute(e, n);if (void 0 === t) return;this._updateState = this._updateState | J, null == t ? this.removeAttribute(r) : this.setAttribute(r, t), this._updateState = this._updateState & ~J; + s = i._attributeNameForProperty(t, n);if (void 0 !== s) { + const t = i._propertyValueToAttribute(e, n);if (void 0 === t) return;this._updateState = this._updateState | X, null == t ? this.removeAttribute(s) : this.setAttribute(s, t), this._updateState = this._updateState & ~X; } }_attributeToProperty(t, e) { - if (this._updateState & J) return;const n = this.constructor, + if (this._updateState & X) return;const n = this.constructor, i = n._attributeToPropertyMap.get(t);if (void 0 !== i) { - const t = n._classProperties.get(i) || U;this._updateState = this._updateState | Z, this[i] = n._propertyValueFromAttribute(e, t), this._updateState = this._updateState & ~Z; + const t = n._classProperties.get(i) || W;this._updateState = this._updateState | K, this[i] = n._propertyValueFromAttribute(e, t), this._updateState = this._updateState & ~K; } }_requestUpdate(t, e) { let n = !0;if (void 0 !== t) { const i = this.constructor, - r = i._classProperties.get(t) || U;i._valueHasChanged(this[t], e, r.hasChanged) ? (this._changedProperties.has(t) || this._changedProperties.set(t, e), !0 !== r.reflect || this._updateState & Z || (void 0 === this._reflectingProperties && (this._reflectingProperties = new Map()), this._reflectingProperties.set(t, r))) : n = !1; + s = i._classProperties.get(t) || W;i._valueHasChanged(this[t], e, s.hasChanged) ? (this._changedProperties.has(t) || this._changedProperties.set(t, e), !0 !== s.reflect || this._updateState & K || (void 0 === this._reflectingProperties && (this._reflectingProperties = new Map()), this._reflectingProperties.set(t, s))) : n = !1; }!this._hasRequestedUpdate && n && this._enqueueUpdate(); }requestUpdate(t, e) { return this._requestUpdate(t, e), this.updateComplete; }async _enqueueUpdate() { - let t, e;this._updateState = this._updateState | G;const n = this._updatePromise;this._updatePromise = new Promise((n, i) => { + let t, e;this._updateState = this._updateState | Z;const n = this._updatePromise;this._updatePromise = new Promise((n, i) => { t = n, e = i; });try { await n; @@ -475,11 +486,11 @@ window.JSCompiler_renameProperty = (t, e) => t;const z = { toAttribute(t, e) { e(t); }t(!this._hasRequestedUpdate); }get _hasConnected() { - return this._updateState & X; + return this._updateState & Q; }get _hasRequestedUpdate() { - return this._updateState & G; + return this._updateState & Z; }get hasUpdated() { - return this._updateState & W; + return this._updateState & J; }performUpdate() { this._instanceProperties && this._applyInstanceProperties();let t = !1;const e = this._changedProperties;try { (t = this.shouldUpdate(e)) && this.update(e); @@ -487,9 +498,9 @@ window.JSCompiler_renameProperty = (t, e) => t;const z = { toAttribute(t, e) { throw t = !1, e; } finally { this._markUpdated(); - }t && (this._updateState & W || (this._updateState = this._updateState | W, this.firstUpdated(e)), this.updated(e)); + }t && (this._updateState & J || (this._updateState = this._updateState | J, this.firstUpdated(e)), this.updated(e)); }_markUpdated() { - this._changedProperties = new Map(), this._updateState = this._updateState & ~G; + this._changedProperties = new Map(), this._updateState = this._updateState & ~Z; }get updateComplete() { return this._updatePromise; }shouldUpdate(t) { @@ -497,7 +508,7 @@ window.JSCompiler_renameProperty = (t, e) => t;const z = { toAttribute(t, e) { }update(t) { void 0 !== this._reflectingProperties && this._reflectingProperties.size > 0 && (this._reflectingProperties.forEach((t, e) => this._propertyToAttribute(e, this[e], t)), this._reflectingProperties = void 0); }updated(t) {}firstUpdated(t) {} -}K.finalized = !0; +}tt.finalized = !0; /** * @license * Copyright (c) 2017 The Polymer Project Authors. All rights reserved. @@ -511,17 +522,17 @@ window.JSCompiler_renameProperty = (t, e) => t;const z = { toAttribute(t, e) { * subject to an additional IP rights grant found at * http://polymer.github.io/PATENTS.txt */ -const Q = (t, e) => "method" !== e.kind || !e.descriptor || "value" in e.descriptor ? { kind: "field", key: Symbol(), placement: "own", descriptor: {}, initializer() { +const et = (t, e) => "method" !== e.kind || !e.descriptor || "value" in e.descriptor ? { kind: "field", key: Symbol(), placement: "own", descriptor: {}, initializer() { "function" == typeof e.initializer && (this[e.key] = e.initializer.call(this)); }, finisher(n) { n.createProperty(e.key, t); } } : Object.assign({}, e, { finisher(n) { n.createProperty(e.key, t); } }), - tt = (t, e, n) => { + nt = (t, e, n) => { e.constructor.createProperty(n, t); -};function et(t) { - return (e, n) => void 0 !== n ? tt(t, e, n) : Q(t, e); +};function it(t) { + return (e, n) => void 0 !== n ? nt(t, e, n) : et(t, e); } /** @license @@ -532,12 +543,12 @@ http://polymer.github.io/AUTHORS.txt The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt Code distributed by Google as part of the polymer project is also subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt -*/const nt = "adoptedStyleSheets" in Document.prototype && "replace" in CSSStyleSheet.prototype, - it = Symbol();class rt { +*/const st = "adoptedStyleSheets" in Document.prototype && "replace" in CSSStyleSheet.prototype, + rt = Symbol();class at { constructor(t, e) { - if (e !== it) throw new Error("CSSResult is not constructable. Use `unsafeCSS` or `css` instead.");this.cssText = t; + if (e !== rt) throw new Error("CSSResult is not constructable. Use `unsafeCSS` or `css` instead.");this.cssText = t; }get styleSheet() { - return void 0 === this._styleSheet && (nt ? (this._styleSheet = new CSSStyleSheet(), this._styleSheet.replaceSync(this.cssText)) : this._styleSheet = null), this._styleSheet; + return void 0 === this._styleSheet && (st ? (this._styleSheet = new CSSStyleSheet(), this._styleSheet.replaceSync(this.cssText)) : this._styleSheet = null), this._styleSheet; }toString() { return this.cssText; } @@ -555,41 +566,41 @@ found at http://polymer.github.io/PATENTS.txt * subject to an additional IP rights grant found at * http://polymer.github.io/PATENTS.txt */ -(window.litElementVersions || (window.litElementVersions = [])).push("2.0.1");const st = t => t.flat ? t.flat(1 / 0) : function t(e, n = []) { - for (let i = 0, r = e.length; i < r; i++) { - const r = e[i];Array.isArray(r) ? t(r, n) : n.push(r); +(window.litElementVersions || (window.litElementVersions = [])).push("2.2.0");const ot = t => t.flat ? t.flat(1 / 0) : function t(e, n = []) { + for (let i = 0, s = e.length; i < s; i++) { + const s = e[i];Array.isArray(s) ? t(s, n) : n.push(s); }return n; -}(t);class at extends K { +}(t);class ct extends tt { static finalize() { super.finalize(), this._styles = this.hasOwnProperty(JSCompiler_renameProperty("styles", this)) ? this._getUniqueStyles() : this._styles || []; }static _getUniqueStyles() { const t = this.styles, e = [];if (Array.isArray(t)) { - st(t).reduceRight((t, e) => (t.add(e), t), new Set()).forEach(t => e.unshift(t)); + ot(t).reduceRight((t, e) => (t.add(e), t), new Set()).forEach(t => e.unshift(t)); } else t && e.push(t);return e; }initialize() { super.initialize(), this.renderRoot = this.createRenderRoot(), window.ShadowRoot && this.renderRoot instanceof window.ShadowRoot && this.adoptStyles(); }createRenderRoot() { return this.attachShadow({ mode: "open" }); }adoptStyles() { - const t = this.constructor._styles;0 !== t.length && (void 0 === window.ShadyCSS || window.ShadyCSS.nativeShadow ? nt ? this.renderRoot.adoptedStyleSheets = t.map(t => t.styleSheet) : this._needsShimAdoptedStyleSheets = !0 : window.ShadyCSS.ScopingShim.prepareAdoptedCssText(t.map(t => t.cssText), this.localName)); + const t = this.constructor._styles;0 !== t.length && (void 0 === window.ShadyCSS || window.ShadyCSS.nativeShadow ? st ? this.renderRoot.adoptedStyleSheets = t.map(t => t.styleSheet) : this._needsShimAdoptedStyleSheets = !0 : window.ShadyCSS.ScopingShim.prepareAdoptedCssText(t.map(t => t.cssText), this.localName)); }connectedCallback() { super.connectedCallback(), this.hasUpdated && void 0 !== window.ShadyCSS && window.ShadyCSS.styleElement(this); }update(t) { - super.update(t);const e = this.render();e instanceof b && this.constructor.render(e, this.renderRoot, { scopeName: this.localName, eventContext: this }), this._needsShimAdoptedStyleSheets && (this._needsShimAdoptedStyleSheets = !1, this.constructor._styles.forEach(t => { + super.update(t);const e = this.render();e instanceof _ && this.constructor.render(e, this.renderRoot, { scopeName: this.localName, eventContext: this }), this._needsShimAdoptedStyleSheets && (this._needsShimAdoptedStyleSheets = !1, this.constructor._styles.forEach(t => { const e = document.createElement("style");e.textContent = t.cssText, this.renderRoot.appendChild(e); })); }render() {} -}at.finalized = !0, at.render = (t, e, n) => { - const i = n.scopeName, - r = N.has(e), - a = e instanceof ShadowRoot && V && t instanceof b, - o = a && !F.has(i), - l = o ? document.createDocumentFragment() : e;if (((t, e, n) => { - let i = N.get(e);void 0 === i && (s(e, e.firstChild), N.set(e, i = new w(Object.assign({ templateFactory: A }, n))), i.appendInto(e)), i.setValue(t), i.commit(); - })(t, l, Object.assign({ templateFactory: j(i) }, n)), o) { - const t = N.get(l);N.delete(l), t.value instanceof g && Y(l, t.value.template, i), s(e, e.firstChild), e.appendChild(l), N.set(e, t); - }!r && a && window.ShadyCSS.styleElement(e.host); +}ct.finalized = !0, ct.render = (t, e, n) => { + if (!n || "object" != typeof n || !n.scopeName) throw new Error("The `scopeName` option is required.");const i = n.scopeName, + s = R.has(e), + a = I && 11 === e.nodeType && !!e.host, + o = a && !z.has(i), + c = o ? document.createDocumentFragment() : e;if (((t, e, n) => { + let i = R.get(e);void 0 === i && (r(e, e.firstChild), R.set(e, i = new x(Object.assign({ templateFactory: A }, n))), i.appendInto(e)), i.setValue(t), i.commit(); + })(t, c, Object.assign({ templateFactory: F(i) }, n)), o) { + const t = R.get(c);R.delete(c);const n = t.value instanceof b ? t.value.template : void 0;q(i, c, n), r(e, e.firstChild), e.appendChild(c), R.set(e, t); + }!s && a && window.ShadyCSS.styleElement(e.host); }; /** * @license @@ -604,60 +615,49 @@ found at http://polymer.github.io/PATENTS.txt * subject to an additional IP rights grant found at * http://polymer.github.io/PATENTS.txt */ -const ot = new WeakMap(), - lt = new WeakMap(), - ct = n(t => e => { - if (!(e instanceof _) || e instanceof k || "style" !== e.committer.name || e.committer.parts.length > 1) throw new Error("The `styleMap` directive must be used in the style attribute and must be the only part in the attribute.");lt.has(e) || (e.committer.element.style.cssText = e.committer.strings.join(" "), lt.set(e, !0));const n = e.committer.element.style, - i = ot.get(e);for (const e in i) e in t || (-1 === e.indexOf("-") ? n[e] = null : n.removeProperty(e));for (const e in t) -1 === e.indexOf("-") ? n[e] = t[e] : n.setProperty(e, t[e]);ot.set(e, t); -}), - ht = new WeakMap(), - dt = n(t => e => { - if (!(e instanceof w)) throw new Error("unsafeHTML can only be used in text bindings");const n = ht.get(e);if (void 0 !== n && y(t) && t === n.value && e.value === n.fragment) return;const i = document.createElement("template");i.innerHTML = t;const r = document.importNode(i.content, !0);e.setValue(r), ht.set(e, { value: t, fragment: r }); +const lt = new WeakMap(), + ht = n(t => e => { + if (!(e instanceof S) || e instanceof E || "style" !== e.committer.name || e.committer.parts.length > 1) throw new Error("The `styleMap` directive must be used in the style attribute and must be the only part in the attribute.");const { committer: n } = e, + { style: i } = n.element;lt.has(e) || (i.cssText = n.strings.join(" "));const s = lt.get(e);for (const e in s) e in t || (-1 === e.indexOf("-") ? i[e] = null : i.removeProperty(e));for (const e in t) -1 === e.indexOf("-") ? i[e] = t[e] : i.setProperty(e, t[e]);lt.set(e, t); }), + dt = new WeakMap(), ut = n(t => e => { - if (void 0 === t && e instanceof _) { + if (!(e instanceof x)) throw new Error("unsafeHTML can only be used in text bindings");const n = dt.get(e);if (void 0 !== n && y(t) && t === n.value && e.value === n.fragment) return;const i = document.createElement("template");i.innerHTML = t;const s = document.importNode(i.content, !0);e.setValue(s), dt.set(e, { value: t, fragment: s }); +}), + pt = n(t => e => { + if (void 0 === t && e instanceof S) { if (t !== e.value) { const t = e.committer.name;e.committer.element.removeAttribute(t); } } else e.setValue(t); -}); -/** - * @license - * Copyright (c) 2018 The Polymer Project Authors. All rights reserved. - * This code may only be used under the BSD style license found at - * http://polymer.github.io/LICENSE.txt - * The complete set of authors may be found at - * http://polymer.github.io/AUTHORS.txt - * The complete set of contributors may be found at - * http://polymer.github.io/CONTRIBUTORS.txt - * Code distributed by Google as part of the polymer project is also - * subject to an additional IP rights grant found at - * http://polymer.github.io/PATENTS.txt - */ -window.navigator.userAgent.match("Trident") && (DOMTokenList.prototype.toggle = function (t, e) { - return void 0 === e || e ? this.add(t) : this.remove(t), void 0 === e || e; -});const pt = new WeakMap(), +}), ft = new WeakMap(), mt = n(t => e => { - if (!(e instanceof _) || e instanceof k || "class" !== e.committer.name || e.committer.parts.length > 1) throw new Error("The `classMap` directive must be used in the `class` attribute and must be the only part in the attribute.");ft.has(e) || (e.committer.element.className = e.committer.strings.join(" "), ft.set(e, !0));const n = pt.get(e);for (const i in n) i in t || e.committer.element.classList.remove(i);for (const i in t) n && n[i] === t[i] || e.committer.element.classList.toggle(i, Boolean(t[i]));pt.set(e, t); + if (!(e instanceof S) || e instanceof E || "class" !== e.committer.name || e.committer.parts.length > 1) throw new Error("The `classMap` directive must be used in the `class` attribute and must be the only part in the attribute.");const { committer: n } = e, + { element: i } = n;ft.has(e) || (i.className = n.strings.join(" "));const { classList: s } = i, + r = ft.get(e);for (const e in r) e in t || s.remove(e);for (const e in t) { + const n = t[e];if (!r || n !== r[e]) { + s[n ? "add" : "remove"](e); + } + }ft.set(e, t); });var gt = {}, bt = /d{1,4}|M{1,4}|YY(?:YY)?|S{1,3}|Do|ZZ|([HhMsDm])\1?|[aA]|"[^"]*"|'[^']*'/g, - yt = "[^\\s]+", - vt = /\[([^]*?)\]/gm, - _t = function () {};function wt(t, e) { - for (var n = [], i = 0, r = t.length; i < r; i++) n.push(t[i].substr(0, e));return n; + _t = "[^\\s]+", + yt = /\[([^]*?)\]/gm, + vt = function () {};function wt(t, e) { + for (var n = [], i = 0, s = t.length; i < s; i++) n.push(t[i].substr(0, e));return n; }function St(t) { return function (e, n, i) { - var r = i[t].indexOf(n.charAt(0).toUpperCase() + n.substr(1).toLowerCase());~r && (e.month = r); + var s = i[t].indexOf(n.charAt(0).toUpperCase() + n.substr(1).toLowerCase());~s && (e.month = s); }; }function xt(t, e) { for (t = String(t), e = e || 2; t.length < e;) t = "0" + t;return t; }var kt = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"], Mt = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"], - Ct = wt(Mt, 3), - Et = wt(kt, 3);gt.i18n = { dayNamesShort: Et, dayNames: kt, monthNamesShort: Ct, monthNames: Mt, amPm: ["am", "pm"], DoFn: function (t) { + Et = wt(Mt, 3), + Ct = wt(kt, 3);gt.i18n = { dayNamesShort: Ct, dayNames: kt, monthNamesShort: Et, monthNames: Mt, amPm: ["am", "pm"], DoFn: function (t) { return t + ["th", "st", "nd", "rd"][t % 10 > 3 ? 0 : (t - t % 10 != 10) * t % 10]; - } };var Pt = { D: function (t) { + } };var Tt = { D: function (t) { return t.getDate(); }, DD: function (t) { return xt(t.getDate()); @@ -712,9 +712,9 @@ window.navigator.userAgent.match("Trident") && (DOMTokenList.prototype.toggle = }, ZZ: function (t) { var e = t.getTimezoneOffset();return (e > 0 ? "-" : "+") + xt(100 * Math.floor(Math.abs(e) / 60) + Math.abs(e) % 60, 4); } }, - At = { D: ["\\d\\d?", function (t, e) { + Pt = { D: ["\\d\\d?", function (t, e) { t.day = e; - }], Do: ["\\d\\d?" + yt, function (t, e) { + }], Do: ["\\d\\d?" + _t, function (t, e) { t.day = parseInt(e, 10); }], M: ["\\d\\d?", function (t, e) { t.month = e - 1; @@ -734,35 +734,35 @@ window.navigator.userAgent.match("Trident") && (DOMTokenList.prototype.toggle = t.millisecond = 10 * e; }], SSS: ["\\d{3}", function (t, e) { t.millisecond = e; - }], d: ["\\d\\d?", _t], ddd: [yt, _t], MMM: [yt, St("monthNamesShort")], MMMM: [yt, St("monthNames")], a: [yt, function (t, e, n) { + }], d: ["\\d\\d?", vt], ddd: [_t, vt], MMM: [_t, St("monthNamesShort")], MMMM: [_t, St("monthNames")], a: [_t, function (t, e, n) { var i = e.toLowerCase();i === n.amPm[0] ? t.isPm = !1 : i === n.amPm[1] && (t.isPm = !0); }], ZZ: ["[^\\s]*?[\\+\\-]\\d\\d:?\\d\\d|[^\\s]*?Z", function (t, e) { var n, i = (e + "").match(/([+-]|\d\d)/gi);i && (n = 60 * i[1] + parseInt(i[2], 10), t.timezoneOffset = "+" === i[0] ? n : -n); - }] };function Tt(t) { + }] };function Nt(t) { var e = t.split(":").map(Number);return 3600 * e[0] + 60 * e[1] + e[2]; -}At.dd = At.d, At.dddd = At.ddd, At.DD = At.D, At.mm = At.m, At.hh = At.H = At.HH = At.h, At.MM = At.M, At.ss = At.s, At.A = At.a, gt.masks = { default: "ddd MMM DD YYYY HH:mm:ss", shortDate: "M/D/YY", mediumDate: "MMM D, YYYY", longDate: "MMMM D, YYYY", fullDate: "dddd, MMMM D, YYYY", shortTime: "HH:mm", mediumTime: "HH:mm:ss", longTime: "HH:mm:ss.SSS" }, gt.format = function (t, e, n) { - var i = n || gt.i18n;if ("number" == typeof t && (t = new Date(t)), "[object Date]" !== Object.prototype.toString.call(t) || isNaN(t.getTime())) throw new Error("Invalid Date in fecha.format");e = gt.masks[e] || e || gt.masks.default;var r = [];return (e = (e = e.replace(vt, function (t, e) { - return r.push(e), "@@@"; +}Pt.dd = Pt.d, Pt.dddd = Pt.ddd, Pt.DD = Pt.D, Pt.mm = Pt.m, Pt.hh = Pt.H = Pt.HH = Pt.h, Pt.MM = Pt.M, Pt.ss = Pt.s, Pt.A = Pt.a, gt.masks = { default: "ddd MMM DD YYYY HH:mm:ss", shortDate: "M/D/YY", mediumDate: "MMM D, YYYY", longDate: "MMMM D, YYYY", fullDate: "dddd, MMMM D, YYYY", shortTime: "HH:mm", mediumTime: "HH:mm:ss", longTime: "HH:mm:ss.SSS" }, gt.format = function (t, e, n) { + var i = n || gt.i18n;if ("number" == typeof t && (t = new Date(t)), "[object Date]" !== Object.prototype.toString.call(t) || isNaN(t.getTime())) throw new Error("Invalid Date in fecha.format");e = gt.masks[e] || e || gt.masks.default;var s = [];return (e = (e = e.replace(yt, function (t, e) { + return s.push(e), "@@@"; })).replace(bt, function (e) { - return e in Pt ? Pt[e](t, i) : e.slice(1, e.length - 1); + return e in Tt ? Tt[e](t, i) : e.slice(1, e.length - 1); })).replace(/@@@/g, function () { - return r.shift(); + return s.shift(); }); }, gt.parse = function (t, e, n) { - var i = n || gt.i18n;if ("string" != typeof e) throw new Error("Invalid format in fecha.parse");if (e = gt.masks[e] || e, t.length > 1e3) return null;var r = {}, - s = [], - a = [];e = e.replace(vt, function (t, e) { + var i = n || gt.i18n;if ("string" != typeof e) throw new Error("Invalid format in fecha.parse");if (e = gt.masks[e] || e, t.length > 1e3) return null;var s = {}, + r = [], + a = [];e = e.replace(yt, function (t, e) { return a.push(e), "@@@"; });var o, - l = (o = e, o.replace(/[|\\{()[^$+*?.-]/g, "\\$&")).replace(bt, function (t) { - if (At[t]) { - var e = At[t];return s.push(e[1]), "(" + e[0] + ")"; + c = (o = e, o.replace(/[|\\{()[^$+*?.-]/g, "\\$&")).replace(bt, function (t) { + if (Pt[t]) { + var e = Pt[t];return r.push(e[1]), "(" + e[0] + ")"; }return t; - });l = l.replace(/@@@/g, function () { + });c = c.replace(/@@@/g, function () { return a.shift(); - });var c = t.match(new RegExp(l, "i"));if (!c) return null;for (var h = 1; h < c.length; h++) s[h - 1](r, c[h], i);var d, - u = new Date();return !0 === r.isPm && null != r.hour && 12 != +r.hour ? r.hour = +r.hour + 12 : !1 === r.isPm && 12 == +r.hour && (r.hour = 0), null != r.timezoneOffset ? (r.minute = +(r.minute || 0) - +r.timezoneOffset, d = new Date(Date.UTC(r.year || u.getFullYear(), r.month || 0, r.day || 1, r.hour || 0, r.minute || 0, r.second || 0, r.millisecond || 0))) : d = new Date(r.year || u.getFullYear(), r.month || 0, r.day || 1, r.hour || 0, r.minute || 0, r.second || 0, r.millisecond || 0), d; + });var l = t.match(new RegExp(c, "i"));if (!l) return null;for (var h = 1; h < l.length; h++) r[h - 1](s, l[h], i);var d, + u = new Date();return !0 === s.isPm && null != s.hour && 12 != +s.hour ? s.hour = +s.hour + 12 : !1 === s.isPm && 12 == +s.hour && (s.hour = 0), null != s.timezoneOffset ? (s.minute = +(s.minute || 0) - +s.timezoneOffset, d = new Date(Date.UTC(s.year || u.getFullYear(), s.month || 0, s.day || 1, s.hour || 0, s.minute || 0, s.second || 0, s.millisecond || 0))) : d = new Date(s.year || u.getFullYear(), s.month || 0, s.day || 1, s.hour || 0, s.minute || 0, s.second || 0, s.millisecond || 0), d; };(function () { try { new Date().toLocaleDateString("i"); @@ -781,49 +781,49 @@ window.navigator.userAgent.match("Trident") && (DOMTokenList.prototype.toggle = } catch (t) { return "RangeError" === t.name; } -}();var Nt = function (t) { +}();var At = function (t) { return t < 10 ? "0" + t : t; -};var Rt = "hass:bookmark", - $t = ["closed", "locked", "off"], - Ht = function (t, e, n, i) { - i = i || {}, n = null == n ? {} : n;var r = new Event(e, { bubbles: void 0 === i.bubbles || i.bubbles, cancelable: Boolean(i.cancelable), composed: void 0 === i.composed || i.composed });return r.detail = n, t.dispatchEvent(r), r; +};var Ot = "hass:bookmark", + Rt = ["closed", "locked", "off"], + $t = function (t, e, n, i) { + i = i || {}, n = null == n ? {} : n;var s = new Event(e, { bubbles: void 0 === i.bubbles || i.bubbles, cancelable: Boolean(i.cancelable), composed: void 0 === i.composed || i.composed });return s.detail = n, t.dispatchEvent(s), s; }, - Dt = { alert: "hass:alert", automation: "hass:playlist-play", calendar: "hass:calendar", camera: "hass:video", climate: "hass:thermostat", configurator: "hass:settings", conversation: "hass:text-to-speech", device_tracker: "hass:account", fan: "hass:fan", group: "hass:google-circles-communities", history_graph: "hass:chart-line", homeassistant: "hass:home-assistant", homekit: "hass:home-automation", image_processing: "hass:image-filter-frames", input_boolean: "hass:drawing", input_datetime: "hass:calendar-clock", input_number: "hass:ray-vertex", input_select: "hass:format-list-bulleted", input_text: "hass:textbox", light: "hass:lightbulb", mailbox: "hass:mailbox", notify: "hass:comment-alert", person: "hass:account", plant: "hass:flower", proximity: "hass:apple-safari", remote: "hass:remote", scene: "hass:google-pages", script: "hass:file-document", sensor: "hass:eye", simple_alarm: "hass:bell", sun: "hass:white-balance-sunny", switch: "hass:flash", timer: "hass:timer", updater: "hass:cloud-upload", vacuum: "hass:robot-vacuum", water_heater: "hass:thermometer", weblink: "hass:open-in-new" };var Ot = function (t, e) { - Ht(t, "haptic", e); + Ht = { alert: "hass:alert", automation: "hass:playlist-play", calendar: "hass:calendar", camera: "hass:video", climate: "hass:thermostat", configurator: "hass:settings", conversation: "hass:text-to-speech", device_tracker: "hass:account", fan: "hass:fan", group: "hass:google-circles-communities", history_graph: "hass:chart-line", homeassistant: "hass:home-assistant", homekit: "hass:home-automation", image_processing: "hass:image-filter-frames", input_boolean: "hass:drawing", input_datetime: "hass:calendar-clock", input_number: "hass:ray-vertex", input_select: "hass:format-list-bulleted", input_text: "hass:textbox", light: "hass:lightbulb", mailbox: "hass:mailbox", notify: "hass:comment-alert", person: "hass:account", plant: "hass:flower", proximity: "hass:apple-safari", remote: "hass:remote", scene: "hass:google-pages", script: "hass:file-document", sensor: "hass:eye", simple_alarm: "hass:bell", sun: "hass:white-balance-sunny", switch: "hass:flash", timer: "hass:timer", updater: "hass:cloud-upload", vacuum: "hass:robot-vacuum", water_heater: "hass:thermometer", weblink: "hass:open-in-new" };var Dt = function (t, e) { + $t(t, "haptic", e); }, - Lt = function (t, e, n, i, r) { - var s;switch (r && n.dbltap_action ? s = n.dbltap_action : i && n.hold_action ? s = n.hold_action : !i && n.tap_action && (s = n.tap_action), s || (s = { action: "more-info" }), s.action) {case "more-info": - (n.entity || n.camera_image) && (Ht(t, "hass-more-info", { entityId: s.entity ? s.entity : n.entity ? n.entity : n.camera_image }), s.haptic && Ot(t, s.haptic));break;case "navigate": - s.navigation_path && (function (t, e, n) { - void 0 === n && (n = !1), n ? history.replaceState(null, "", e) : history.pushState(null, "", e), Ht(window, "location-changed", { replace: n }); - }(0, s.navigation_path), s.haptic && Ot(t, s.haptic));break;case "url": - s.url && window.open(s.url), s.haptic && Ot(t, s.haptic);break;case "toggle": + jt = function (t, e, n, i, s) { + var r;switch (s && n.dbltap_action ? r = n.dbltap_action : i && n.hold_action ? r = n.hold_action : !i && n.tap_action && (r = n.tap_action), r || (r = { action: "more-info" }), r.action) {case "more-info": + (n.entity || n.camera_image) && ($t(t, "hass-more-info", { entityId: r.entity ? r.entity : n.entity ? n.entity : n.camera_image }), r.haptic && Dt(t, r.haptic));break;case "navigate": + r.navigation_path && (function (t, e, n) { + void 0 === n && (n = !1), n ? history.replaceState(null, "", e) : history.pushState(null, "", e), $t(window, "location-changed", { replace: n }); + }(0, r.navigation_path), r.haptic && Dt(t, r.haptic));break;case "url": + r.url && window.open(r.url), r.haptic && Dt(t, r.haptic);break;case "toggle": n.entity && (function (t, e) { (function (t, e, n) { void 0 === n && (n = !0);var i, - r = function (t) { + s = function (t) { return t.substr(0, t.indexOf(".")); }(e), - s = "group" === r ? "homeassistant" : r;switch (r) {case "lock": + r = "group" === s ? "homeassistant" : s;switch (s) {case "lock": i = n ? "unlock" : "lock";break;case "cover": i = n ? "open_cover" : "close_cover";break;default: - i = n ? "turn_on" : "turn_off";}t.callService(s, i, { entity_id: e }); - })(t, e, $t.includes(t.states[e].state)); - }(e, n.entity), s.haptic && Ot(t, s.haptic));break;case "call-service": - if (!s.service) return;var a = s.service.split(".", 2), + i = n ? "turn_on" : "turn_off";}t.callService(r, i, { entity_id: e }); + })(t, e, Rt.includes(t.states[e].state)); + }(e, n.entity), r.haptic && Dt(t, r.haptic));break;case "call-service": + if (!r.service) return;var a = r.service.split(".", 2), o = a[0], - l = a[1], - c = Object.assign({}, s.service_data);"entity" === c.entity_id && (c.entity_id = n.entity), e.callService(o, l, c), s.haptic && Ot(t, s.haptic);} + c = a[1], + l = Object.assign({}, r.service_data);"entity" === l.entity_id && (l.entity_id = n.entity), e.callService(o, c, l), r.haptic && Dt(t, r.haptic);} };String(Math.random()).slice(2);try { const t = { get capture() { return !1; } };window.addEventListener("test", t, t), window.removeEventListener("test", t, t); -} catch (t) {}(window.litHtmlVersions || (window.litHtmlVersions = [])).push("1.0.0");var Vt = "ontouchstart" in window || navigator.maxTouchPoints > 0 || navigator.msMaxTouchPoints > 0, - jt = function (t) { +} catch (t) {}(window.litHtmlVersions || (window.litHtmlVersions = [])).push("1.0.0");var Lt = "ontouchstart" in window || navigator.maxTouchPoints > 0 || navigator.msMaxTouchPoints > 0, + Vt = function (t) { function e() { t.call(this), this.holdTime = 500, this.ripple = document.createElement("paper-ripple"), this.timer = void 0, this.held = !1, this.cooldownStart = !1, this.cooldownEnd = !1, this.nbClicks = 0; }return t && (e.__proto__ = t), (e.prototype = Object.create(t && t.prototype)).constructor = e, e.prototype.connectedCallback = function () { - var t = this;Object.assign(this.style, { borderRadius: "50%", position: "absolute", width: Vt ? "100px" : "50px", height: Vt ? "100px" : "50px", transform: "translate(-50%, -50%)", pointerEvents: "none" }), this.appendChild(this.ripple), this.ripple.style.color = "#03a9f4", this.ripple.style.color = "var(--primary-color)", ["touchcancel", "mouseout", "mouseup", "touchmove", "mousewheel", "wheel", "scroll"].forEach(function (e) { + var t = this;Object.assign(this.style, { borderRadius: "50%", position: "absolute", width: Lt ? "100px" : "50px", height: Lt ? "100px" : "50px", transform: "translate(-50%, -50%)", pointerEvents: "none" }), this.appendChild(this.ripple), this.ripple.style.color = "#03a9f4", this.ripple.style.color = "var(--primary-color)", ["touchcancel", "mouseout", "mouseup", "touchmove", "mousewheel", "wheel", "scroll"].forEach(function (e) { document.addEventListener(e, function () { clearTimeout(t.timer), t.stopAnimation(), t.timer = void 0; }, { passive: !0 }); @@ -833,8 +833,8 @@ window.navigator.userAgent.match("Trident") && (DOMTokenList.prototype.toggle = t.longPress = !0, t.addEventListener("contextmenu", function (t) { var e = t || window.event;return e.preventDefault && e.preventDefault(), e.stopPropagation && e.stopPropagation(), e.cancelBubble = !0, e.returnValue = !1, !1; });var n = function (n) { - var i, r;e.cooldownStart || (e.held = !1, n.touches ? (i = n.touches[0].pageX, r = n.touches[0].pageY) : (i = n.pageX, r = n.pageY), e.timer = window.setTimeout(function () { - e.startAnimation(i, r), e.held = !0, t.repeat && !t.isRepeating && (t.isRepeating = !0, e.repeatTimeout = setInterval(function () { + var i, s;e.cooldownStart || (e.held = !1, n.touches ? (i = n.touches[0].pageX, s = n.touches[0].pageY) : (i = n.pageX, s = n.pageY), e.timer = window.setTimeout(function () { + e.startAnimation(i, s), e.held = !0, t.repeat && !t.isRepeating && (t.isRepeating = !0, e.repeatTimeout = setInterval(function () { t.dispatchEvent(new Event("ha-hold")); }, t.repeat)); }, e.holdTime), e.cooldownStart = !0, window.setTimeout(function () { @@ -854,7 +854,7 @@ window.navigator.userAgent.match("Trident") && (DOMTokenList.prototype.toggle = }, e.prototype.stopAnimation = function () { this.ripple.holdDown = !1, this.style.display = "none"; }, e; -}(HTMLElement);customElements.get("long-press-custom-card-helpers") || customElements.define("long-press-custom-card-helpers", jt);const It = "ontouchstart" in window || navigator.maxTouchPoints > 0 || navigator.msMaxTouchPoints > 0;customElements.define("long-press-button-card", class extends HTMLElement { +}(HTMLElement);customElements.get("long-press-custom-card-helpers") || customElements.define("long-press-custom-card-helpers", Vt);const It = "ontouchstart" in window || navigator.maxTouchPoints > 0 || navigator.msMaxTouchPoints > 0;customElements.define("long-press-button-card", class extends HTMLElement { constructor() { super(), this.holdTime = 500, this.ripple = document.createElement("paper-ripple"), this.timer = void 0, this.held = !1, this.cooldownStart = !1, this.cooldownEnd = !1, this.nbClicks = 0; }connectedCallback() { @@ -867,14 +867,14 @@ window.navigator.userAgent.match("Trident") && (DOMTokenList.prototype.toggle = if (t.longPress) return;t.longPress = !0, t.addEventListener("contextmenu", t => { const e = t || window.event;return e.preventDefault && e.preventDefault(), e.stopPropagation && e.stopPropagation(), e.cancelBubble = !0, e.returnValue = !1, !1; });const e = e => { - if (this.cooldownStart) return;let n, i;this.held = !1, e.touches ? (n = e.touches[0].pageX, i = e.touches[0].pageY) : (n = e.pageX, i = e.pageY), this.timer = window.setTimeout(() => { + if (e.stopPropagation(), this.cooldownStart) return;let n, i;this.held = !1, e.touches ? (n = e.touches[0].pageX, i = e.touches[0].pageY) : (n = e.pageX, i = e.pageY), this.timer = window.setTimeout(() => { this.startAnimation(n, i), this.held = !0, t.repeat && !t.isRepeating && (t.isRepeating = !0, this.repeatTimeout = setInterval(() => { t.dispatchEvent(new Event("ha-hold")); }, t.repeat)); }, this.holdTime), this.cooldownStart = !0, window.setTimeout(() => this.cooldownStart = !1, 100); }, n = e => { - this.cooldownEnd || ["touchend", "touchcancel"].includes(e.type) && void 0 === this.timer ? t.isRepeating && this.repeatTimeout && (clearInterval(this.repeatTimeout), t.isRepeating = !1) : (clearTimeout(this.timer), t.isRepeating && this.repeatTimeout && clearInterval(this.repeatTimeout), t.isRepeating = !1, this.stopAnimation(), this.timer = void 0, this.held ? t.repeat || t.dispatchEvent(new Event("ha-hold")) : t.hasDblClick ? 0 === this.nbClicks ? (this.nbClicks += 1, this.dblClickTimeout = window.setTimeout(() => { + e.stopPropagation(), this.cooldownEnd || ["touchend", "touchcancel"].includes(e.type) && void 0 === this.timer ? t.isRepeating && this.repeatTimeout && (clearInterval(this.repeatTimeout), t.isRepeating = !1) : (clearTimeout(this.timer), t.isRepeating && this.repeatTimeout && clearInterval(this.repeatTimeout), t.isRepeating = !1, this.stopAnimation(), this.timer = void 0, this.held ? t.repeat || t.dispatchEvent(new Event("ha-hold")) : t.hasDblClick ? 0 === this.nbClicks ? (this.nbClicks += 1, this.dblClickTimeout = window.setTimeout(() => { 1 === this.nbClicks && (this.nbClicks = 0, t.dispatchEvent(new Event("ha-click"))); }, 250)) : (this.nbClicks = 0, clearTimeout(this.dblClickTimeout), t.dispatchEvent(new Event("ha-dblclick"))) : t.dispatchEvent(new Event("ha-click")), this.cooldownEnd = !0, window.setTimeout(() => this.cooldownEnd = !1, 100)); };t.addEventListener("touchstart", e, { passive: !0 }), t.addEventListener("touchend", n), t.addEventListener("touchcancel", n), t.addEventListener("mousedown", e, { passive: !0 }), t.addEventListener("click", n); @@ -892,9 +892,9 @@ window.navigator.userAgent.match("Trident") && (DOMTokenList.prototype.toggle = Ft(t.committer.element); });function zt(t, e) { (function (t) { - return "string" == typeof t && -1 !== t.indexOf(".") && 1 === parseFloat(t); + return "string" == typeof t && t.includes(".") && 1 === parseFloat(t); })(t) && (t = "100%");var n = function (t) { - return "string" == typeof t && -1 !== t.indexOf("%"); + return "string" == typeof t && t.includes("%"); }(t);return t = 360 === e ? t : Math.min(e, Math.max(0, parseFloat(t))), n && (t = parseInt(String(t * e), 10) / 100), Math.abs(t - e) < 1e-6 ? 1 : t = 360 === e ? (t < 0 ? t % e + e : t % e) / parseFloat(String(e)) : t % e / parseFloat(String(e)); }function qt(t) { return Math.min(1, Math.max(0, t)); @@ -906,29 +906,29 @@ window.navigator.userAgent.match("Trident") && (DOMTokenList.prototype.toggle = return 1 === t.length ? "0" + t : String(t); }function Gt(t, e, n) { t = zt(t, 255), e = zt(e, 255), n = zt(n, 255);var i = Math.max(t, e, n), - r = Math.min(t, e, n), - s = 0, + s = Math.min(t, e, n), + r = 0, a = 0, - o = (i + r) / 2;if (i === r) a = 0, s = 0;else { - var l = i - r;switch (a = o > .5 ? l / (2 - i - r) : l / (i + r), i) {case t: - s = (e - n) / l + (e < n ? 6 : 0);break;case e: - s = (n - t) / l + 2;break;case n: - s = (t - e) / l + 4;}s /= 6; - }return { h: s, s: a, l: o }; + o = (i + s) / 2;if (i === s) a = 0, r = 0;else { + var c = i - s;switch (a = o > .5 ? c / (2 - i - s) : c / (i + s), i) {case t: + r = (e - n) / c + (e < n ? 6 : 0);break;case e: + r = (n - t) / c + 2;break;case n: + r = (t - e) / c + 4;}r /= 6; + }return { h: r, s: a, l: o }; }function Jt(t, e, n) { t = zt(t, 255), e = zt(e, 255), n = zt(n, 255);var i = Math.max(t, e, n), - r = Math.min(t, e, n), - s = 0, + s = Math.min(t, e, n), + r = 0, a = i, - o = i - r, - l = 0 === i ? 0 : o / i;if (i === r) s = 0;else { + o = i - s, + c = 0 === i ? 0 : o / i;if (i === s) r = 0;else { switch (i) {case t: - s = (e - n) / o + (e < n ? 6 : 0);break;case e: - s = (n - t) / o + 2;break;case n: - s = (t - e) / o + 4;}s /= 6; - }return { h: s, s: l, v: a }; + r = (e - n) / o + (e < n ? 6 : 0);break;case e: + r = (n - t) / o + 2;break;case n: + r = (t - e) / o + 4;}r /= 6; + }return { h: r, s: c, v: a }; }function Zt(t, e, n, i) { - var r = [Wt(Math.round(t).toString(16)), Wt(Math.round(e).toString(16)), Wt(Math.round(n).toString(16))];return i && r[0].charAt(0) === r[0].charAt(1) && r[1].charAt(0) === r[1].charAt(1) && r[2].charAt(0) === r[2].charAt(1) ? r[0].charAt(0) + r[1].charAt(0) + r[2].charAt(0) : r.join(""); + var s = [Wt(Math.round(t).toString(16)), Wt(Math.round(e).toString(16)), Wt(Math.round(n).toString(16))];return i && s[0].charAt(0) === s[0].charAt(1) && s[1].charAt(0) === s[1].charAt(1) && s[2].charAt(0) === s[2].charAt(1) ? s[0].charAt(0) + s[1].charAt(0) + s[2].charAt(0) : s.join(""); }function Xt(t) { return Kt(t) / 255; }function Kt(t) { @@ -937,34 +937,34 @@ window.navigator.userAgent.match("Trident") && (DOMTokenList.prototype.toggle = var e, n, i, - r = { r: 0, g: 0, b: 0 }, - s = 1, + s = { r: 0, g: 0, b: 0 }, + r = 1, a = null, o = null, - l = null, - c = !1, + c = null, + l = !1, h = !1;return "string" == typeof t && (t = function (t) { - if (0 === (t = t.trim().toLowerCase()).length) return !1;var e = !1;if (Qt[t]) t = Qt[t], e = !0;else if ("transparent" === t) return { r: 0, g: 0, b: 0, a: 0, format: "name" };var n = re.rgb.exec(t);if (n) return { r: n[1], g: n[2], b: n[3] };if (n = re.rgba.exec(t)) return { r: n[1], g: n[2], b: n[3], a: n[4] };if (n = re.hsl.exec(t)) return { h: n[1], s: n[2], l: n[3] };if (n = re.hsla.exec(t)) return { h: n[1], s: n[2], l: n[3], a: n[4] };if (n = re.hsv.exec(t)) return { h: n[1], s: n[2], v: n[3] };if (n = re.hsva.exec(t)) return { h: n[1], s: n[2], v: n[3], a: n[4] };if (n = re.hex8.exec(t)) return { r: Kt(n[1]), g: Kt(n[2]), b: Kt(n[3]), a: Xt(n[4]), format: e ? "name" : "hex8" };if (n = re.hex6.exec(t)) return { r: Kt(n[1]), g: Kt(n[2]), b: Kt(n[3]), format: e ? "name" : "hex" };if (n = re.hex4.exec(t)) return { r: Kt(n[1] + n[1]), g: Kt(n[2] + n[2]), b: Kt(n[3] + n[3]), a: Xt(n[4] + n[4]), format: e ? "name" : "hex8" };if (n = re.hex3.exec(t)) return { r: Kt(n[1] + n[1]), g: Kt(n[2] + n[2]), b: Kt(n[3] + n[3]), format: e ? "name" : "hex" };return !1; - }(t)), "object" == typeof t && (se(t.r) && se(t.g) && se(t.b) ? (e = t.r, n = t.g, i = t.b, r = { r: 255 * zt(e, 255), g: 255 * zt(n, 255), b: 255 * zt(i, 255) }, c = !0, h = "%" === String(t.r).substr(-1) ? "prgb" : "rgb") : se(t.h) && se(t.s) && se(t.v) ? (a = Bt(t.s), o = Bt(t.v), r = function (t, e, n) { + if (0 === (t = t.trim().toLowerCase()).length) return !1;var e = !1;if (Qt[t]) t = Qt[t], e = !0;else if ("transparent" === t) return { r: 0, g: 0, b: 0, a: 0, format: "name" };var n = se.rgb.exec(t);if (n) return { r: n[1], g: n[2], b: n[3] };if (n = se.rgba.exec(t)) return { r: n[1], g: n[2], b: n[3], a: n[4] };if (n = se.hsl.exec(t)) return { h: n[1], s: n[2], l: n[3] };if (n = se.hsla.exec(t)) return { h: n[1], s: n[2], l: n[3], a: n[4] };if (n = se.hsv.exec(t)) return { h: n[1], s: n[2], v: n[3] };if (n = se.hsva.exec(t)) return { h: n[1], s: n[2], v: n[3], a: n[4] };if (n = se.hex8.exec(t)) return { r: Kt(n[1]), g: Kt(n[2]), b: Kt(n[3]), a: Xt(n[4]), format: e ? "name" : "hex8" };if (n = se.hex6.exec(t)) return { r: Kt(n[1]), g: Kt(n[2]), b: Kt(n[3]), format: e ? "name" : "hex" };if (n = se.hex4.exec(t)) return { r: Kt(n[1] + n[1]), g: Kt(n[2] + n[2]), b: Kt(n[3] + n[3]), a: Xt(n[4] + n[4]), format: e ? "name" : "hex8" };if (n = se.hex3.exec(t)) return { r: Kt(n[1] + n[1]), g: Kt(n[2] + n[2]), b: Kt(n[3] + n[3]), format: e ? "name" : "hex" };return !1; + }(t)), "object" == typeof t && (re(t.r) && re(t.g) && re(t.b) ? (e = t.r, n = t.g, i = t.b, s = { r: 255 * zt(e, 255), g: 255 * zt(n, 255), b: 255 * zt(i, 255) }, l = !0, h = "%" === String(t.r).substr(-1) ? "prgb" : "rgb") : re(t.h) && re(t.s) && re(t.v) ? (a = Bt(t.s), o = Bt(t.v), s = function (t, e, n) { t = 6 * zt(t, 360), e = zt(e, 100), n = zt(n, 100);var i = Math.floor(t), - r = t - i, - s = n * (1 - e), - a = n * (1 - r * e), - o = n * (1 - (1 - r) * e), - l = i % 6;return { r: 255 * [n, a, s, s, o, n][l], g: 255 * [o, n, n, a, s, s][l], b: 255 * [s, s, o, n, n, a][l] }; - }(t.h, a, o), c = !0, h = "hsv") : se(t.h) && se(t.s) && se(t.l) && (a = Bt(t.s), l = Bt(t.l), r = function (t, e, n) { - var i, r, s;function a(t, e, n) { + s = t - i, + r = n * (1 - e), + a = n * (1 - s * e), + o = n * (1 - (1 - s) * e), + c = i % 6;return { r: 255 * [n, a, r, r, o, n][c], g: 255 * [o, n, n, a, r, r][c], b: 255 * [r, r, o, n, n, a][c] }; + }(t.h, a, o), l = !0, h = "hsv") : re(t.h) && re(t.s) && re(t.l) && (a = Bt(t.s), c = Bt(t.l), s = function (t, e, n) { + var i, s, r;function a(t, e, n) { return n < 0 && (n += 1), n > 1 && (n -= 1), n < 1 / 6 ? t + 6 * n * (e - t) : n < .5 ? e : n < 2 / 3 ? t + (e - t) * (2 / 3 - n) * 6 : t; - }if (t = zt(t, 360), e = zt(e, 100), n = zt(n, 100), 0 === e) r = n, s = n, i = n;else { + }if (t = zt(t, 360), e = zt(e, 100), n = zt(n, 100), 0 === e) s = n, r = n, i = n;else { var o = n < .5 ? n * (1 + e) : n + e - n * e, - l = 2 * n - o;i = a(l, o, t + 1 / 3), r = a(l, o, t), s = a(l, o, t - 1 / 3); - }return { r: 255 * i, g: 255 * r, b: 255 * s }; - }(t.h, a, l), c = !0, h = "hsl"), Object.prototype.hasOwnProperty.call(t, "a") && (s = t.a)), s = Ut(s), { ok: c, format: t.format || h, r: Math.min(255, Math.max(r.r, 0)), g: Math.min(255, Math.max(r.g, 0)), b: Math.min(255, Math.max(r.b, 0)), a: s }; + c = 2 * n - o;i = a(c, o, t + 1 / 3), s = a(c, o, t), r = a(c, o, t - 1 / 3); + }return { r: 255 * i, g: 255 * s, b: 255 * r }; + }(t.h, a, c), l = !0, h = "hsl"), Object.prototype.hasOwnProperty.call(t, "a") && (r = t.a)), r = Ut(r), { ok: l, format: t.format || h, r: Math.min(255, Math.max(s.r, 0)), g: Math.min(255, Math.max(s.g, 0)), b: Math.min(255, Math.max(s.b, 0)), a: r }; }var ee = "(?:[-\\+]?\\d*\\.\\d+%?)|(?:[-\\+]?\\d+%?)", ne = "[\\s|\\(]+(" + ee + ")[,|\\s]+(" + ee + ")[,|\\s]+(" + ee + ")\\s*\\)?", ie = "[\\s|\\(]+(" + ee + ")[,|\\s]+(" + ee + ")[,|\\s]+(" + ee + ")[,|\\s]+(" + ee + ")\\s*\\)?", - re = { CSS_UNIT: new RegExp(ee), rgb: new RegExp("rgb" + ne), rgba: new RegExp("rgba" + ie), hsl: new RegExp("hsl" + ne), hsla: new RegExp("hsla" + ie), hsv: new RegExp("hsv" + ne), hsva: new RegExp("hsva" + ie), hex3: /^#?([0-9a-fA-F]{1})([0-9a-fA-F]{1})([0-9a-fA-F]{1})$/, hex6: /^#?([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})$/, hex4: /^#?([0-9a-fA-F]{1})([0-9a-fA-F]{1})([0-9a-fA-F]{1})([0-9a-fA-F]{1})$/, hex8: /^#?([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})$/ };function se(t) { - return Boolean(re.CSS_UNIT.exec(String(t))); + se = { CSS_UNIT: new RegExp(ee), rgb: new RegExp("rgb" + ne), rgba: new RegExp("rgba" + ie), hsl: new RegExp("hsl" + ne), hsla: new RegExp("hsla" + ie), hsv: new RegExp("hsv" + ne), hsva: new RegExp("hsva" + ie), hex3: /^#?([0-9a-fA-F]{1})([0-9a-fA-F]{1})([0-9a-fA-F]{1})$/, hex6: /^#?([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})$/, hex4: /^#?([0-9a-fA-F]{1})([0-9a-fA-F]{1})([0-9a-fA-F]{1})([0-9a-fA-F]{1})$/, hex8: /^#?([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})$/ };function re(t) { + return Boolean(se.CSS_UNIT.exec(String(t))); }var ae = function () { function t(e, n) { if (void 0 === e && (e = ""), void 0 === n && (n = {}), e instanceof t) return e;this.originalInput = e;var i = te(e);this.originalInput = e, this.r = i.r, this.g = i.g, this.b = i.b, this.a = i.a, this.roundA = Math.round(100 * this.a) / 100, this.format = n.format || i.format, this.gradientType = n.gradientType, this.r < 1 && (this.r = Math.round(this.r)), this.g < 1 && (this.g = Math.round(this.g)), this.b < 1 && (this.b = Math.round(this.b)), this.isValid = i.ok; @@ -1002,9 +1002,9 @@ window.navigator.userAgent.match("Trident") && (DOMTokenList.prototype.toggle = }, t.prototype.toHexString = function (t) { return void 0 === t && (t = !1), "#" + this.toHex(t); }, t.prototype.toHex8 = function (t) { - return void 0 === t && (t = !1), function (t, e, n, i, r) { - var s, - a = [Wt(Math.round(t).toString(16)), Wt(Math.round(e).toString(16)), Wt(Math.round(n).toString(16)), Wt((s = i, Math.round(255 * parseFloat(s)).toString(16)))];return r && a[0].charAt(0) === a[0].charAt(1) && a[1].charAt(0) === a[1].charAt(1) && a[2].charAt(0) === a[2].charAt(1) && a[3].charAt(0) === a[3].charAt(1) ? a[0].charAt(0) + a[1].charAt(0) + a[2].charAt(0) + a[3].charAt(0) : a.join(""); + return void 0 === t && (t = !1), function (t, e, n, i, s) { + var r, + a = [Wt(Math.round(t).toString(16)), Wt(Math.round(e).toString(16)), Wt(Math.round(n).toString(16)), Wt((r = i, Math.round(255 * parseFloat(r)).toString(16)))];return s && a[0].charAt(0) === a[0].charAt(1) && a[1].charAt(0) === a[1].charAt(1) && a[2].charAt(0) === a[2].charAt(1) && a[3].charAt(0) === a[3].charAt(1) ? a[0].charAt(0) + a[1].charAt(0) + a[2].charAt(0) + a[3].charAt(0) : a.join(""); }(this.r, this.g, this.b, this.a, t); }, t.prototype.toHex8String = function (t) { return void 0 === t && (t = !1), "#" + this.toHex8(t); @@ -1052,16 +1052,16 @@ window.navigator.userAgent.match("Trident") && (DOMTokenList.prototype.toggle = i = (n.h + e) % 360;return n.h = i < 0 ? 360 + i : i, new t(n); }, t.prototype.mix = function (e, n) { void 0 === n && (n = 50);var i = this.toRgb(), - r = new t(e).toRgb(), - s = n / 100;return new t({ r: (r.r - i.r) * s + i.r, g: (r.g - i.g) * s + i.g, b: (r.b - i.b) * s + i.b, a: (r.a - i.a) * s + i.a }); + s = new t(e).toRgb(), + r = n / 100;return new t({ r: (s.r - i.r) * r + i.r, g: (s.g - i.g) * r + i.g, b: (s.b - i.b) * r + i.b, a: (s.a - i.a) * r + i.a }); }, t.prototype.analogous = function (e, n) { void 0 === e && (e = 6), void 0 === n && (n = 30);var i = this.toHsl(), - r = 360 / n, - s = [this];for (i.h = (i.h - (r * e >> 1) + 720) % 360; --e;) i.h = (i.h + r) % 360, s.push(new t(i));return s; + s = 360 / n, + r = [this];for (i.h = (i.h - (s * e >> 1) + 720) % 360; --e;) i.h = (i.h + s) % 360, r.push(new t(i));return r; }, t.prototype.complement = function () { var e = this.toHsl();return e.h = (e.h + 180) % 360, new t(e); }, t.prototype.monochromatic = function (e) { - void 0 === e && (e = 6);for (var n = this.toHsv(), i = n.h, r = n.s, s = n.v, a = [], o = 1 / e; e--;) a.push(new t({ h: i, s: r, v: s })), s = (s + o) % 1;return a; + void 0 === e && (e = 6);for (var n = this.toHsv(), i = n.h, s = n.s, r = n.v, a = [], o = 1 / e; e--;) a.push(new t({ h: i, s: s, v: r })), r = (r + o) % 1;return a; }, t.prototype.splitcomplement = function () { var e = this.toHsl(), n = e.h;return [this, new t({ h: (n + 72) % 360, s: e.s, l: e.l }), new t({ h: (n + 216) % 360, s: e.s, l: e.l })]; @@ -1070,24 +1070,24 @@ window.navigator.userAgent.match("Trident") && (DOMTokenList.prototype.toggle = }, t.prototype.tetrad = function () { return this.polyad(4); }, t.prototype.polyad = function (e) { - for (var n = this.toHsl(), i = n.h, r = [this], s = 360 / e, a = 1; a < e; a++) r.push(new t({ h: (i + a * s) % 360, s: n.s, l: n.l }));return r; + for (var n = this.toHsl(), i = n.h, s = [this], r = 360 / e, a = 1; a < e; a++) s.push(new t({ h: (i + a * r) % 360, s: n.s, l: n.l }));return s; }, t.prototype.equals = function (e) { return this.toRgbString() === new t(e).toRgbString(); }, t; }();function oe(t, e) { return void 0 === t && (t = ""), void 0 === e && (e = {}), new ae(t, e); -}function le(t) { - return t.substr(0, t.indexOf(".")); }function ce(t) { + return t.substr(0, t.indexOf(".")); +}function le(t) { return "var" === t.substring(0, 3) ? window.getComputedStyle(document.documentElement).getPropertyValue(t.substring(4).slice(0, -1)).trim() : t; }function he(t, e) { - const n = new ae(ce(t));if (n.isValid) { + const n = new ae(le(t));if (n.isValid) { const t = n.mix("black", 100 - e).toString();if (t) return t; }return t; }function de(...t) { const e = t => t && "object" == typeof t;return t.reduce((t, n) => (Object.keys(n).forEach(i => { - const r = t[i], - s = n[i];Array.isArray(r) && Array.isArray(s) ? t[i] = r.concat(...s) : e(r) && e(s) ? t[i] = de(r, s) : t[i] = s; + const s = t[i], + r = n[i];Array.isArray(s) && Array.isArray(r) ? t[i] = s.concat(...r) : e(s) && e(r) ? t[i] = de(s, r) : t[i] = r; }), t), {}); }function ue(t, e) { let n = [];return t && t.forEach(t => { @@ -1097,8 +1097,8 @@ window.navigator.userAgent.match("Trident") && (DOMTokenList.prototype.toggle = }), e && (n = n.concat(e.filter(e => !t || !t.find(t => !(!t.id || !e.id) && t.id == e.id)))), n; }const pe = ((t, ...e) => { const n = e.reduce((e, n, i) => e + (t => { - if (t instanceof rt) return t.cssText;throw new Error(`Value passed to 'css' function must be a 'css' function result: ${t}. Use 'unsafeCSS' to pass non-literal values, but\n take care to ensure page security.`); - })(n) + t[i + 1], t[0]);return new rt(n, it); + if (t instanceof at) return t.cssText;if ("number" == typeof t) return t;throw new Error(`Value passed to 'css' function must be a 'css' function result: ${t}. Use 'unsafeCSS' to pass non-literal values, but\n take care to ensure page security.`); + })(n) + t[i + 1], t[0]);return new at(n, rt); })` ha-card { cursor: pointer; @@ -1479,27 +1479,26 @@ window.navigator.userAgent.match("Trident") && (DOMTokenList.prototype.toggle = height: 100%; } } -`;let fe = class extends at { +`;let fe = class extends ct { disconnectedCallback() { super.disconnectedCallback(), this._clearInterval(); }connectedCallback() { - if (super.connectedCallback(), this.config && this.config.entity && "timer" === le(this.config.entity)) { + if (super.connectedCallback(), this.config && this.config.entity && "timer" === ce(this.config.entity)) { const t = this.hass.states[this.config.entity];this._startInterval(t); } }static get styles() { return pe; }render() { - return this.config && this.hass ? this._cardHtml() : R``; + return this.config && this.hass ? this._cardHtml() : $``; }shouldUpdate(t) { const e = this.config.entity ? this.hass.states[this.config.entity] : void 0, - n = this._getMatchingConfigState(e), - i = !!(n && (this.config.show_label && n.label_template || this.config.show_entity_picture && n.entity_picture_template || this.config.show_name && n.name_template) || this.config.show_label && this.config.label_template || this.config.show_name && this.config.name_template || this.config.show_entity_picture && this.config.entity_picture_template || this.config.state && this.config.state.find(t => "template" === t.operator) || t.has("_timeRemaining"));return function (t, e, n) { + n = (this._getMatchingConfigState(e), !!(this._hasTemplate || this.config.state && this.config.state.find(t => "template" === t.operator) || t.has("_timeRemaining")));return function (t, e, n) { if (e.has("config") || n) return !0;if (t.config.entity) { const n = e.get("hass");return !n || n.states[t.config.entity] !== t.hass.states[t.config.entity]; }return !1; - }(this, t, i); + }(this, t, n); }updated(t) { - if (super.updated(t), this.config && this.config.entity && "timer" === le(this.config.entity) && t.has("hass")) { + if (super.updated(t), this.config && this.config.entity && "timer" === ce(this.config.entity) && t.has("hass")) { const e = this.hass.states[this.config.entity], n = t.get("hass");(n ? n.states[this.config.entity] : void 0) !== e ? this._startInterval(e) : e || this._clearInterval(); } @@ -1509,7 +1508,7 @@ window.navigator.userAgent.match("Trident") && (DOMTokenList.prototype.toggle = this._clearInterval(), this._calculateRemaining(t), "active" === t.state && (this._interval = window.setInterval(() => this._calculateRemaining(t), 1e3)); }_calculateRemaining(t) { this._timeRemaining = function (t) { - var e = Tt(t.attributes.remaining);if ("active" === t.state) { + var e = Nt(t.attributes.remaining);if ("active" === t.state) { var n = new Date().getTime(), i = new Date(t.last_changed).getTime();e = Math.max(e - (n - i) / 1e3, 0); }return e; @@ -1518,24 +1517,26 @@ window.navigator.userAgent.match("Trident") && (DOMTokenList.prototype.toggle = if (t) return function (t) { var e = Math.floor(t / 3600), n = Math.floor(t % 3600 / 60), - i = Math.floor(t % 3600 % 60);return e > 0 ? e + ":" + Nt(n) + ":" + Nt(i) : n > 0 ? n + ":" + Nt(i) : i > 0 ? "" + i : null; - }(this._timeRemaining || Tt(t.attributes.duration)); + i = Math.floor(t % 3600 % 60);return e > 0 ? e + ":" + At(n) + ":" + At(i) : n > 0 ? n + ":" + At(i) : i > 0 ? "" + i : null; + }(this._timeRemaining || Nt(t.attributes.duration)); }_getMatchingConfigState(t) { if (!this.config.state) return;const e = this.config.state.find(t => "template" === t.operator);if (!t && !e) return;let n;const i = this.config.state.find(e => { - if (!e.operator) return t && e.value == t.state;switch (e.operator) {case "==": - return t && t.state == e.value;case "<=": - return t && t.state <= e.value;case "<": - return t && t.state < e.value;case ">=": - return t && t.state >= e.value;case ">": - return t && t.state > e.value;case "!=": - return t && t.state != e.value;case "regex": - return !(!t || !t.state.match(e.value));case "template": - return this._evalTemplate(t, e.value);case "default": + if (!e.operator) return t && this._getTemplateOrString(t, e.value) == t.state;switch (e.operator) {case "==": + return t && t.state == this._getTemplateOrString(t, e.value);case "<=": + return t && t.state <= this._getTemplateOrString(t, e.value);case "<": + return t && t.state < this._getTemplateOrString(t, e.value);case ">=": + return t && t.state >= this._getTemplateOrString(t, e.value);case ">": + return t && t.state > this._getTemplateOrString(t, e.value);case "!=": + return t && t.state != this._getTemplateOrString(t, e.value);case "regex": + return !(!t || !t.state.match(this._getTemplateOrString(t, e.value)));case "template": + return this._getTemplateOrString(t, e.value);case "default": return n = e, !1;default: return !1;} });return !i && n ? n : i; }_evalTemplate(t, e) { return new Function("states", "entity", "user", "hass", `'use strict'; ${e}`).call(this, this.hass.states, t, this.hass.user, this.hass); + }_getTemplateOrString(t, e) { + if (!e) return;if ("number" == typeof e) return e;const n = e.trim();return "[[[" === n.substring(0, 3) && "]]]" === n.slice(-3) ? this._evalTemplate(t, n.slice(3, -3)) : e; }_getDefaultColorForState(t) { switch (t.state) {case "on": return this.config.color_on;case "off": @@ -1544,16 +1545,16 @@ window.navigator.userAgent.match("Trident") && (DOMTokenList.prototype.toggle = }_getColorForLightEntity(t, e) { let n = this.config.default_color;return t && (t.attributes.rgb_color ? (n = `rgb(${t.attributes.rgb_color.join(",")})`, t.attributes.brightness && (n = he(n, (t.attributes.brightness + 245) / 5))) : e && t.attributes.color_temp && t.attributes.min_mireds && t.attributes.max_mireds ? (n = function (t, e, n) { const i = new ae("rgb(255, 160, 0)"), - r = new ae("rgb(166, 209, 255)"), - s = new ae("white"), - a = (t - e) / (n - e) * 100;return a < 50 ? oe(r).mix(s, 2 * a).toRgbString() : oe(s).mix(i, 2 * (a - 50)).toRgbString(); + s = new ae("rgb(166, 209, 255)"), + r = new ae("white"), + a = (t - e) / (n - e) * 100;return a < 50 ? oe(s).mix(r, 2 * a).toRgbString() : oe(r).mix(i, 2 * (a - 50)).toRgbString(); }(t.attributes.color_temp, t.attributes.min_mireds, t.attributes.max_mireds), t.attributes.brightness && (n = he(n, (t.attributes.brightness + 245) / 5))) : n = t.attributes.brightness ? he(this._getDefaultColorForState(t), (t.attributes.brightness + 245) / 5) : this._getDefaultColorForState(t)), n; }_buildCssColorAttribute(t, e) { let n, i = "";return e && e.color ? i = e.color : "auto" !== this.config.color && t && "off" === t.state ? i = this.config.color_off : this.config.color && (i = this.config.color), n = "auto" == i || "auto-no-temperature" == i ? this._getColorForLightEntity(t, "auto-no-temperature" !== i) : i || (t ? this._getDefaultColorForState(t) : this.config.default_color); }_buildIcon(t, e) { if (!this.config.show_icon) return;let n;return e && e.icon ? n = e.icon : this.config.icon ? n = this.config.icon : t && t.attributes && (n = t.attributes.icon ? t.attributes.icon : function (t, e) { - if (t in Dt) return Dt[t];switch (t) {case "alarm_control_panel": + if (t in Ht) return Ht[t];switch (t) {case "alarm_control_panel": switch (e) {case "armed_home": return "hass:bell-plus";case "armed_night": return "hass:bell-sleep";case "disarmed": @@ -1569,47 +1570,66 @@ window.navigator.userAgent.match("Trident") && (DOMTokenList.prototype.toggle = return "hass:sleep";case "initializing": return "hass:timer-sand";default: return "hass:z-wave";}default: - return console.warn("Unable to find icon for domain " + t + " (" + e + ")"), Rt;} - }(le(t.entity_id), t.state)), n; + return console.warn("Unable to find icon for domain " + t + " (" + e + ")"), Ot;} + }(ce(t.entity_id), t.state)), this._getTemplateOrString(t, n); }_buildEntityPicture(t, e) { - if (!this.config.show_entity_picture || !t && !e && !this.config.entity_picture) return;let n, i;return (i = e && e.entity_picture_template ? e.entity_picture_template : this.config.entity_picture_template) ? this._evalTemplate(t, i) : (e && e.entity_picture ? n = e.entity_picture : this.config.entity_picture ? n = this.config.entity_picture : t && (n = t.attributes && t.attributes.entity_picture ? t.attributes.entity_picture : void 0), n); - }_buildStyleGeneric(t, e) { - let n = {};if (this.config.styles && this.config.styles[e] && (n = Object.assign(n, ...this.config.styles[e])), t && t.styles && t.styles[e]) { - let i = {};i = Object.assign(i, ...t.styles[e]), n = Object.assign({}, n, i); - }return n; + if (!this.config.show_entity_picture || !t && !e && !this.config.entity_picture) return;let n;return e && e.entity_picture ? n = e.entity_picture : this.config.entity_picture ? n = this.config.entity_picture : t && (n = t.attributes && t.attributes.entity_picture ? t.attributes.entity_picture : void 0), this._getTemplateOrString(t, n); + }_buildStyleGeneric(t, e, n) { + let i = {};if (this.config.styles && this.config.styles[n] && (i = Object.assign(i, ...this.config.styles[n])), e && e.styles && e.styles[n]) { + let t = {};t = Object.assign(t, ...e.styles[n]), i = Object.assign({}, i, t); + }return Object.keys(i).forEach(e => { + i[e] = this._getTemplateOrString(t, i[e]); + }), i; + }_buildCustomStyleGeneric(t, e, n) { + let i = {};if (this.config.styles && this.config.styles.custom_fields && this.config.styles.custom_fields[n] && (i = Object.assign(i, ...this.config.styles.custom_fields[n])), e && e.styles && e.styles.custom_fields && e.styles.custom_fields[n]) { + let t = {};t = Object.assign(t, ...e.styles.custom_fields[n]), i = Object.assign({}, i, t); + }return Object.keys(i).forEach(e => { + i[e] = this._getTemplateOrString(t, i[e]); + }), i; }_buildName(t, e) { - if (!1 === this.config.show_name) return;let n, i;return (i = e && e.name_template ? e.name_template : this.config.name_template) ? this._evalTemplate(t, i) : (e && e.name ? n = e.name : this.config.name ? n = this.config.name : t && (n = t.attributes && t.attributes.friendly_name ? t.attributes.friendly_name : (r = t.entity_id).substr(r.indexOf(".") + 1)), n);var r; + if (!1 === this.config.show_name) return;let n;var i;return e && e.name ? n = e.name : this.config.name ? n = this.config.name : t && (n = t.attributes && t.attributes.friendly_name ? t.attributes.friendly_name : (i = t.entity_id).substr(i.indexOf(".") + 1)), this._getTemplateOrString(t, n); }_buildStateString(t) { let e;if (this.config.show_state && t && t.state) { const n = ((t, e) => { - let n;const i = le(e.entity_id);return "binary_sensor" === i ? (e.attributes.device_class && (n = t(`state.${i}.${e.attributes.device_class}.${e.state}`)), n || (n = t(`state.${i}.default.${e.state}`))) : n = e.attributes.unit_of_measurement && !["unknown", "unavailable"].includes(e.state) ? e.state : "zwave" === i ? ["initializing", "dead"].includes(e.state) ? t(`state.zwave.query_stage.${e.state}`, "query_stage", e.attributes.query_stage) : t(`state.zwave.default.${e.state}`) : t(`state.${i}.${e.state}`), n || (n = t(`state.default.${e.state}`) || t(`component.${i}.state.${e.state}`) || e.state), n; + let n;const i = ce(e.entity_id);return "binary_sensor" === i ? (e.attributes.device_class && (n = t(`state.${i}.${e.attributes.device_class}.${e.state}`)), n || (n = t(`state.${i}.default.${e.state}`))) : n = e.attributes.unit_of_measurement && !["unknown", "unavailable"].includes(e.state) ? e.state : "zwave" === i ? ["initializing", "dead"].includes(e.state) ? t(`state.zwave.query_stage.${e.state}`, "query_stage", e.attributes.query_stage) : t(`state.zwave.default.${e.state}`) : t(`state.${i}.${e.state}`), n || (n = t(`state.default.${e.state}`) || t(`component.${i}.state.${e.state}`) || e.state), n; })(this.hass.localize, t), - i = this._buildUnits(t);i ? e = `${t.state} ${i}` : "timer" === le(t.entity_id) ? "idle" === t.state || 0 === this._timeRemaining ? e = n : (e = this._computeTimeDisplay(t), "paused" === t.state && (e += ` (${n})`)) : e = n; + i = this._buildUnits(t);i ? e = `${t.state} ${i}` : "timer" === ce(t.entity_id) ? "idle" === t.state || 0 === this._timeRemaining ? e = n : (e = this._computeTimeDisplay(t), "paused" === t.state && (e += ` (${n})`)) : e = n; }return e; }_buildUnits(t) { let e;return t && this.config.show_units && (e = t.attributes && t.attributes.unit_of_measurement && !this.config.units ? t.attributes.unit_of_measurement : this.config.units ? this.config.units : void 0), e; }_buildLastChanged(t, e) { - return this.config.show_last_changed && t ? R` + return this.config.show_last_changed && t ? $` ` : void 0; }_buildLabel(t, e) { - if (!this.config.show_label) return;let n, i;return (i = e && e.label_template ? e.label_template : this.config.label_template) ? this._evalTemplate(t, i) : n = e && e.label ? e.label : this.config.label; + if (!this.config.show_label) return;let n;return n = e && e.label ? e.label : this.config.label, this._getTemplateOrString(t, n); + }_buildCustomFields(t, e) { + let n = $``;const i = {};return this.config.custom_fields && Object.keys(this.config.custom_fields).forEach(e => { + const n = this.config.custom_fields[e];i[e] = this._getTemplateOrString(t, n); + }), e && e.custom_fields && Object.keys(e.custom_fields).forEach(n => { + const s = e.custom_fields[n];i[n] = this._getTemplateOrString(t, s); + }), Object.keys(i).forEach(s => { + if (null != i[s]) { + const r = Object.assign({}, this._buildCustomStyleGeneric(t, e, s), { "grid-area": s });n = $`${n} +
${ut(i[s])}
`; + } + }), n; }_isClickable(t) { let e = !0;if ("toggle" === this.config.tap_action.action && "none" === this.config.hold_action.action && "none" === this.config.dbltap_action.action || "toggle" === this.config.hold_action.action && "none" === this.config.tap_action.action && "none" === this.config.dbltap_action.action || "toggle" === this.config.dbltap_action.action && "none" === this.config.tap_action.action && "none" === this.config.hold_action.action) { - if (t) switch (le(t.entity_id)) {case "sensor":case "binary_sensor":case "device_tracker": + if (t) switch (ce(t.entity_id)) {case "sensor":case "binary_sensor":case "device_tracker": e = !1;break;default: e = !0;} else e = !1; } else e = "none" != this.config.tap_action.action || "none" != this.config.hold_action.action || "none" != this.config.dbltap_action.action;return e; }_rotate(t) { return !(!t || !t.spin); }_blankCardColoredHtml(t) { - const e = Object.assign({ background: "none", "box-shadow": "none" }, t);return R` - + const e = Object.assign({ background: "none", "box-shadow": "none" }, t);return $` +
`; @@ -1617,81 +1637,82 @@ window.navigator.userAgent.match("Trident") && (DOMTokenList.prototype.toggle = const t = this.config.entity ? this.hass.states[this.config.entity] : void 0, e = this._getMatchingConfigState(t), n = this._buildCssColorAttribute(t, e);let i = n, - r = {}, s = {}, - a = {};const o = this._buildStyleGeneric(e, "lock"), - l = this._buildStyleGeneric(e, "card"), - c = { "button-card-main": !0, disabled: !this._isClickable(t) };switch (l.width && (this.style.setProperty("flex", "0 0 auto"), this.style.setProperty("max-width", "fit-content")), this.config.color_type) {case "blank-card": - return this._blankCardColoredHtml(l);case "card":case "label-card": + r = {};const a = {}, + o = this._buildStyleGeneric(t, e, "lock"), + c = this._buildStyleGeneric(t, e, "card"), + l = { "button-card-main": !0, disabled: !this._isClickable(t) };switch (c.width && (this.style.setProperty("flex", "0 0 auto"), this.style.setProperty("max-width", "fit-content")), this.config.color_type) {case "blank-card": + return this._blankCardColoredHtml(c);case "card":case "label-card": { const t = function (t) { - const e = new ae(ce(t));return e.isValid && e.getLuminance() > .5 ? "rgb(62, 62, 62)" : "rgb(234, 234, 234)"; - }(n);r.color = t, s.color = t, r["background-color"] = n, r = Object.assign({}, r, l), i = "inherit";break; + const e = new ae(le(t));return e.isValid && e.getLuminance() > .5 ? "rgb(62, 62, 62)" : "rgb(234, 234, 234)"; + }(n);s.color = t, r.color = t, s["background-color"] = n, s = Object.assign({}, s, c), i = "inherit";break; }default: - r = l;}return this.config.aspect_ratio ? (a["--aspect-ratio"] = this.config.aspect_ratio, r.position = "absolute") : a.display = "inline", this.style.setProperty("--button-card-light-color", this._getColorForLightEntity(t, !0)), this.style.setProperty("--button-card-light-color-no-temperature", this._getColorForLightEntity(t, !1)), s = Object.assign({}, s, o), R` -
+ s = c;}return this.config.aspect_ratio ? (a["--aspect-ratio"] = this.config.aspect_ratio, s.position = "absolute") : a.display = "inline", this.style.setProperty("--button-card-light-color", this._getColorForLightEntity(t, !0)), this.style.setProperty("--button-card-light-color-no-temperature", this._getColorForLightEntity(t, !1)), r = Object.assign({}, r, o), $` +
- ${this._getLock(s)} + ${this._getLock(r)} ${this._buttonContent(t, e, i)} - ${this.config.lock ? "" : R``} + ${this.config.lock ? "" : $``}
`; }_getLock(t) { - return this.config.lock ? R` -
+ return this.config.lock ? $` +
- ` : R``; + ` : $``; }_buttonContent(t, e, n) { const i = this._buildName(t, e), - r = this._buildStateString(t), - s = function (t, e) { + s = this._buildStateString(t), + r = function (t, e) { if (!t && !e) return;let n;return n = e ? t ? `${t}: ${e}` : e : t; - }(i, r);switch (this.config.layout) {case "icon_name_state":case "name_state": - return this._gridHtml(t, e, this.config.layout, n, s, void 0);default: - return this._gridHtml(t, e, this.config.layout, n, i, r);} - }_gridHtml(t, e, n, i, r, s) { + }(i, s);switch (this.config.layout) {case "icon_name_state":case "name_state": + return this._gridHtml(t, e, this.config.layout, n, r, void 0);default: + return this._gridHtml(t, e, this.config.layout, n, i, s);} + }_gridHtml(t, e, n, i, s, r) { const a = this._getIconHtml(t, e, i), o = [n], - l = this._buildLabel(t, e), - c = this._buildStyleGeneric(e, "name"), - h = this._buildStyleGeneric(e, "state"), - d = this._buildStyleGeneric(e, "label"), + c = this._buildLabel(t, e), + l = this._buildStyleGeneric(t, e, "name"), + h = this._buildStyleGeneric(t, e, "state"), + d = this._buildStyleGeneric(t, e, "label"), u = this._buildLastChanged(t, d), - p = this._buildStyleGeneric(e, "grid");return a || o.push("no-icon"), r || o.push("no-name"), s || o.push("no-state"), l || u || o.push("no-label"), R` -
+ p = this._buildStyleGeneric(t, e, "grid");return a || o.push("no-icon"), s || o.push("no-name"), r || o.push("no-state"), c || u || o.push("no-label"), $` +
${a || ""} - ${r ? R`
${dt(r)}
` : ""} - ${s ? R`
${s}
` : ""} - ${l && !u ? R`
${dt(l)}
` : ""} + ${s ? $`
${ut(s)}
` : ""} + ${r ? $`
${r}
` : ""} + ${c && !u ? $`
${ut(c)}
` : ""} ${u || ""} + ${this._buildCustomFields(t, e)}
`; }_getIconHtml(t, e, n) { const i = this._buildIcon(t, e), - r = this._buildEntityPicture(t, e), - s = this._buildStyleGeneric(e, "entity_picture"), - a = this._buildStyleGeneric(e, "icon"), - o = this._buildStyleGeneric(e, "img_cell"), - l = this._buildStyleGeneric(e, "card"), - c = Object.assign({ color: n, width: this.config.size, position: this.config.aspect_ratio || l.height ? "absolute" : "relative" }, a), - h = Object.assign({}, c, s);return i || r ? R` -
- ${i && !r ? R` + ${i && !s ? $`` : ""} - ${r ? R`` : ""}
` : void 0; @@ -1702,29 +1723,37 @@ window.navigator.userAgent.match("Trident") && (DOMTokenList.prototype.toggle = }return null; }();let n = Object.assign({}, t), i = n.template, - r = t.state;for (; i && e.config.button_card_templates && e.config.button_card_templates[i];) n = de(e.config.button_card_templates[i], n), r = ue(e.config.button_card_templates[i].state, r), i = e.config.button_card_templates[i].template;n.state = r, this.config = Object.assign({ tap_action: { action: "toggle" }, hold_action: { action: "none" }, dbltap_action: { action: "none" }, layout: "vertical", size: "40%", color_type: "icon", show_name: !0, show_state: !1, show_icon: !0, show_units: !0, show_label: !1, show_entity_picture: !1 }, n), this.config.default_color = "var(--primary-text-color)", "icon" !== this.config.color_type ? this.config.color_off = "var(--paper-card-background-color)" : this.config.color_off = "var(--paper-item-icon-color)", this.config.color_on = "var(--paper-item-icon-active-color)"; + s = t.state;for (; i && e.config.button_card_templates && e.config.button_card_templates[i];) n = de(e.config.button_card_templates[i], n), s = ue(e.config.button_card_templates[i].state, s), i = e.config.button_card_templates[i].template;n.state = s, this.config = Object.assign({ tap_action: { action: "toggle" }, hold_action: { action: "none" }, dbltap_action: { action: "none" }, layout: "vertical", size: "40%", color_type: "icon", show_name: !0, show_state: !1, show_icon: !0, show_units: !0, show_label: !1, show_entity_picture: !1 }, n), this.config.default_color = "var(--primary-text-color)", "icon" !== this.config.color_type ? this.config.color_off = "var(--paper-card-background-color)" : this.config.color_off = "var(--paper-item-icon-color)", this.config.color_on = "var(--paper-item-icon-active-color)";const r = JSON.stringify(this.config), + a = new RegExp("\\[\\[\\[.*\\]\\]\\]", "gm");this._hasTemplate = !!r.match(a); }getCardSize() { return 3; + }_evalActions(t, e) { + const n = this.config.entity ? this.hass.states[this.config.entity] : void 0, + i = JSON.parse(JSON.stringify(t));return Object.keys(i[e]).forEach(t => { + "service_data" === t ? Object.keys(i[e].service_data).forEach(t => { + i[e].service_data[t] = this._getTemplateOrString(n, i[e].service_data[t]); + }) : i[e][t] = this._getTemplateOrString(n, i[e][t]); + }), i; }_handleTap(t) { - if (this.config.confirmation && !window.confirm(this.config.confirmation)) return;const e = t.target.config;Lt(this, this.hass, e, !1, !1); + if (this.config.confirmation && !window.confirm(this.config.confirmation)) return;const e = t.target.config;jt(this, this.hass, this._evalActions(e, "tap_action"), !1, !1); }_handleHold(t) { - if (this.config.confirmation && !window.confirm(this.config.confirmation)) return;const e = t.target.config;Lt(this, this.hass, e, !0, !1); + if (this.config.confirmation && !window.confirm(this.config.confirmation)) return;const e = t.target.config;jt(this, this.hass, this._evalActions(e, "hold_action"), !0, !1); }_handleDblTap(t) { - if (this.config.confirmation && !window.confirm(this.config.confirmation)) return;const e = t.target.config;Lt(this, this.hass, e, !1, !0); + if (this.config.confirmation && !window.confirm(this.config.confirmation)) return;const e = t.target.config;jt(this, this.hass, this._evalActions(e, "dbltap_action"), !1, !0); }_handleLock(t) { if (t.stopPropagation(), this.config.unlock_users) { if (!this.hass.user.name) return;if (this.config.unlock_users.indexOf(this.hass.user.name) < 0) return; }const e = this.shadowRoot.getElementById("overlay"), n = this.shadowRoot.getElementById("card");e.style.setProperty("pointer-events", "none");const i = document.createElement("paper-ripple"), - r = this.shadowRoot.getElementById("lock");if (r) { - n.appendChild(i);const t = document.createAttribute("icon");t.value = "mdi:lock-open-outline", r.attributes.setNamedItem(t), r.classList.add("fadeOut"); + s = this.shadowRoot.getElementById("lock");if (s) { + n.appendChild(i);const t = document.createAttribute("icon");t.value = "mdi:lock-open-outline", s.attributes.setNamedItem(t), s.classList.add("fadeOut"); }window.setTimeout(() => { - if (e.style.setProperty("pointer-events", ""), r) { - r.classList.remove("fadeOut");const t = document.createAttribute("icon");t.value = "mdi:lock-outline", r.attributes.setNamedItem(t), n.removeChild(i); + if (e.style.setProperty("pointer-events", ""), s) { + s.classList.remove("fadeOut");const t = document.createAttribute("icon");t.value = "mdi:lock-outline", s.attributes.setNamedItem(t), n.removeChild(i); } }, 5e3); } -};t([et()], fe.prototype, "hass", void 0), t([et()], fe.prototype, "config", void 0), t([et()], fe.prototype, "_timeRemaining", void 0), fe = t([(t => e => "function" == typeof e ? ((t, e) => (window.customElements.define(t, e), e))(t, e) : ((t, e) => { +};t([it()], fe.prototype, "hass", void 0), t([it()], fe.prototype, "config", void 0), t([it()], fe.prototype, "_timeRemaining", void 0), t([it()], fe.prototype, "_hasTemplate", void 0), fe = t([(t => e => "function" == typeof e ? ((t, e) => (window.customElements.define(t, e), e))(t, e) : ((t, e) => { const { kind: n, elements: i } = e;return { kind: n, elements: i, finisher(e) { window.customElements.define(t, e); } }; diff --git a/examples/custom_fields_1.gif b/examples/custom_fields_1.gif new file mode 100644 index 0000000000000000000000000000000000000000..a27197ff385ce2819a7480d849fe37cb051538ae GIT binary patch literal 9627 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 Y5ft=~Ci_qI{{M6Tcct{dSWk`r2ELb`=Kufz literal 0 HcmV?d00001 diff --git a/examples/custom_fields_2.png b/examples/custom_fields_2.png new file mode 100644 index 0000000000000000000000000000000000000000..f73edac4e79d04e51eea69c55c3b809d3ee2f28d GIT binary patch literal 13222 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 Y13>NDGJY&l7ytkO07*qoM6N<$f>z{LeE=0.5 0", - "rimraf": "2" - } + "dev": true }, "gauge": { "version": "2.7.4", @@ -4734,7 +4991,7 @@ } }, "glob": { - "version": "7.1.3", + "version": "7.1.4", "bundled": true, "dev": true, "requires": { @@ -4780,7 +5037,7 @@ } }, "graceful-fs": { - "version": "4.1.15", + "version": "4.2.0", "bundled": true, "dev": true }, @@ -4798,11 +5055,24 @@ "har-schema": "^2.0.0" } }, + "has": { + "version": "1.0.3", + "bundled": true, + "dev": true, + "requires": { + "function-bind": "^1.1.1" + } + }, "has-flag": { "version": "3.0.0", "bundled": true, "dev": true }, + "has-symbols": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, "has-unicode": { "version": "2.0.1", "bundled": true, @@ -4895,7 +5165,7 @@ } }, "inherits": { - "version": "2.0.3", + "version": "2.0.4", "bundled": true, "dev": true }, @@ -4934,6 +5204,11 @@ "bundled": true, "dev": true }, + "is-callable": { + "version": "1.1.4", + "bundled": true, + "dev": true + }, "is-ci": { "version": "1.1.0", "bundled": true, @@ -4957,6 +5232,11 @@ "cidr-regex": "^2.0.10" } }, + "is-date-object": { + "version": "1.0.1", + "bundled": true, + "dev": true + }, "is-fullwidth-code-point": { "version": "1.0.0", "bundled": true, @@ -4997,6 +5277,14 @@ "bundled": true, "dev": true }, + "is-regex": { + "version": "1.0.4", + "bundled": true, + "dev": true, + "requires": { + "has": "^1.0.1" + } + }, "is-retry-allowed": { "version": "1.1.0", "bundled": true, @@ -5007,6 +5295,14 @@ "bundled": true, "dev": true }, + "is-symbol": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "requires": { + "has-symbols": "^1.0.0" + } + }, "is-typedarray": { "version": "1.0.0", "bundled": true, @@ -5091,7 +5387,7 @@ } }, "libcipm": { - "version": "3.0.3", + "version": "4.0.0", "bundled": true, "dev": true, "requires": { @@ -5103,7 +5399,7 @@ "ini": "^1.3.5", "lock-verify": "^2.0.2", "mkdirp": "^0.5.1", - "npm-lifecycle": "^2.0.3", + "npm-lifecycle": "^3.0.0", "npm-logical-tree": "^1.2.1", "npm-package-arg": "^6.1.0", "pacote": "^9.1.0", @@ -5113,7 +5409,7 @@ } }, "libnpm": { - "version": "2.0.1", + "version": "3.0.0", "bundled": true, "dev": true, "requires": { @@ -5128,7 +5424,7 @@ "libnpmsearch": "^2.0.0", "libnpmteam": "^1.0.1", "lock-verify": "^2.0.2", - "npm-lifecycle": "^2.1.0", + "npm-lifecycle": "^3.0.0", "npm-logical-tree": "^1.2.1", "npm-package-arg": "^6.1.0", "npm-profile": "^4.0.1", @@ -5185,7 +5481,7 @@ } }, "p-limit": { - "version": "2.1.0", + "version": "2.2.0", "bundled": true, "dev": true, "requires": { @@ -5201,7 +5497,7 @@ } }, "p-try": { - "version": "2.0.0", + "version": "2.2.0", "bundled": true, "dev": true } @@ -5253,7 +5549,7 @@ } }, "libnpmsearch": { - "version": "2.0.0", + "version": "2.0.1", "bundled": true, "dev": true, "requires": { @@ -5399,12 +5695,11 @@ "dev": true }, "lru-cache": { - "version": "4.1.5", + "version": "5.1.1", "bundled": true, "dev": true, "requires": { - "pseudomap": "^1.0.2", - "yallist": "^2.1.2" + "yallist": "^3.0.2" } }, "make-dir": { @@ -5416,16 +5711,16 @@ } }, "make-fetch-happen": { - "version": "4.0.1", + "version": "4.0.2", "bundled": true, "dev": true, "requires": { "agentkeepalive": "^3.4.1", - "cacache": "^11.0.1", + "cacache": "^11.3.3", "http-cache-semantics": "^3.8.1", "http-proxy-agent": "^2.1.0", "https-proxy-agent": "^2.2.1", - "lru-cache": "^4.1.2", + "lru-cache": "^5.1.1", "mississippi": "^3.0.0", "node-fetch-npm": "^2.0.2", "promise-retry": "^1.1.1", @@ -5494,7 +5789,7 @@ } }, "minizlib": { - "version": "1.1.1", + "version": "1.2.1", "bundled": true, "dev": true, "requires": { @@ -5567,21 +5862,20 @@ } }, "node-gyp": { - "version": "3.8.0", + "version": "5.0.2", "bundled": true, "dev": true, "requires": { - "fstream": "^1.0.0", + "env-paths": "^1.0.0", "glob": "^7.0.3", "graceful-fs": "^4.1.2", "mkdirp": "^0.5.0", "nopt": "2 || 3", "npmlog": "0 || 1 || 2 || 3 || 4", - "osenv": "0", "request": "^2.87.0", "rimraf": "2", "semver": "~5.3.0", - "tar": "^2.0.0", + "tar": "^4.4.8", "which": "1" }, "dependencies": { @@ -5597,16 +5891,6 @@ "version": "5.3.0", "bundled": true, "dev": true - }, - "tar": { - "version": "2.2.1", - "bundled": true, - "dev": true, - "requires": { - "block-stream": "*", - "fstream": "^1.0.2", - "inherits": "2" - } } } }, @@ -5668,13 +5952,13 @@ } }, "npm-lifecycle": { - "version": "2.1.0", + "version": "3.0.0", "bundled": true, "dev": true, "requires": { "byline": "^5.0.0", - "graceful-fs": "^4.1.11", - "node-gyp": "^3.8.0", + "graceful-fs": "^4.1.15", + "node-gyp": "^5.0.2", "resolve-from": "^4.0.0", "slide": "^1.1.6", "uid-number": "0.0.6", @@ -5699,7 +5983,7 @@ } }, "npm-packlist": { - "version": "1.4.1", + "version": "1.4.4", "bundled": true, "dev": true, "requires": { @@ -5728,16 +6012,36 @@ } }, "npm-registry-fetch": { - "version": "3.9.0", + "version": "3.9.1", "bundled": true, "dev": true, "requires": { "JSONStream": "^1.3.4", "bluebird": "^3.5.1", "figgy-pudding": "^3.4.1", - "lru-cache": "^4.1.3", - "make-fetch-happen": "^4.0.1", + "lru-cache": "^5.1.1", + "make-fetch-happen": "^4.0.2", "npm-package-arg": "^6.1.0" + }, + "dependencies": { + "make-fetch-happen": { + "version": "4.0.2", + "bundled": true, + "dev": true, + "requires": { + "agentkeepalive": "^3.4.1", + "cacache": "^11.3.3", + "http-cache-semantics": "^3.8.1", + "http-proxy-agent": "^2.1.0", + "https-proxy-agent": "^2.2.1", + "lru-cache": "^5.1.1", + "mississippi": "^3.0.0", + "node-fetch-npm": "^2.0.2", + "promise-retry": "^1.1.1", + "socks-proxy-agent": "^4.0.0", + "ssri": "^6.0.0" + } + } } }, "npm-run-path": { @@ -5779,6 +6083,20 @@ "bundled": true, "dev": true }, + "object-keys": { + "version": "1.0.12", + "bundled": true, + "dev": true + }, + "object.getownpropertydescriptors": { + "version": "2.0.3", + "bundled": true, + "dev": true, + "requires": { + "define-properties": "^1.1.2", + "es-abstract": "^1.5.1" + } + }, "once": { "version": "1.4.0", "bundled": true, @@ -5859,7 +6177,7 @@ } }, "pacote": { - "version": "9.5.0", + "version": "9.5.1", "bundled": true, "dev": true, "requires": { @@ -5892,14 +6210,6 @@ "which": "^1.3.1" }, "dependencies": { - "lru-cache": { - "version": "5.1.1", - "bundled": true, - "dev": true, - "requires": { - "yallist": "^3.0.2" - } - }, "minipass": { "version": "2.3.5", "bundled": true, @@ -5908,11 +6218,6 @@ "safe-buffer": "^5.1.2", "yallist": "^3.0.0" } - }, - "yallist": { - "version": "3.0.3", - "bundled": true, - "dev": true } } }, @@ -6098,11 +6403,12 @@ "dev": true }, "query-string": { - "version": "6.2.0", + "version": "6.8.1", "bundled": true, "dev": true, "requires": { "decode-uri-component": "^0.2.0", + "split-on-first": "^1.0.0", "strict-uri-encode": "^2.0.0" } }, @@ -6172,19 +6478,17 @@ } }, "read-package-tree": { - "version": "5.2.2", + "version": "5.3.1", "bundled": true, "dev": true, "requires": { - "debuglog": "^1.0.1", - "dezalgo": "^1.0.0", - "once": "^1.3.0", "read-package-json": "^2.0.0", - "readdir-scoped-modules": "^1.0.0" + "readdir-scoped-modules": "^1.0.0", + "util-promisify": "^2.1.0" } }, "readable-stream": { - "version": "3.1.1", + "version": "3.4.0", "bundled": true, "dev": true, "requires": { @@ -6194,7 +6498,7 @@ } }, "readdir-scoped-modules": { - "version": "1.0.2", + "version": "1.1.0", "bundled": true, "dev": true, "requires": { @@ -6302,7 +6606,7 @@ "dev": true }, "semver": { - "version": "5.6.0", + "version": "5.7.0", "bundled": true, "dev": true }, @@ -6320,36 +6624,11 @@ "dev": true }, "sha": { - "version": "2.0.1", + "version": "3.0.0", "bundled": true, "dev": true, "requires": { - "graceful-fs": "^4.1.2", - "readable-stream": "^2.0.2" - }, - "dependencies": { - "readable-stream": { - "version": "2.3.6", - "bundled": true, - "dev": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "string_decoder": { - "version": "1.1.1", - "bundled": true, - "dev": true, - "requires": { - "safe-buffer": "~5.1.0" - } - } + "graceful-fs": "^4.1.2" } }, "shebang-command": { @@ -6477,6 +6756,11 @@ "bundled": true, "dev": true }, + "split-on-first": { + "version": "1.1.0", + "bundled": true, + "dev": true + }, "sshpk": { "version": "1.14.2", "bundled": true, @@ -6622,24 +6906,19 @@ } }, "tar": { - "version": "4.4.8", + "version": "4.4.10", "bundled": true, "dev": true, "requires": { "chownr": "^1.1.1", "fs-minipass": "^1.2.5", - "minipass": "^2.3.4", - "minizlib": "^1.1.1", + "minipass": "^2.3.5", + "minizlib": "^1.2.1", "mkdirp": "^0.5.0", "safe-buffer": "^5.1.2", - "yallist": "^3.0.2" + "yallist": "^3.0.3" }, "dependencies": { - "chownr": { - "version": "1.1.1", - "bundled": true, - "dev": true - }, "minipass": { "version": "2.3.5", "bundled": true, @@ -6824,6 +7103,14 @@ "bundled": true, "dev": true }, + "util-promisify": { + "version": "2.1.0", + "bundled": true, + "dev": true, + "requires": { + "object.getownpropertydescriptors": "^2.0.3" + } + }, "uuid": { "version": "3.3.2", "bundled": true, @@ -6906,7 +7193,7 @@ } }, "worker-farm": { - "version": "1.6.0", + "version": "1.7.0", "bundled": true, "dev": true, "requires": { @@ -6940,7 +7227,7 @@ "dev": true }, "write-file-atomic": { - "version": "2.4.2", + "version": "2.4.3", "bundled": true, "dev": true, "requires": { @@ -6965,7 +7252,7 @@ "dev": true }, "yallist": { - "version": "2.1.2", + "version": "3.0.3", "bundled": true, "dev": true }, @@ -7114,6 +7401,18 @@ } } }, + "object.values": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.0.tgz", + "integrity": "sha512-8mf0nKLAoFX6VlNVdhGj31SVYpaNFtUnuoOXWyFEstsWRgU837AK+JYM0iAxwkSzGRbwn8cbFmgbyxj1j4VbXg==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.12.0", + "function-bind": "^1.1.1", + "has": "^1.0.3" + } + }, "once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -7355,9 +7654,9 @@ "optional": true }, "prettier": { - "version": "1.17.1", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-1.17.1.tgz", - "integrity": "sha512-TzGRNvuUSmPgwivDqkZ9tM/qTGW9hqDKWOE9YHiyQdixlKbv7kvEqsmDPrcHJTKwthU774TQwZXVtaQ/mMsvjg==", + "version": "1.18.2", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-1.18.2.tgz", + "integrity": "sha512-OeHeMc0JhFE9idD4ZdtNibzY0+TPHSpSSb9h8FqtP+YnoZZ1sl8Vc9b1sasjfymH3SonAF4QcA2+mzHPhMvIiw==", "dev": true }, "private": { @@ -7851,12 +8150,6 @@ "is-finite": "^1.0.0" } }, - "requireindex": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/requireindex/-/requireindex-1.2.0.tgz", - "integrity": "sha512-L9jEkOi3ASd9PYit2cwRfyppc9NoABujTP8/5gFcbERmo5jUoAKovIC3fsF17pkTnGsrByysqX+Kxd2OTNI1ww==", - "dev": true - }, "resolve": { "version": "1.11.0", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.11.0.tgz", @@ -7904,24 +8197,55 @@ } }, "rollup": { - "version": "1.12.2", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-1.12.2.tgz", - "integrity": "sha512-ePehZfVMIE4eO0/LV6VaMY8kp0D9sbziUabpBeJbHAHa2WJPxuS0lYLmiLamb02e098RIRyq1F2yjM4O08dQVA==", + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-1.17.0.tgz", + "integrity": "sha512-k/j1m0NIsI4SYgCJR4MWPstGJOWfJyd6gycKoMhyoKPVXxm+L49XtbUwZyFsrSU2YXsOkM4u1ll9CS/ZgJBUpw==", "dev": true, "requires": { "@types/estree": "0.0.39", - "@types/node": "^12.0.2", - "acorn": "^6.1.1" + "@types/node": "^12.6.2", + "acorn": "^6.2.0" + }, + "dependencies": { + "@types/node": { + "version": "12.6.8", + "resolved": "https://registry.npmjs.org/@types/node/-/node-12.6.8.tgz", + "integrity": "sha512-aX+gFgA5GHcDi89KG5keey2zf0WfZk/HAQotEamsK2kbey+8yGKcson0hbK8E+v0NArlCJQCqMP161YhV6ZXLg==", + "dev": true + }, + "acorn": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.2.1.tgz", + "integrity": "sha512-JD0xT5FCRDNyjDda3Lrg/IxFscp9q4tiYtxE1/nOzlKCk7hIRuYjhq1kCNkbPjMRMZuFq20HNQn1I9k8Oj0E+Q==", + "dev": true + } } }, "rollup-plugin-babel": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/rollup-plugin-babel/-/rollup-plugin-babel-4.3.2.tgz", - "integrity": "sha512-KfnizE258L/4enADKX61ozfwGHoqYauvoofghFJBhFnpH9Sb9dNPpWg8QHOaAfVASUYV8w0mCx430i9z0LJoJg==", + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/rollup-plugin-babel/-/rollup-plugin-babel-4.3.3.tgz", + "integrity": "sha512-tKzWOCmIJD/6aKNz0H1GMM+lW1q9KyFubbWzGiOG540zxPPifnEAHTZwjo0g991Y+DyOZcLqBgqOdqazYE5fkw==", "dev": true, "requires": { "@babel/helper-module-imports": "^7.0.0", - "rollup-pluginutils": "^2.3.0" + "rollup-pluginutils": "^2.8.1" + }, + "dependencies": { + "estree-walker": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-0.6.1.tgz", + "integrity": "sha512-SqmZANLWS0mnatqbSfRP5g8OXZC12Fgg1IwNtLsyHDzJizORW4khDfjPqJZsemPWBB2uqykUah5YpQ6epsqC/w==", + "dev": true + }, + "rollup-pluginutils": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/rollup-pluginutils/-/rollup-pluginutils-2.8.1.tgz", + "integrity": "sha512-J5oAoysWar6GuZo0s+3bZ6sVZAC0pfqKz68De7ZgDi5z63jOVZn1uJL/+z1jeKHNbGII8kAyHF5q8LnxSX5lQg==", + "dev": true, + "requires": { + "estree-walker": "^0.6.1" + } + } } }, "rollup-plugin-json": { @@ -8632,9 +8956,9 @@ "dev": true }, "set-value": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.0.tgz", - "integrity": "sha512-hw0yxk9GT/Hr5yJEYnHNKYXkIA8mVJgd9ditYZCe16ZczcaELYYcfvaXesNACk2O8O0nTiPQcQhGUQj8JLzeeg==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", + "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==", "dev": true, "requires": { "extend-shallow": "^2.0.1", @@ -8903,9 +9227,9 @@ } }, "spdx-license-ids": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.4.tgz", - "integrity": "sha512-7j8LYJLeY/Yb6ACbQ7F76qy5jHkp0U6jgBfJsk97bwWlVUnUWsAgpyaCvo17h0/RQGnQ036tVDomiwoI4pDkQA==", + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.5.tgz", + "integrity": "sha512-J+FWzZoynJEXGphVIS+XEh3kFSjZX/1i9gFBaWQcB+/tmpe2qUsSBABpcxqxnAxFdiUFEgAX1bjYGQvIZmoz9Q==", "dev": true }, "split-string": { @@ -9192,9 +9516,9 @@ "dev": true }, "tsutils": { - "version": "3.10.0", - "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.10.0.tgz", - "integrity": "sha512-q20XSMq7jutbGB8luhKKsQldRKWvyBO2BGqni3p4yq8Ys9bEP/xQw3KepKmMRt9gJ4lvQSScrihJrcKdKoSU7Q==", + "version": "3.14.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.14.0.tgz", + "integrity": "sha512-SmzGbB0l+8I0QwsPgjooFRaRvHLBLNYM8SeQ0k6rtNDru5sCGeLJcZdwilNndN+GysuFjF5EIYgN8GfFG6UeUw==", "dev": true, "requires": { "tslib": "^1.8.1" @@ -9216,9 +9540,9 @@ "dev": true }, "typescript": { - "version": "3.4.5", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.4.5.tgz", - "integrity": "sha512-YycBxUb49UUhdNMU5aJ7z5Ej2XGmaIBL0x34vZ82fn3hGvD+bgrMrVDpatgz2f7YxUMJxMkbWxJZeAvDxVe7Vw==", + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.5.3.tgz", + "integrity": "sha512-ACzBtm/PhXBDId6a6sDJfroT2pOWt/oOnk4/dElG5G33ZL776N3Y6/6bKZJBFpd+b05F3Ct9qDjMeJmRWtE2/g==", "dev": true }, "typescript-styled-plugin": { @@ -9252,38 +9576,15 @@ "dev": true }, "union-value": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.0.tgz", - "integrity": "sha1-XHHDTLW61dzr4+oM0IIHulqhrqQ=", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", + "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==", "dev": true, "requires": { "arr-union": "^3.1.0", "get-value": "^2.0.6", "is-extendable": "^0.1.1", - "set-value": "^0.4.3" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - }, - "set-value": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/set-value/-/set-value-0.4.3.tgz", - "integrity": "sha1-fbCPnT0i3H945Trzw79GZuzfzPE=", - "dev": true, - "requires": { - "extend-shallow": "^2.0.1", - "is-extendable": "^0.1.1", - "is-plain-object": "^2.0.1", - "to-object-path": "^0.3.0" - } - } + "set-value": "^2.0.1" } }, "universalify": { diff --git a/package.json b/package.json index 405d5bd..e01719c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "button-card", - "version": "1.11.1", + "version": "2.0.0", "description": "Button card for lovelace", "main": "dist/button-card.js", "pre-commit": [ @@ -32,33 +32,33 @@ }, "homepage": "https://github.com/custom-cards/button-card#readme", "devDependencies": { - "@babel/core": "^7.4.4", - "@babel/plugin-proposal-class-properties": "^7.4.4", + "@babel/core": "^7.5.5", + "@babel/plugin-proposal-class-properties": "^7.5.5", "@babel/plugin-proposal-decorators": "^7.4.4", - "@typescript-eslint/eslint-plugin": "^1.9.0", - "@typescript-eslint/parser": "^1.9.0", + "@typescript-eslint/eslint-plugin": "^1.12.0", + "@typescript-eslint/parser": "^1.12.0", "babel-cli": "^6.26.0", "eslint": "^5.16.0", - "eslint-config-airbnb-base": "^13.1.0", - "eslint-plugin-import": "^2.17.2", - "npm": "^6.9.0", + "eslint-config-airbnb-base": "^13.2.0", + "eslint-plugin-import": "^2.18.2", + "npm": "^6.10.1", "pre-commit": "^1.2.2", - "prettier": "^1.17.1", - "rollup": "^1.12.2", - "rollup-plugin-babel": "^4.3.2", + "prettier": "^1.18.2", + "rollup": "^1.17.0", + "rollup-plugin-babel": "^4.3.3", "rollup-plugin-json": "^4.0.0", "rollup-plugin-node-resolve": "^4.2.4", "rollup-plugin-terser": "^4.0.4", "rollup-plugin-typescript2": "^0.20.1", "ts-lit-plugin": "^1.0.6", - "typescript": "^3.4.4", + "typescript": "^3.5.3", "typescript-styled-plugin": "^0.14.0" }, "dependencies": { - "@ctrl/tinycolor": "^2.4.0", - "custom-card-helpers": "github:custom-cards/custom-card-helpers#fix-service-call", + "@ctrl/tinycolor": "^2.5.3", + "custom-card-helpers": "^1.2.2", "home-assistant-js-websocket": "^3.4.0", - "lit-element": "^2.1.0", - "lit-html": "^1.0.0" + "lit-element": "^2.2.0", + "lit-html": "^1.1.1" } } diff --git a/src/button-card.ts b/src/button-card.ts index fbc9453..3845049 100644 --- a/src/button-card.ts +++ b/src/button-card.ts @@ -10,14 +10,10 @@ import { import { styleMap, StyleInfo } from 'lit-html/directives/style-map'; import { unsafeHTML } from 'lit-html/directives/unsafe-html'; import { ifDefined } from 'lit-html/directives/if-defined'; -import { classMap, ClassInfo } from 'lit-html/directives/class-map.js'; +import { classMap, ClassInfo } from 'lit-html/directives/class-map'; import { HassEntity, } from 'home-assistant-js-websocket'; -import { - ButtonCardConfig, - StateConfig, -} from './types'; import { domainIcon, HomeAssistant, @@ -25,10 +21,14 @@ import { getLovelace, timerTimeRemaining, secondsToDuration, - durationToSeconds + durationToSeconds, // Still not working... // longPress, } from 'custom-card-helpers'; +import { + ButtonCardConfig, + StateConfig, +} from './types'; import { longPress } from './long-press'; import { computeDomain, @@ -52,6 +52,8 @@ class ButtonCard extends LitElement { @property() private _timeRemaining?: number; + @property() private _hasTemplate?: boolean; + private _interval?: number; public disconnectedCallback(): void { @@ -62,9 +64,9 @@ class ButtonCard extends LitElement { public connectedCallback(): void { super.connectedCallback(); if ( - this.config && - this.config.entity && - computeDomain(this.config.entity) === 'timer' + this.config + && this.config.entity + && computeDomain(this.config.entity) === 'timer' ) { const stateObj = this.hass!.states[this.config.entity]; this._startInterval(stateObj); @@ -85,16 +87,7 @@ class ButtonCard extends LitElement { protected shouldUpdate(changedProps: PropertyValues): boolean { const state = this.config!.entity ? this.hass!.states[this.config!.entity] : undefined; const configState = this._getMatchingConfigState(state); - const forceUpdate = ( - configState && ( - this.config!.show_label && configState.label_template - || this.config!.show_entity_picture && configState.entity_picture_template - || this.config!.show_name && configState.name_template - ) - || this.config!.show_label && this.config!.label_template - || this.config!.show_name && this.config!.name_template - || this.config!.show_entity_picture && this.config!.entity_picture_template - ) + const forceUpdate = this._hasTemplate || this.config!.state && this.config!.state.find(elt => elt.operator === 'template') || changedProps.has('_timeRemaining') @@ -106,10 +99,10 @@ class ButtonCard extends LitElement { super.updated(changedProps); if ( - this.config && - this.config.entity && - computeDomain(this.config.entity) === 'timer' && - changedProps.has('hass') + this.config + && this.config.entity + && computeDomain(this.config.entity) === 'timer' + && changedProps.has('hass') ) { const stateObj = this.hass!.states[this.config.entity]; const oldHass = changedProps.get('hass') as this['hass']; @@ -139,7 +132,7 @@ class ButtonCard extends LitElement { if (stateObj.state === 'active') { this._interval = window.setInterval( () => this._calculateRemaining(stateObj), - 1000 + 1000, ); } } @@ -154,7 +147,7 @@ class ButtonCard extends LitElement { } return secondsToDuration( - this._timeRemaining || durationToSeconds(stateObj.attributes['duration']) + this._timeRemaining || durationToSeconds(stateObj.attributes.duration), ); } @@ -174,24 +167,25 @@ class ButtonCard extends LitElement { switch (elt.operator) { case '==': /* eslint eqeqeq: 0 */ - return (state && state.state == elt.value); + return (state && state.state == this._getTemplateOrString(state, elt.value)); case '<=': - return (state && state.state <= elt.value); + return (state && state.state <= this._getTemplateOrString(state, elt.value)); case '<': - return (state && state.state < elt.value); + return (state && state.state < this._getTemplateOrString(state, elt.value)); case '>=': - return (state && state.state >= elt.value); + return (state && state.state >= this._getTemplateOrString(state, elt.value)); case '>': - return (state && state.state > elt.value); + return (state && state.state > this._getTemplateOrString(state, elt.value)); case '!=': - return (state && state.state != elt.value); + return (state && state.state != this._getTemplateOrString(state, elt.value)); case 'regex': { /* eslint no-unneeded-ternary: 0 */ - const matches = state && state.state.match(elt.value) ? true : false; + const matches = state + && state.state.match(this._getTemplateOrString(state, elt.value)) ? true : false; return matches; } case 'template': { - return this._evalTemplate(state, elt.value); + return this._getTemplateOrString(state, elt.value); } case 'default': def = elt; @@ -200,7 +194,7 @@ class ButtonCard extends LitElement { return false; } } else { - return state && (elt.value == state.state); + return state && (this._getTemplateOrString(state, elt.value) == state.state); } }); if (!retval && def) { @@ -210,11 +204,29 @@ class ButtonCard extends LitElement { } private _evalTemplate(state: HassEntity | undefined, func: any): any { + /* eslint no-new-func: 0 */ return new Function('states', 'entity', 'user', 'hass', `'use strict'; ${func}`) .call(this, this.hass!.states, state, this.hass!.user, this.hass); } + private _getTemplateOrString( + state: HassEntity | undefined, + value: any | undefined, + ): any | undefined { + if (!value) return undefined; + if (typeof value === 'number') return value; + const trimmed = value.trim(); + if ( + trimmed.substring(0, 3) === '[[[' + && trimmed.slice(-3) === ']]]' + ) { + return this._evalTemplate(state, trimmed.slice(3, -3)); + } else { + return value; + } + } + private _getDefaultColorForState(state: HassEntity): string { switch (state.state) { case 'on': @@ -300,7 +312,7 @@ class ButtonCard extends LitElement { ? state.attributes.icon : domainIcon(computeDomain(state.entity_id), state.state); } - return icon; + return this._getTemplateOrString(state, icon); } private _buildEntityPicture( @@ -311,33 +323,24 @@ class ButtonCard extends LitElement { return undefined; } let entityPicture: string | undefined; - let matchingEntityPictureTemplate: string | undefined; - if (configState && configState.entity_picture_template) { - matchingEntityPictureTemplate = configState.entity_picture_template; - } else { - matchingEntityPictureTemplate = this.config!.entity_picture_template; - } - if (!matchingEntityPictureTemplate) { - if (configState && configState.entity_picture) { - entityPicture = configState.entity_picture; - } else if (this.config!.entity_picture) { - entityPicture = this.config!.entity_picture; - } else if (state) { - entityPicture = state.attributes && state.attributes.entity_picture - ? state.attributes.entity_picture : undefined; - } - return entityPicture; + if (configState && configState.entity_picture) { + entityPicture = configState.entity_picture; + } else if (this.config!.entity_picture) { + entityPicture = this.config!.entity_picture; + } else if (state) { + entityPicture = state.attributes && state.attributes.entity_picture + ? state.attributes.entity_picture : undefined; } - - return this._evalTemplate(state, matchingEntityPictureTemplate); + return this._getTemplateOrString(state, entityPicture); } private _buildStyleGeneric( + state: HassEntity | undefined, configState: StateConfig | undefined, styleType: string, ): StyleInfo { - let style: StyleInfo = {}; + let style: any = {}; if (this.config!.styles && this.config!.styles[styleType]) { style = Object.assign(style, ...this.config!.styles[styleType]); } @@ -349,6 +352,41 @@ class ButtonCard extends LitElement { ...configStateStyle, }; } + Object.keys(style).forEach((key) => { + style[key] = this._getTemplateOrString(state, style[key]); + }); + return style; + } + + private _buildCustomStyleGeneric( + state: HassEntity | undefined, + configState: StateConfig | undefined, + styleType: string, + ): StyleInfo { + let style: any = {}; + if (this.config!.styles + && this.config!.styles.custom_fields + && this.config!.styles.custom_fields[styleType] + ) { + style = Object.assign(style, ...this.config!.styles.custom_fields[styleType]); + } + if (configState && configState.styles + && configState.styles.custom_fields + && configState.styles.custom_fields[styleType] + ) { + let configStateStyle: StyleInfo = {}; + configStateStyle = Object.assign( + configStateStyle, + ...configState.styles.custom_fields[styleType], + ); + style = { + ...style, + ...configStateStyle, + }; + } + Object.keys(style).forEach((key) => { + style[key] = this._getTemplateOrString(state, style[key]); + }); return style; } @@ -359,26 +397,17 @@ class ButtonCard extends LitElement { return undefined; } let name: string | undefined; - let matchingNameTemplate: string | undefined; - if (configState && configState.name_template) { - matchingNameTemplate = configState.name_template; - } else { - matchingNameTemplate = this.config!.name_template; - } - if (!matchingNameTemplate) { - if (configState && configState.name) { - name = configState.name; - } else if (this.config!.name) { - name = this.config!.name; - } else if (state) { - name = state.attributes && state.attributes.friendly_name - ? state.attributes.friendly_name : computeEntity(state.entity_id); - } - return name; + if (configState && configState.name) { + name = configState.name; + } else if (this.config!.name) { + name = this.config!.name; + } else if (state) { + name = state.attributes && state.attributes.friendly_name + ? state.attributes.friendly_name : computeEntity(state.entity_id); } - return this._evalTemplate(state, matchingNameTemplate); + return this._getTemplateOrString(state, name); } private _buildStateString(state: HassEntity | undefined): string | undefined { @@ -394,7 +423,7 @@ class ButtonCard extends LitElement { } else { stateString = this._computeTimeDisplay(state); if (state.state === 'paused') { - stateString += ` (${localizedState})` + stateString += ` (${localizedState})`; } } } else { @@ -422,8 +451,8 @@ class ButtonCard extends LitElement { state: HassEntity | undefined, style: StyleInfo, ): TemplateResult | undefined { - return this.config!.show_last_changed && state ? - html` + return this.config!.show_last_changed && state + ? html` { + const value = this.config!.custom_fields![key]; + fields[key] = this._getTemplateOrString(state, value); + }); + } + if (configState && configState.custom_fields) { + Object.keys(configState.custom_fields).forEach((key) => { + const value = configState!.custom_fields![key]; + fields[key] = this._getTemplateOrString(state, value); + }); + } + Object.keys(fields).forEach((key) => { + if (fields[key] != undefined) { + const customStyle: StyleInfo = { + ...this._buildCustomStyleGeneric(state, configState, key), + 'grid-area': key, + }; + result = html`${result} +
${unsafeHTML(fields[key])}
`; + } + }); + return result; } private _isClickable(state: HassEntity | undefined): boolean { @@ -525,15 +576,15 @@ class ButtonCard extends LitElement { const configState = this._getMatchingConfigState(state); const color = this._buildCssColorAttribute(state, configState); let buttonColor = color; - let cardStyle: StyleInfo = {}; - let lockStyle: StyleInfo = {}; - let aspectRatio: StyleInfo = {}; - const lockStyleFromConfig = this._buildStyleGeneric(configState, 'lock'); - const configCardStyle = this._buildStyleGeneric(configState, 'card'); + let cardStyle: any = {}; + let lockStyle: any = {}; + const aspectRatio: any = {}; + const lockStyleFromConfig = this._buildStyleGeneric(state, configState, 'lock'); + const configCardStyle = this._buildStyleGeneric(state, configState, 'card'); const classList: ClassInfo = { 'button-card-main': true, disabled: !this._isClickable(state), - } + }; if (configCardStyle.width) { this.style.setProperty('flex', '0 0 auto'); this.style.setProperty('max-width', 'fit-content'); @@ -629,11 +680,11 @@ class ButtonCard extends LitElement { const iconTemplate = this._getIconHtml(state, configState, color); const itemClass: string[] = [containerClass]; const label = this._buildLabel(state, configState); - const nameStyleFromConfig = this._buildStyleGeneric(configState, 'name'); - const stateStyleFromConfig = this._buildStyleGeneric(configState, 'state'); - const labelStyleFromConfig = this._buildStyleGeneric(configState, 'label'); + const nameStyleFromConfig = this._buildStyleGeneric(state, configState, 'name'); + const stateStyleFromConfig = this._buildStyleGeneric(state, configState, 'state'); + const labelStyleFromConfig = this._buildStyleGeneric(state, configState, 'label'); const lastChangedTemplate = this._buildLastChanged(state, labelStyleFromConfig); - const gridStyleFromConfig = this._buildStyleGeneric(configState, 'grid'); + const gridStyleFromConfig = this._buildStyleGeneric(state, configState, 'grid'); if (!iconTemplate) itemClass.push('no-icon'); if (!name) itemClass.push('no-name'); if (!stateString) itemClass.push('no-state'); @@ -646,6 +697,7 @@ class ButtonCard extends LitElement { ${stateString ? html`
${stateString}
` : ''} ${label && !lastChangedTemplate ? html`
${unsafeHTML(label)}
` : ''} ${lastChangedTemplate ? lastChangedTemplate : ''} + ${this._buildCustomFields(state, configState)}
`; } @@ -657,10 +709,10 @@ class ButtonCard extends LitElement { ): TemplateResult | undefined { const icon = this._buildIcon(state, configState); const entityPicture = this._buildEntityPicture(state, configState); - const entityPictureStyleFromConfig = this._buildStyleGeneric(configState, 'entity_picture'); - const haIconStyleFromConfig = this._buildStyleGeneric(configState, 'icon'); - const imgCellStyleFromConfig = this._buildStyleGeneric(configState, 'img_cell'); - const haCardStyleFromConfig = this._buildStyleGeneric(configState, 'card'); + const entityPictureStyleFromConfig = this._buildStyleGeneric(state, configState, 'entity_picture'); + const haIconStyleFromConfig = this._buildStyleGeneric(state, configState, 'icon'); + const imgCellStyleFromConfig = this._buildStyleGeneric(state, configState, 'img_cell'); + const haCardStyleFromConfig = this._buildStyleGeneric(state, configState, 'card'); const haIconStyle: StyleInfo = { color, @@ -698,7 +750,10 @@ class ButtonCard extends LitElement { let mergedStateConfig: StateConfig[] | undefined = config.state; while (tplName && ll.config.button_card_templates && ll.config.button_card_templates[tplName]) { template = mergeDeep(ll.config.button_card_templates[tplName], template); - mergedStateConfig = mergeStatesById((ll.config.button_card_templates[tplName] as ButtonCardConfig).state, mergedStateConfig); + mergedStateConfig = mergeStatesById( + (ll.config.button_card_templates[tplName] as ButtonCardConfig).state, + mergedStateConfig, + ); tplName = (ll.config.button_card_templates[tplName] as ButtonCardConfig).template; } template.state = mergedStateConfig; @@ -724,6 +779,10 @@ class ButtonCard extends LitElement { this.config!.color_off = 'var(--paper-item-icon-color)'; } this.config!.color_on = 'var(--paper-item-icon-active-color)'; + + const jsonConfig = JSON.stringify(this.config); + const rxp = new RegExp('\\[\\[\\[.*\\]\\]\\]', 'gm'); + this._hasTemplate = jsonConfig.match(rxp) ? true : false; } // The height of your card. Home Assistant uses this to automatically @@ -732,6 +791,25 @@ class ButtonCard extends LitElement { return 3; } + private _evalActions(config: ButtonCardConfig, action: string): ButtonCardConfig { + const state = this.config!.entity ? this.hass!.states[this.config!.entity] : undefined; + const configDuplicate = JSON.parse(JSON.stringify(config)); + Object.keys(configDuplicate![action]).forEach((key) => { + if (key === 'service_data') { + Object.keys(configDuplicate![action].service_data).forEach((sdKey) => { + configDuplicate![action].service_data[sdKey] = this._getTemplateOrString( + state, configDuplicate![action].service_data[sdKey], + ); + }); + } else { + configDuplicate![action][key] = this._getTemplateOrString( + state, configDuplicate![action][key], + ); + } + }); + return configDuplicate; + } + private _handleTap(ev): void { /* eslint no-alert: 0 */ if (this.config!.confirmation @@ -739,7 +817,7 @@ class ButtonCard extends LitElement { return; } const config = ev.target.config; - handleClick(this, this.hass!, config, false, false); + handleClick(this, this.hass!, this._evalActions(config, 'tap_action'), false, false); } private _handleHold(ev): void { @@ -749,7 +827,7 @@ class ButtonCard extends LitElement { return; } const config = ev.target.config; - handleClick(this, this.hass!, config, true, false); + handleClick(this, this.hass!, this._evalActions(config, 'hold_action'), true, false); } private _handleDblTap(ev): void { @@ -759,7 +837,7 @@ class ButtonCard extends LitElement { return; } const config = ev.target.config; - handleClick(this, this.hass!, config, false, true); + handleClick(this, this.hass!, this._evalActions(config, 'dbltap_action'), false, true); } private _handleLock(ev): void { diff --git a/src/compute_state_display.ts b/src/compute_state_display.ts index bf8bf31..cbd775c 100644 --- a/src/compute_state_display.ts +++ b/src/compute_state_display.ts @@ -1,6 +1,6 @@ import { HassEntity } from 'home-assistant-js-websocket'; -import { computeDomain } from './helpers'; import { LocalizeFunc } from 'custom-card-helpers'; +import { computeDomain } from './helpers'; export default ( localize: LocalizeFunc, diff --git a/src/helpers.ts b/src/helpers.ts index 94abdb0..93930a2 100644 --- a/src/helpers.ts +++ b/src/helpers.ts @@ -139,13 +139,20 @@ export function mergeStatesById( fromStates.forEach((fromState) => { if (fromState.id && intoState.id && fromState.id == intoState.id) localState = mergeDeep(localState, fromState); - }) + }); } resultStateConfigs.push(localState); }); } if (fromStates) { - resultStateConfigs = resultStateConfigs.concat(fromStates.filter(x => !intoStates ? true : !intoStates.find(y => y.id && x.id ? y.id == x.id : false))); + /* eslint eqeqeq: 0 no-confusing-arrow: 0 */ + resultStateConfigs = resultStateConfigs.concat( + fromStates.filter( + x => !intoStates + ? true + : !intoStates.find(y => y.id && x.id ? y.id == x.id : false), + ), + ); } return resultStateConfigs; -} \ No newline at end of file +} diff --git a/src/long-press.ts b/src/long-press.ts index f219c1c..08f1208 100644 --- a/src/long-press.ts +++ b/src/long-press.ts @@ -105,6 +105,7 @@ class LongPress extends HTMLElement implements LongPress { }); const clickStart = (ev: Event) => { + ev.stopPropagation(); if (this.cooldownStart) { return; } @@ -134,6 +135,7 @@ class LongPress extends HTMLElement implements LongPress { }; const clickEnd = (ev: Event) => { + ev.stopPropagation(); if ( this.cooldownEnd || (['touchend', 'touchcancel'].includes(ev.type) diff --git a/src/types.ts b/src/types.ts index 37385e1..651ff54 100644 --- a/src/types.ts +++ b/src/types.ts @@ -5,7 +5,6 @@ export interface ButtonCardConfig { type: string; entity?: string; name?: string; - name_template?: string; icon?: string; color_type: 'icon' | 'card' | 'label-card' | 'blank-card' color?: 'auto' | 'auto-no-temperature' | string; @@ -24,19 +23,17 @@ export interface ButtonCardConfig { show_last_changed?: boolean; show_label?: boolean; label?: string; - label_template?: string; entity_picture?: string; - entity_picture_template?: string; units?: string; state?: StateConfig[]; styles?: StylesConfig; confirmation?: string; layout: Layout; entity_picture_style?: CssStyleConfig[]; - default_color: string; color_on: string; color_off: string; + custom_fields?: CustomFields; } export type Layout = 'vertical' @@ -53,16 +50,14 @@ export interface StateConfig { operator?: '<' | '<=' | '==' | '>=' | '>' | '!=' | 'regex' | 'template' | 'default'; value?: any; name?: string; - name_template?: string; icon?: string; color?: 'auto' | 'auto-no-temperature' | string; entity_picture_style?: CssStyleConfig[]; entity_picture?: string; - entity_picture_template?: string; styles?: StylesConfig; spin?: boolean; label?: string; - label_template?: string; + custom_fields?: CustomFields; } export interface StylesConfig { @@ -75,8 +70,17 @@ export interface StylesConfig { grid?: CssStyleConfig[]; img_cell?: CssStyleConfig[]; lock?: CssStyleConfig[]; + custom_fields?: CustomStyleConfig; +} + +export interface CustomStyleConfig { + [key: string]: CssStyleConfig[]; } export interface CssStyleConfig { [key: string]: any; } + +export interface CustomFields { + [key: string]: any; +}