859 lines
24 KiB
TypeScript
859 lines
24 KiB
TypeScript
import {
|
|
LitElement,
|
|
html,
|
|
customElement,
|
|
property,
|
|
TemplateResult,
|
|
CSSResult,
|
|
PropertyValues
|
|
} from "lit-element";
|
|
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 { HassEntity } from "home-assistant-js-websocket";
|
|
import {
|
|
HomeAssistant,
|
|
domainIcon,
|
|
handleClick,
|
|
computeStateDisplay,
|
|
hasConfigOrEntityChanged,
|
|
computeDomain,
|
|
computeEntity,
|
|
longPress,
|
|
timerTimeRemaining,
|
|
secondsToDuration,
|
|
durationToSeconds
|
|
} from "custom-card-helpers";
|
|
|
|
import { ButtonCardConfig, StateConfig } from "./types";
|
|
import {
|
|
getFontColorBasedOnBackgroundColor,
|
|
buildNameStateConcat,
|
|
applyBrightnessToColor,
|
|
getLightColorBasedOnTemperature
|
|
} from "./helpers";
|
|
import { styles } from "./styles";
|
|
|
|
@customElement("button-card")
|
|
class ButtonCard extends LitElement {
|
|
@property() public hass?: HomeAssistant;
|
|
|
|
@property() private config?: ButtonCardConfig;
|
|
|
|
@property() private _timeRemaining?: number;
|
|
|
|
private _interval?: number;
|
|
|
|
static get styles(): CSSResult {
|
|
return styles;
|
|
}
|
|
|
|
public disconnectedCallback(): void {
|
|
super.disconnectedCallback();
|
|
this._clearInterval();
|
|
}
|
|
|
|
protected render(): TemplateResult | void {
|
|
if (!this.config || !this.hass) {
|
|
return html``;
|
|
}
|
|
return this._cardHtml();
|
|
}
|
|
|
|
protected shouldUpdate(changedProps: PropertyValues): boolean {
|
|
const state = this.config!.entity
|
|
? this.hass!.states[this.config!.entity]
|
|
: undefined;
|
|
const configState = this._getMatchingConfigState(state);
|
|
const forceUpdate =
|
|
(this.config!.show_label &&
|
|
((configState && configState.label_template) ||
|
|
this.config!.label_template)) ||
|
|
(this.config!.state &&
|
|
this.config!.state.find(elt => elt.operator === "template"))
|
|
? true
|
|
: false || changedProps.has("_timeRemaining");
|
|
return hasConfigOrEntityChanged(this, changedProps, forceUpdate);
|
|
}
|
|
|
|
protected updated(changedProps: PropertyValues) {
|
|
super.updated(changedProps);
|
|
|
|
if (
|
|
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"];
|
|
const oldStateObj = oldHass
|
|
? oldHass.states[this.config.entity]
|
|
: undefined;
|
|
|
|
if (oldStateObj !== stateObj) {
|
|
this._startInterval(stateObj);
|
|
} else if (!stateObj) {
|
|
this._clearInterval();
|
|
}
|
|
}
|
|
}
|
|
|
|
private _clearInterval(): void {
|
|
if (this._interval) {
|
|
window.clearInterval(this._interval);
|
|
this._interval = undefined;
|
|
}
|
|
}
|
|
|
|
private _startInterval(stateObj: HassEntity): void {
|
|
this._clearInterval();
|
|
this._calculateRemaining(stateObj);
|
|
|
|
if (stateObj.state === "active") {
|
|
this._interval = window.setInterval(
|
|
() => this._calculateRemaining(stateObj),
|
|
1000
|
|
);
|
|
}
|
|
}
|
|
|
|
private _calculateRemaining(stateObj: HassEntity): void {
|
|
this._timeRemaining = timerTimeRemaining(stateObj);
|
|
}
|
|
|
|
private _computeTimeDisplay(stateObj: HassEntity): string | undefined {
|
|
if (!stateObj) {
|
|
return undefined;
|
|
}
|
|
|
|
return secondsToDuration(
|
|
this._timeRemaining || durationToSeconds(stateObj.attributes["duration"])
|
|
);
|
|
}
|
|
|
|
private _getMatchingConfigState(
|
|
state: HassEntity | undefined
|
|
): StateConfig | undefined {
|
|
if (!this.config!.state) {
|
|
return undefined;
|
|
}
|
|
const hasTemplate = this.config!.state.find(
|
|
elt => elt.operator === "template"
|
|
);
|
|
if (!state && !hasTemplate) {
|
|
return undefined;
|
|
}
|
|
let def: StateConfig | undefined;
|
|
const retval = this.config!.state.find(elt => {
|
|
if (elt.operator) {
|
|
switch (elt.operator) {
|
|
case "==":
|
|
/* eslint eqeqeq: 0 */
|
|
return state && state.state == elt.value;
|
|
case "<=":
|
|
return state && state.state <= elt.value;
|
|
case "<":
|
|
return state && state.state < elt.value;
|
|
case ">=":
|
|
return state && state.state >= elt.value;
|
|
case ">":
|
|
return state && state.state > elt.value;
|
|
case "!=":
|
|
return state && state.state != elt.value;
|
|
case "regex": {
|
|
/* eslint no-unneeded-ternary: 0 */
|
|
const matches =
|
|
state && state.state.match(elt.value) ? true : false;
|
|
return matches;
|
|
}
|
|
case "template": {
|
|
return new Function(
|
|
"states",
|
|
"entity",
|
|
"user",
|
|
"hass",
|
|
`'use strict'; ${elt.value}`
|
|
).call(this, this.hass!.states, state, this.hass!.user, this.hass);
|
|
}
|
|
case "default":
|
|
def = elt;
|
|
return false;
|
|
default:
|
|
return false;
|
|
}
|
|
} else {
|
|
return state && elt.value == state.state;
|
|
}
|
|
});
|
|
if (!retval && def) {
|
|
return def;
|
|
}
|
|
return retval;
|
|
}
|
|
|
|
private _getDefaultColorForState(state: HassEntity): string {
|
|
switch (state.state) {
|
|
case "on":
|
|
return this.config!.color_on;
|
|
case "off":
|
|
return this.config!.color_off;
|
|
default:
|
|
return this.config!.default_color;
|
|
}
|
|
}
|
|
|
|
private _getColorForLightEntity(state: HassEntity | undefined): string {
|
|
let color: string = this.config!.default_color;
|
|
if (state) {
|
|
if (state.attributes.rgb_color) {
|
|
color = `rgb(${state.attributes.rgb_color.join(",")})`;
|
|
if (state.attributes.brightness) {
|
|
color = applyBrightnessToColor(
|
|
color,
|
|
(state.attributes.brightness + 245) / 5
|
|
);
|
|
}
|
|
} else if (
|
|
state.attributes.color_temp &&
|
|
state.attributes.min_mireds &&
|
|
state.attributes.max_mireds
|
|
) {
|
|
color = getLightColorBasedOnTemperature(
|
|
state.attributes.color_temp,
|
|
state.attributes.min_mireds,
|
|
state.attributes.max_mireds
|
|
);
|
|
if (state.attributes.brightness) {
|
|
color = applyBrightnessToColor(
|
|
color,
|
|
(state.attributes.brightness + 245) / 5
|
|
);
|
|
}
|
|
} else if (state.attributes.brightness) {
|
|
color = applyBrightnessToColor(
|
|
this._getDefaultColorForState(state),
|
|
(state.attributes.brightness + 245) / 5
|
|
);
|
|
} else {
|
|
color = this._getDefaultColorForState(state);
|
|
}
|
|
}
|
|
return color;
|
|
}
|
|
|
|
private _buildCssColorAttribute(
|
|
state: HassEntity | undefined,
|
|
configState: StateConfig | undefined
|
|
): string {
|
|
let colorValue: string = "";
|
|
let color: undefined | string;
|
|
if (configState && configState.color) {
|
|
colorValue = configState.color;
|
|
} else if (
|
|
this.config!.color !== "auto" &&
|
|
state &&
|
|
state.state === "off"
|
|
) {
|
|
colorValue = this.config!.color_off;
|
|
} else if (this.config!.color) {
|
|
colorValue = this.config!.color;
|
|
}
|
|
if (colorValue == "auto") {
|
|
color = this._getColorForLightEntity(state);
|
|
} else if (colorValue) {
|
|
color = colorValue;
|
|
} else if (state) {
|
|
color = this._getDefaultColorForState(state);
|
|
} else {
|
|
color = this.config!.default_color;
|
|
}
|
|
return color;
|
|
}
|
|
|
|
private _buildIcon(
|
|
state: HassEntity | undefined,
|
|
configState: StateConfig | undefined
|
|
): string | undefined {
|
|
if (!this.config!.show_icon) {
|
|
return undefined;
|
|
}
|
|
let icon: undefined | string;
|
|
if (configState && configState.icon) {
|
|
icon = configState.icon;
|
|
} else if (this.config!.icon) {
|
|
icon = this.config!.icon;
|
|
} else if (state && state.attributes) {
|
|
icon = state.attributes.icon
|
|
? state.attributes.icon
|
|
: domainIcon(computeDomain(state.entity_id), state.state);
|
|
}
|
|
return icon;
|
|
}
|
|
|
|
private _buildEntityPicture(
|
|
state: HassEntity | undefined,
|
|
configState: StateConfig | undefined
|
|
): string | undefined {
|
|
if (
|
|
!this.config!.show_entity_picture ||
|
|
(!state && !configState && !this.config!.entity_picture)
|
|
) {
|
|
return undefined;
|
|
}
|
|
let entityPicture: string | undefined;
|
|
if (configState && configState.entity_picture) {
|
|
entityPicture = configState.entity_picture;
|
|
} else if (this.config!.entity_picture) {
|
|
entityPicture = this.config!.entity_picture;
|
|
} else {
|
|
entityPicture =
|
|
state && state.attributes && state.attributes.entity_picture
|
|
? state.attributes.entity_picture
|
|
: undefined;
|
|
}
|
|
return entityPicture;
|
|
}
|
|
|
|
private _buildStyleGeneric(
|
|
configState: StateConfig | undefined,
|
|
styleType: string
|
|
): StyleInfo {
|
|
let style: StyleInfo = {};
|
|
if (this.config!.styles[styleType]) {
|
|
style = Object.assign(style, ...this.config!.styles[styleType]);
|
|
}
|
|
if (configState && configState.styles[styleType]) {
|
|
let configStateStyle: StyleInfo = {};
|
|
configStateStyle = Object.assign(
|
|
configStateStyle,
|
|
...configState.styles[styleType]
|
|
);
|
|
style = {
|
|
...style,
|
|
...configStateStyle
|
|
};
|
|
}
|
|
return style;
|
|
}
|
|
|
|
private _buildName(
|
|
state: HassEntity | undefined,
|
|
configState: StateConfig | undefined
|
|
): string | undefined {
|
|
if (this.config!.show_name === false) {
|
|
return undefined;
|
|
}
|
|
let name: string | undefined;
|
|
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;
|
|
}
|
|
|
|
private _buildStateString(state: HassEntity | undefined): string | undefined {
|
|
let stateString: string | undefined;
|
|
if (this.config!.show_state && state && state.state) {
|
|
const localizedState = computeStateDisplay(
|
|
this.hass!.localize,
|
|
state,
|
|
this.hass!.language
|
|
);
|
|
const units = this._buildUnits(state);
|
|
if (units) {
|
|
stateString = `${state.state} ${units}`;
|
|
} else if (computeDomain(state.entity_id) === "timer") {
|
|
stateString = this._computeTimeDisplay(state);
|
|
} else {
|
|
stateString = localizedState;
|
|
}
|
|
}
|
|
return stateString;
|
|
}
|
|
|
|
private _buildUnits(state: HassEntity | undefined): string | undefined {
|
|
let units: string | undefined;
|
|
if (state) {
|
|
if (this.config!.show_units) {
|
|
if (
|
|
state.attributes &&
|
|
state.attributes.unit_of_measurement &&
|
|
!this.config!.units
|
|
) {
|
|
units = state.attributes.unit_of_measurement;
|
|
} else {
|
|
units = this.config!.units ? this.config!.units : undefined;
|
|
}
|
|
}
|
|
}
|
|
return units;
|
|
}
|
|
|
|
private _buildLastChanged(
|
|
state: HassEntity | undefined,
|
|
style: StyleInfo
|
|
): TemplateResult | undefined {
|
|
return this.config!.show_last_changed && state
|
|
? html`
|
|
<ha-relative-time
|
|
id="label"
|
|
class="ellipsis"
|
|
.hass="${this.hass}"
|
|
.datetime="${state.last_changed}"
|
|
style=${styleMap(style)}
|
|
></ha-relative-time>
|
|
`
|
|
: undefined;
|
|
}
|
|
|
|
private _buildLabel(
|
|
state: HassEntity | undefined,
|
|
configState: StateConfig | undefined
|
|
): string | undefined {
|
|
if (!this.config!.show_label) {
|
|
return undefined;
|
|
}
|
|
let label: string | undefined;
|
|
let matchingLabelTemplate: string | undefined;
|
|
|
|
if (configState && configState.label_template) {
|
|
matchingLabelTemplate = configState.label_template;
|
|
} else {
|
|
matchingLabelTemplate = this.config!.label_template;
|
|
}
|
|
if (!matchingLabelTemplate) {
|
|
if (configState && configState.label) {
|
|
label = configState.label;
|
|
} else {
|
|
label = this.config!.label;
|
|
}
|
|
return label;
|
|
}
|
|
|
|
/* eslint no-new-func: 0 */
|
|
return new Function(
|
|
"states",
|
|
"entity",
|
|
"user",
|
|
"hass",
|
|
`'use strict'; ${matchingLabelTemplate}`
|
|
).call(this, this.hass!.states, state, this.hass!.user, this.hass);
|
|
}
|
|
|
|
private _isClickable(state: HassEntity | undefined): boolean {
|
|
let clickable = true;
|
|
if (
|
|
(this.config!.tap_action!.action === "toggle" &&
|
|
this.config!.hold_action!.action === "none") ||
|
|
(this.config!.hold_action!.action === "toggle" &&
|
|
this.config!.tap_action!.action === "none")
|
|
) {
|
|
if (state) {
|
|
switch (computeDomain(state.entity_id)) {
|
|
case "sensor":
|
|
case "binary_sensor":
|
|
case "device_tracker":
|
|
clickable = false;
|
|
break;
|
|
default:
|
|
clickable = true;
|
|
break;
|
|
}
|
|
} else {
|
|
clickable = false;
|
|
}
|
|
} else if (
|
|
this.config!.tap_action!.action != "none" ||
|
|
this.config!.hold_action!.action != "none"
|
|
) {
|
|
clickable = true;
|
|
} else {
|
|
clickable = false;
|
|
}
|
|
return clickable;
|
|
}
|
|
|
|
private _rotate(configState: StateConfig | undefined): Boolean {
|
|
return configState && configState.spin ? true : false;
|
|
}
|
|
|
|
private _blankCardColoredHtml(cardStyle: StyleInfo): TemplateResult {
|
|
const blankCardStyle = {
|
|
background: "none",
|
|
"box-shadow": "none",
|
|
...cardStyle
|
|
};
|
|
return html`
|
|
<ha-card class="disabled" style=${styleMap(blankCardStyle)}>
|
|
<div></div>
|
|
</ha-card>
|
|
`;
|
|
}
|
|
|
|
private _cardHtml(): TemplateResult {
|
|
const state = this.config!.entity
|
|
? this.hass!.states[this.config!.entity]
|
|
: undefined;
|
|
const configState = this._getMatchingConfigState(state);
|
|
const color = this._buildCssColorAttribute(state, configState);
|
|
let buttonColor = color;
|
|
let cardStyle: StyleInfo = {};
|
|
let lockStyle: StyleInfo = {};
|
|
const lockStyleFromConfig = this._buildStyleGeneric(configState, "lock");
|
|
const configCardStyle = this._buildStyleGeneric(configState, "card");
|
|
|
|
if (configCardStyle.width) {
|
|
this.style.setProperty("flex", "0 0 auto");
|
|
this.style.setProperty("max-width", "fit-content");
|
|
}
|
|
switch (this.config!.color_type) {
|
|
case "blank-card":
|
|
return this._blankCardColoredHtml(configCardStyle);
|
|
case "card":
|
|
case "label-card": {
|
|
const fontColor = getFontColorBasedOnBackgroundColor(color);
|
|
cardStyle.color = fontColor;
|
|
lockStyle.color = fontColor;
|
|
cardStyle["background-color"] = color;
|
|
cardStyle = { ...cardStyle, ...configCardStyle };
|
|
buttonColor = "inherit";
|
|
break;
|
|
}
|
|
default:
|
|
cardStyle = configCardStyle;
|
|
break;
|
|
}
|
|
this.style.setProperty(
|
|
"--button-card-light-color",
|
|
this._getColorForLightEntity(state)
|
|
);
|
|
lockStyle = { ...lockStyle, ...lockStyleFromConfig };
|
|
|
|
return html`
|
|
<ha-card
|
|
class="button-card-main ${this._isClickable(state) ? "" : "disabled"}"
|
|
style=${styleMap(cardStyle)}
|
|
@ha-click="${this._handleTap}"
|
|
@ha-hold="${this._handleHold}"
|
|
@ha-dblclick=${this._handleDblTap}
|
|
.hasDblClick=${this.config!.dbltap_action!.action !== "none"}
|
|
.repeat=${ifDefined(this.config!.hold_action!.repeat)}
|
|
.longpress="${longPress()}"
|
|
.config="${this.config}"
|
|
>
|
|
${this._getLock(lockStyle)}
|
|
${this._buttonContent(state, configState, buttonColor)}
|
|
${this.config!.lock
|
|
? ""
|
|
: html`
|
|
<mwc-ripple id="ripple"></mwc-ripple>
|
|
`}
|
|
</ha-card>
|
|
`;
|
|
}
|
|
|
|
private _getLock(lockStyle: StyleInfo): TemplateResult {
|
|
if (this.config!.lock) {
|
|
return html`
|
|
<div id="overlay" style=${styleMap(lockStyle)} @click=${
|
|
this._handleLock
|
|
} @touchstart=${this._handleLock}>
|
|
<ha-icon id="lock" icon="mdi:lock-outline"></iron-icon>
|
|
</div>
|
|
`;
|
|
}
|
|
return html``;
|
|
}
|
|
|
|
private _buttonContent(
|
|
state: HassEntity | undefined,
|
|
configState: StateConfig | undefined,
|
|
color: string
|
|
): TemplateResult {
|
|
const name = this._buildName(state, configState);
|
|
const stateString = this._buildStateString(state);
|
|
const nameStateString = buildNameStateConcat(name, stateString);
|
|
|
|
switch (this.config!.layout) {
|
|
case "icon_name_state":
|
|
case "name_state":
|
|
return this._gridHtml(
|
|
state,
|
|
configState,
|
|
this.config!.layout,
|
|
color,
|
|
nameStateString,
|
|
undefined
|
|
);
|
|
default:
|
|
return this._gridHtml(
|
|
state,
|
|
configState,
|
|
this.config!.layout,
|
|
color,
|
|
name,
|
|
stateString
|
|
);
|
|
}
|
|
}
|
|
|
|
private _gridHtml(
|
|
state: HassEntity | undefined,
|
|
configState: StateConfig | undefined,
|
|
containerClass: string,
|
|
color: string,
|
|
name: string | undefined,
|
|
stateString: string | undefined
|
|
): TemplateResult {
|
|
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 lastChangedTemplate = this._buildLastChanged(
|
|
state,
|
|
labelStyleFromConfig
|
|
);
|
|
const gridStyleFromConfig = this._buildStyleGeneric(configState, "grid");
|
|
if (!iconTemplate) itemClass.push("no-icon");
|
|
if (!name) itemClass.push("no-name");
|
|
if (!stateString) itemClass.push("no-state");
|
|
if (!label && !lastChangedTemplate) itemClass.push("no-label");
|
|
|
|
return html`
|
|
<div
|
|
id="container"
|
|
class=${itemClass.join(" ")}
|
|
style=${styleMap(gridStyleFromConfig)}
|
|
>
|
|
${iconTemplate ? iconTemplate : ""}
|
|
${name
|
|
? html`
|
|
<div
|
|
id="name"
|
|
class="ellipsis"
|
|
style=${styleMap(nameStyleFromConfig)}
|
|
>
|
|
${name}
|
|
</div>
|
|
`
|
|
: ""}
|
|
${stateString
|
|
? html`
|
|
<div
|
|
id="state"
|
|
class="ellipsis"
|
|
style=${styleMap(stateStyleFromConfig)}
|
|
>
|
|
${stateString}
|
|
</div>
|
|
`
|
|
: ""}
|
|
${label && !lastChangedTemplate
|
|
? html`
|
|
<div
|
|
id="label"
|
|
class="ellipsis"
|
|
style=${styleMap(labelStyleFromConfig)}
|
|
>
|
|
${unsafeHTML(label)}
|
|
</div>
|
|
`
|
|
: ""}
|
|
${lastChangedTemplate ? lastChangedTemplate : ""}
|
|
</div>
|
|
`;
|
|
}
|
|
|
|
private _getIconHtml(
|
|
state: HassEntity | undefined,
|
|
configState: StateConfig | undefined,
|
|
color: string
|
|
): 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 haIconStyle = {
|
|
color,
|
|
width: this.config!.size,
|
|
...haIconStyleFromConfig
|
|
};
|
|
const entityPictureStyle = {
|
|
...haIconStyle,
|
|
...entityPictureStyleFromConfig
|
|
};
|
|
|
|
if (icon || entityPicture) {
|
|
return html`
|
|
<div id="img-cell" style=${styleMap(imgCellStyleFromConfig)}>
|
|
${icon && !entityPicture
|
|
? html`
|
|
<ha-icon
|
|
style=${styleMap(haIconStyle)}
|
|
.icon="${icon}"
|
|
id="icon"
|
|
?rotating=${this._rotate(configState)}
|
|
></ha-icon>
|
|
`
|
|
: ""}
|
|
${entityPicture
|
|
? html`
|
|
<img
|
|
src="${entityPicture}"
|
|
style=${styleMap(entityPictureStyle)}
|
|
id="icon"
|
|
?rotating=${this._rotate(configState)}
|
|
/>
|
|
`
|
|
: ""}
|
|
</div>
|
|
`;
|
|
} else {
|
|
return undefined;
|
|
}
|
|
}
|
|
|
|
public setConfig(config: ButtonCardConfig): void {
|
|
if (!config) {
|
|
throw new Error("Invalid configuration");
|
|
}
|
|
|
|
this.config = {
|
|
tap_action: { action: "toggle" },
|
|
hold_action: { action: "none" },
|
|
dbltap_action: { action: "none" },
|
|
layout: "vertical",
|
|
size: "40%",
|
|
color_type: "icon",
|
|
show_name: true,
|
|
show_state: false,
|
|
show_icon: true,
|
|
show_units: true,
|
|
show_label: false,
|
|
show_entity_picture: false,
|
|
...config
|
|
};
|
|
this.config!.default_color = "var(--primary-text-color)";
|
|
if (this.config!.color_type !== "icon") {
|
|
this.config!.color_off = "var(--paper-card-background-color)";
|
|
} else {
|
|
this.config!.color_off = "var(--paper-item-icon-color)";
|
|
}
|
|
this.config!.color_on = "var(--paper-item-icon-active-color)";
|
|
|
|
/* Temporary until we deprecate style and entity_picture_style config option */
|
|
if (!this.config.styles) {
|
|
this.config.styles = {};
|
|
}
|
|
if (this.config.style && !this.config.styles.card) {
|
|
this.config.styles.card = this.config.style;
|
|
}
|
|
if (
|
|
this.config.entity_picture_style &&
|
|
!this.config.styles.entity_picture
|
|
) {
|
|
this.config.styles.entity_picture = this.config.entity_picture_style;
|
|
}
|
|
if (this.config.state) {
|
|
/* eslint no-param-reassign: ["error", { "props": false }] */
|
|
this.config.state.forEach(s => {
|
|
if (!s.styles) {
|
|
s.styles = {};
|
|
}
|
|
if (s.entity_picture_style && !s.styles.entity_picture) {
|
|
s.styles.entity_picture = s.entity_picture_style;
|
|
}
|
|
if (s.style && !s.styles.card) {
|
|
s.styles.card = s.style;
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
// The height of your card. Home Assistant uses this to automatically
|
|
// distribute all cards over the available columns.
|
|
public getCardSize(): number {
|
|
return 3;
|
|
}
|
|
|
|
private _handleTap(ev): void {
|
|
/* eslint no-alert: 0 */
|
|
if (
|
|
this.config!.confirmation &&
|
|
!window.confirm(this.config!.confirmation)
|
|
) {
|
|
return;
|
|
}
|
|
const config = ev.target.config;
|
|
handleClick(this, this.hass!, config, false, false);
|
|
}
|
|
|
|
private _handleHold(ev): void {
|
|
/* eslint no-alert: 0 */
|
|
if (
|
|
this.config!.confirmation &&
|
|
!window.confirm(this.config!.confirmation)
|
|
) {
|
|
return;
|
|
}
|
|
const config = ev.target.config;
|
|
handleClick(this, this.hass!, config, true, false);
|
|
}
|
|
|
|
private _handleDblTap(ev): void {
|
|
/* eslint no-alert: 0 */
|
|
if (
|
|
this.config!.confirmation &&
|
|
!window.confirm(this.config!.confirmation)
|
|
) {
|
|
return;
|
|
}
|
|
const config = ev.target.config;
|
|
handleClick(this, this.hass!, config, false, true);
|
|
}
|
|
|
|
private _handleLock(ev): void {
|
|
ev.stopPropagation();
|
|
const overlay = this.shadowRoot!.getElementById("overlay") as LitElement;
|
|
const haCard = this.shadowRoot!.firstElementChild as LitElement;
|
|
overlay.style.setProperty("pointer-events", "none");
|
|
const paperRipple = document.createElement("paper-ripple");
|
|
|
|
const lock = this.shadowRoot!.getElementById("lock") as LitElement;
|
|
if (lock) {
|
|
haCard.appendChild(paperRipple);
|
|
const icon = document.createAttribute("icon");
|
|
icon.value = "mdi:lock-open-outline";
|
|
lock.attributes.setNamedItem(icon);
|
|
lock.classList.add("fadeOut");
|
|
}
|
|
window.setTimeout(() => {
|
|
overlay.style.setProperty("pointer-events", "");
|
|
if (lock) {
|
|
lock.classList.remove("fadeOut");
|
|
const icon = document.createAttribute("icon");
|
|
icon.value = "mdi:lock-outline";
|
|
lock.attributes.setNamedItem(icon);
|
|
haCard.removeChild(paperRipple);
|
|
}
|
|
}, 5000);
|
|
}
|
|
}
|