Skip to content

Commit

Permalink
Replace Polymer with LitElement + major refactoring
Browse files Browse the repository at this point in the history
- Now hopefully supports HA Cast (#20)
- Support for displaying icons for additional entities (#19)
- Fix unsupported toggle state for climate entities (#18)
  • Loading branch information
benct committed Jan 7, 2020
1 parent f47f0e3 commit ffdf82e
Showing 1 changed file with 121 additions and 151 deletions.
272 changes: 121 additions & 151 deletions multiple-entity-row.js
Original file line number Diff line number Diff line change
@@ -1,145 +1,114 @@
class MultipleEntityRow extends Polymer.Element {

static get template() {
return Polymer.html`
<style>
:host {
display: flex;
align-items: center;
}
.flex {
flex: 1;
margin-left: 16px;
display: flex;
justify-content: space-between;
align-items: center;
min-width: 0;
}
.info {
flex: 1 0 60px;
cursor: pointer;
}
.info, .info > * {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.flex ::slotted(*) {
margin-left: 8px;
min-width: 0;
}
.flex ::slotted([slot="secondary"]) {
margin-left: 0;
}
.secondary, ha-relative-time {
display: block;
color: var(--secondary-text-color);
}
state-badge {
flex: 0 0 40px;
cursor: pointer;
}
.entity {
margin-right: 16px;
text-align: center;
cursor: pointer;
}
.entity span {
font-size: 10px;
color: var(--secondary-text-color);
}
.entity:last-of-type {
margin-right: 0;
}
.state {
min-width: 45px;
}
.toggle {
margin-left: 8px;
}
</style>
<state-badge state-obj="[[main.stateObj]]" override-icon="[[main.icon]]" on-click="defaultMoreInfo"></state-badge>
<div class="flex" on-click="defaultMoreInfo">
<div class="info">
[[entityName(main)]]
<div class="secondary">
<template is="dom-if" if="{{info}}">
[[entityName(info)]] [[entityState(info)]]
</template>
<template is="dom-if" if="{{showLastChanged}}">
<ha-relative-time datetime="[[main.stateObj.last_changed]]" hass="[[_hass]]"></ha-relative-time>
</template>
</div>
</div>
<template is="dom-if" if="{{primary}}">
<div class="entity" on-click="primaryMoreInfo">
<span>[[entityName(primary)]]</span>
<div>
<template is="dom-if" if="{{primary.showToggle}}">
<ha-entity-toggle state-obj="[[primary.stateObj]]" hass="[[_hass]]"></ha-entity-toggle>
</template>
<template is="dom-if" if="{{!primary.showToggle}}">[[entityState(primary)]]</template>
</div>
</div>
</template>
<template is="dom-if" if="{{secondary}}">
<div class="entity" on-click="secondaryMoreInfo">
<span>[[entityName(secondary)]]</span>
<div>
<template is="dom-if" if="{{secondary.showToggle}}">
<ha-entity-toggle state-obj="[[secondary.stateObj]]" hass="[[_hass]]"></ha-entity-toggle>
</template>
<template is="dom-if" if="{{!secondary.showToggle}}">[[entityState(secondary)]]</template>
</div>
</div>
</template>
<template is="dom-if" if="{{tertiary}}">
<div class="entity" on-click="tertiaryMoreInfo">
<span>[[entityName(tertiary)]]</span>
<div>
<template is="dom-if" if="{{tertiary.showToggle}}">
<ha-entity-toggle state-obj="[[tertiary.stateObj]]" hass="[[_hass]]"></ha-entity-toggle>
</template>
<template is="dom-if" if="{{!tertiary.showToggle}}">[[entityState(tertiary)]]</template>
</div>
</div>
</template>
<template is="dom-if" if="{{!main.hide_state}}">
<div class="state entity">
<template is="dom-if" if="{{showMainHeader}}">
<span>[[_config.name_state]]</span>
</template>
<template is="dom-if" if="{{main.showToggle}}">
<div class="toggle">
<ha-entity-toggle state-obj="[[main.stateObj]]" hass="[[_hass]]"></ha-entity-toggle>
</div>
</template>
<template is="dom-if" if="{{!main.showToggle}}">
<div>[[entityState(main)]]</div>
</template>
</div>
</template>
</div>`;
}
const LitElement = Object.getPrototypeOf(customElements.get("hui-view"));
const html = LitElement.prototype.html;
const css = LitElement.prototype.css;

defaultMoreInfo(e) {
e.stopPropagation();
this.fireEvent(this.main.entity);
class MultipleEntityRow extends LitElement {

static get properties() {
return {
_hass: {},
_config: {},
state: {}
}
}

primaryMoreInfo(e) {
e.stopPropagation();
this.fireEvent(this.primary.entity);
static get styles() {
return css`
:host {
display: flex;
align-items: center;
}
.flex {
flex: 1;
margin-left: 16px;
display: flex;
justify-content: space-between;
align-items: center;
min-width: 0;
}
.info {
flex: 1 0 60px;
cursor: pointer;
}
.info, .info > * {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.flex ::slotted(*) {
margin-left: 8px;
min-width: 0;
}
.flex ::slotted([slot="secondary"]) {
margin-left: 0;
}
.secondary, ha-relative-time {
display: block;
color: var(--secondary-text-color);
}
state-badge {
flex: 0 0 40px;
cursor: pointer;
}
.entity {
margin-right: 16px;
text-align: center;
cursor: pointer;
}
.entity span {
font-size: 10px;
color: var(--secondary-text-color);
}
.entity:last-of-type {
margin-right: 0;
}
.state {
min-width: 45px;
}
.toggle {
margin-left: 8px;
}`;
}

secondaryMoreInfo(e) {
e.stopPropagation();
this.fireEvent(this.secondary.entity);
renderEntity(data) {
return data ? html`
<div class="entity" @click="${() => this.fireEvent(data.entity)}">
<span>${this.entityName(data)}</span>
<div>${data.showToggle
? html`<ha-entity-toggle .stateObj="${data.stateObj}" .hass="${this._hass}"></ha-entity-toggle>`
: data.showIcon ? html`<ha-icon icon="${data.showIcon}"></ha-icon>` : this.entityState(data)}
</div>
</div>` : null;
}

tertiaryMoreInfo(e) {
e.stopPropagation();
this.fireEvent(this.tertiary.entity);
render() {
return html`
<state-badge
.stateObj="${this.state.main.stateObj}"
.overrideIcon="${this.state.main.icon}"
@click="${this.defaultMoreInfo}">
</state-badge>
<div class="flex">
<div class="info" @click="${this.defaultMoreInfo}">
${this.entityName(this.state.main)}
<div class="secondary">
${this.state.info && `${this.entityName(this.state.info)} ${this.entityState(this.state.info)}`}
${this.state.showLastChanged
? html`<ha-relative-time datetime="${this.state.main.stateObj.last_changed}" .hass="${this._hass}"></ha-relative-time>`
: null}
</div>
</div>
${this.renderEntity(this.state.primary)}
${this.renderEntity(this.state.secondary)}
${this.renderEntity(this.state.tertiary)}
${!this.state.main.hide_state ? html`
<div class="state entity">
${this.state.main.name_state && html`<span>${this.state.main.name_state}</span>`}
${this.state.main.showToggle
? html`<div class="toggle"><ha-entity-toggle .stateObj="${this.state.main.stateObj}" .hass="${this._hass}"></ha-entity-toggle></div>`
: html`<div @click="${this.defaultMoreInfo}">${this.entityState(this.state.main)}</div>`}
</div>` : null}
</div>`;
}

entityName(data) {
Expand Down Expand Up @@ -195,37 +164,39 @@ class MultipleEntityRow extends Polymer.Element {
if (config.tertiary && !config.tertiary.entity) throw new Error('Please define a tertiary entity.');
if (config.info && !config.info.entity) throw new Error('Please define an info entity.');

this.showMainHeader = config.name_state;
this.showLastChanged = config.secondary_info === 'last-changed' && !config.info;

this.state = {
showLastChanged: config.secondary_info === 'last-changed' && !config.info
};
this._config = config;
}

set hass(hass) {
this._hass = hass;

if (hass && this._config) {
const stateObj = this._config.entity in hass.states ? hass.states[this._config.entity] : null;
if (stateObj) {
this.main = this.initEntity(this._config);
this.primary = this.initEntity(this._config.primary);
this.secondary = this.initEntity(this._config.secondary);
this.tertiary = this.initEntity(this._config.tertiary);
this.info = this.initEntity(this._config.info);
this.state = {
...this.state,
main: this.initEntity(this._config),
primary: this.initEntity(this._config.primary),
secondary: this.initEntity(this._config.secondary),
tertiary: this.initEntity(this._config.tertiary),
info: this.initEntity(this._config.info)
}
}
}

initEntity(config) {
const stateObj = config && config.entity && this._hass.states[config.entity];
const stateObj = config && this._hass && this._hass.states[config.entity];
return stateObj ? Object.assign({}, config, {
stateObj: stateObj,
showToggle: this.validateToggle(config, stateObj),
showToggle: config.toggle === true && stateObj.state && !["unknown", "unavailable"].includes(stateObj.state),
showIcon: config.icon === true ? stateObj.attributes.icon : config.icon
}) : null;
}

validateToggle(config, stateObj) {
return config && config.toggle === true && stateObj && (stateObj.state === "on" || stateObj.state === "off");
defaultMoreInfo(e) {
e.stopPropagation();
this.fireEvent(this.state.main.entity);
}

fireEvent(entity, options = {}) {
Expand All @@ -235,8 +206,7 @@ class MultipleEntityRow extends Polymer.Element {
composed: options.composed || true,
});
event.detail = {entityId: entity};
this.shadowRoot.dispatchEvent(event);
return event;
this.dispatchEvent(event);
}
}

Expand Down

0 comments on commit ffdf82e

Please sign in to comment.