Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
126 changes: 126 additions & 0 deletions src/components/ha-date-input.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
import {
html,
css,
LitElement,
TemplateResult,
property,
customElement,
} from "lit-element";

import "@polymer/paper-input/paper-input";
// tslint:disable-next-line:no-duplicate-imports
import { PaperInputElement } from "@polymer/paper-input/paper-input";

@customElement("ha-date-input")
export class HaDateInput extends LitElement {
@property() public year?: string;
@property() public month?: string;
@property() public day?: string;
@property({ type: Boolean }) public disabled = false;

static get styles() {
return css`
:host {
display: block;
font-family: var(--paper-font-common-base_-_font-family);
-webkit-font-smoothing: var(
--paper-font-common-base_-_-webkit-font-smoothing
);
}

paper-input {
width: 30px;
text-align: center;
--paper-input-container-input_-_-moz-appearance: textfield;
--paper-input-container-input-webkit-spinner_-_-webkit-appearance: none;
--paper-input-container-input-webkit-spinner_-_margin: 0;
--paper-input-container-input-webkit-spinner_-_display: none;
}

paper-input#year {
width: 50px;
}

.date-input-wrap {
display: flex;
flex-direction: row;
}
`;
}

protected render(): TemplateResult {
return html`
<div class="date-input-wrap">
<paper-input
Comment thread
thomasloven marked this conversation as resolved.
id="year"
type="number"
.value=${this.year}
@change=${this._formatYear}
maxlength="4"
max="9999"
min="0"
.disabled=${this.disabled}
no-label-float
>
<span suffix="" slot="suffix">-</span>
</paper-input>
<paper-input
id="month"
type="number"
.value=${this.month}
@change=${this._formatMonth}
maxlength="2"
max="12"
min="1"
.disabled=${this.disabled}
no-label-float
>
<span suffix="" slot="suffix">-</span>
</paper-input>
<paper-input
id="day"
type="number"
.value=${this.day}
@change=${this._formatDay}
maxlength="2"
max="31"
min="1"
.disabled=${this.disabled}
no-label-float
>
</paper-input>
</div>
`;
}

private _formatYear() {
const yearElement = this.shadowRoot!.getElementById(
"year"
) as PaperInputElement;
this.year = yearElement.value!;
}

private _formatMonth() {
const monthElement = this.shadowRoot!.getElementById(
"month"
) as PaperInputElement;
this.month = ("0" + monthElement.value!).slice(-2);
}

private _formatDay() {
const dayElement = this.shadowRoot!.getElementById(
"day"
) as PaperInputElement;
this.day = ("0" + dayElement.value!).slice(-2);
}

get value() {
return `${this.year}-${this.month}-${this.day}`;
}
}

declare global {
interface HTMLElementTagNameMap {
"ha-date-input": HaDateInput;
}
}
2 changes: 1 addition & 1 deletion src/components/paper-time-input.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import "@polymer/paper-dropdown-menu/paper-dropdown-menu";
import { html } from "@polymer/polymer/lib/utils/html-tag";
import { PolymerElement } from "@polymer/polymer/polymer-element";

class PaperTimeInput extends PolymerElement {
export class PaperTimeInput extends PolymerElement {
static get template() {
return html`
<style>
Expand Down
11 changes: 11 additions & 0 deletions src/data/input_datetime.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { HomeAssistant } from "../types";

export const setInputDateTimeValue = (
hass: HomeAssistant,
entityId: string,
time: string | undefined = undefined,
date: string | undefined = undefined
) => {
const param = { entity_id: entityId, time, date };
hass.callService(entityId.split(".", 1)[0], "set_datetime", param);
};
2 changes: 2 additions & 0 deletions src/panels/lovelace/common/create-row-element.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
import "../entity-rows/hui-climate-entity-row";
import "../entity-rows/hui-cover-entity-row";
import "../entity-rows/hui-group-entity-row";
import "../entity-rows/hui-input-datetime-entity-row";
import "../entity-rows/hui-input-number-entity-row";
import "../entity-rows/hui-input-select-entity-row";
import "../entity-rows/hui-input-text-entity-row";
Expand Down Expand Up @@ -58,6 +59,7 @@ const DOMAIN_TO_ELEMENT_TYPE = {
// Temporary. Once climate is rewritten,
// water heater should get it's own row.
water_heater: "climate",
input_datetime: "input-datetime",
};
const TIMEOUT = 2000;

Expand Down
128 changes: 128 additions & 0 deletions src/panels/lovelace/entity-rows/hui-input-datetime-entity-row.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
import {
html,
LitElement,
TemplateResult,
property,
PropertyValues,
customElement,
} from "lit-element";

import "../components/hui-generic-entity-row";
import "../../../components/paper-time-input.js";
// tslint:disable-next-line:no-duplicate-imports
import { PaperTimeInput } from "../../../components/paper-time-input.js";
import "../../../components/ha-date-input";
// tslint:disable-next-line:no-duplicate-imports
import { HaDateInput } from "../../../components/ha-date-input";

import { HomeAssistant } from "../../../types";
import { EntityRow, EntityConfig } from "./types";
import { setInputDateTimeValue } from "../../../data/input_datetime";
import { hasConfigOrEntityChanged } from "../common/has-changed";

@customElement("hui-input-datetime-entity-row")
class HuiInputDatetimeEntityRow extends LitElement implements EntityRow {
@property() public hass?: HomeAssistant;
@property() private _config?: EntityConfig;

public setConfig(config: EntityConfig): void {
if (!config) {
throw new Error("Configuration error");
}
this._config = config;
}

protected shouldUpdate(changedProps: PropertyValues): boolean {
return hasConfigOrEntityChanged(this, changedProps);
}

protected render(): TemplateResult | void {
if (!this._config || !this.hass) {
return html``;
}

const stateObj = this.hass.states[this._config.entity];

if (!stateObj) {
return html`
<hui-warning
>${this.hass.localize(
"ui.panel.lovelace.warning.entity_not_found",
"entity",
this._config.entity
)}</hui-warning
>
`;
}

return html`
<hui-generic-entity-row .hass="${this.hass}" .config="${this._config}">
${stateObj.attributes.has_date
? html`
<ha-date-input
.year=${stateObj.attributes.year}
.month=${("0" + stateObj.attributes.month).slice(-2)}
.day=${("0" + stateObj.attributes.day).slice(-2)}
@change=${this._selectedValueChanged}
@click=${this._stopEventPropagation}
></ha-date-input>
${stateObj.attributes.has_time ? "," : ""}
`
: ``}
${stateObj.attributes.has_time
? html`
<paper-time-input
.hour=${stateObj.state === "unknown"
? ""
: ("0" + stateObj.attributes.hour).slice(-2)}
.min=${stateObj.state === "unknown"
? ""
: ("0" + stateObj.attributes.minute).slice(-2)}
.amPm=${false}
@change=${this._selectedValueChanged}
@click=${this._stopEventPropagation}
hide-label
format="24"
></paper-time-input>
`
: ``}
</hui-generic-entity-row>
`;
}

private _stopEventPropagation(ev: Event): void {
ev.stopPropagation();
}

private get _timeInputEl(): PaperTimeInput {
return this.shadowRoot!.querySelector("paper-time-input")!;
}

private get _dateInputEl(): HaDateInput {
return this.shadowRoot!.querySelector("ha-date-input")!;
}

private _selectedValueChanged(ev): void {
const stateObj = this.hass!.states[this._config!.entity];

const time =
this._timeInputEl !== null
? this._timeInputEl.value.trim() + ":00"
: undefined;

const date =
this._dateInputEl !== null ? this._dateInputEl.value : undefined;

if (time !== stateObj.state) {
setInputDateTimeValue(this.hass!, stateObj.entity_id, time, date);
}

ev.target.blur();
}
}

declare global {
interface HTMLElementTagNameMap {
"hui-input-datetime-entity-row": HuiInputDatetimeEntityRow;
}
}