mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-28 19:56:42 +00:00
Add support for delay values split into parts + millisecond time input (#7886)
Co-authored-by: Bram Kragten <mail@bramkragten.nl>
This commit is contained in:
parent
8400e90e34
commit
ed368ddd9d
@ -6,8 +6,7 @@ import {
|
||||
query,
|
||||
TemplateResult,
|
||||
} from "lit-element";
|
||||
import { fireEvent } from "../../common/dom/fire_event";
|
||||
import "../paper-time-input";
|
||||
import "../ha-time-input";
|
||||
import { HaFormElement, HaFormTimeData, HaFormTimeSchema } from "./ha-form";
|
||||
|
||||
@customElement("ha-form-positive_time_period_dict")
|
||||
@ -20,7 +19,7 @@ export class HaFormTimePeriod extends LitElement implements HaFormElement {
|
||||
|
||||
@property() public suffix!: string;
|
||||
|
||||
@query("paper-time-input", true) private _input?: HTMLElement;
|
||||
@query("ha-time-input", true) private _input?: HTMLElement;
|
||||
|
||||
public focus() {
|
||||
if (this._input) {
|
||||
@ -30,86 +29,13 @@ export class HaFormTimePeriod extends LitElement implements HaFormElement {
|
||||
|
||||
protected render(): TemplateResult {
|
||||
return html`
|
||||
<paper-time-input
|
||||
<ha-time-input
|
||||
.label=${this.label}
|
||||
.required=${this.schema.required}
|
||||
.autoValidate=${this.schema.required}
|
||||
error-message="Required"
|
||||
enable-second
|
||||
format="24"
|
||||
.hour=${this._parseDuration(this._hours)}
|
||||
.min=${this._parseDuration(this._minutes)}
|
||||
.sec=${this._parseDuration(this._seconds)}
|
||||
@hour-changed=${this._hourChanged}
|
||||
@min-changed=${this._minChanged}
|
||||
@sec-changed=${this._secChanged}
|
||||
float-input-labels
|
||||
no-hours-limit
|
||||
always-float-input-labels
|
||||
hour-label="hh"
|
||||
min-label="mm"
|
||||
sec-label="ss"
|
||||
></paper-time-input>
|
||||
.data=${this.data}
|
||||
></ha-time-input>
|
||||
`;
|
||||
}
|
||||
|
||||
private get _hours() {
|
||||
return this.data && this.data.hours ? Number(this.data.hours) : 0;
|
||||
}
|
||||
|
||||
private get _minutes() {
|
||||
return this.data && this.data.minutes ? Number(this.data.minutes) : 0;
|
||||
}
|
||||
|
||||
private get _seconds() {
|
||||
return this.data && this.data.seconds ? Number(this.data.seconds) : 0;
|
||||
}
|
||||
|
||||
private _parseDuration(value) {
|
||||
return value.toString().padStart(2, "0");
|
||||
}
|
||||
|
||||
private _hourChanged(ev) {
|
||||
this._durationChanged(ev, "hours");
|
||||
}
|
||||
|
||||
private _minChanged(ev) {
|
||||
this._durationChanged(ev, "minutes");
|
||||
}
|
||||
|
||||
private _secChanged(ev) {
|
||||
this._durationChanged(ev, "seconds");
|
||||
}
|
||||
|
||||
private _durationChanged(ev, unit) {
|
||||
let value = Number(ev.detail.value);
|
||||
|
||||
if (value === this[`_${unit}`]) {
|
||||
return;
|
||||
}
|
||||
|
||||
let hours = this._hours;
|
||||
let minutes = this._minutes;
|
||||
|
||||
if (unit === "seconds" && value > 59) {
|
||||
minutes += Math.floor(value / 60);
|
||||
value %= 60;
|
||||
}
|
||||
|
||||
if (unit === "minutes" && value > 59) {
|
||||
hours += Math.floor(value / 60);
|
||||
value %= 60;
|
||||
}
|
||||
|
||||
fireEvent(this, "value-changed", {
|
||||
value: {
|
||||
hours,
|
||||
minutes,
|
||||
seconds: this._seconds,
|
||||
...{ [unit]: value },
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
declare global {
|
||||
|
@ -8,6 +8,7 @@ import {
|
||||
} from "lit-element";
|
||||
import { dynamicElement } from "../../common/dom/dynamic-element-directive";
|
||||
import { fireEvent } from "../../common/dom/fire_event";
|
||||
import { HaTimeData } from "../ha-time-input";
|
||||
import "./ha-form-boolean";
|
||||
import "./ha-form-constant";
|
||||
import "./ha-form-float";
|
||||
@ -71,7 +72,7 @@ export interface HaFormBooleanSchema extends HaFormBaseSchema {
|
||||
}
|
||||
|
||||
export interface HaFormTimeSchema extends HaFormBaseSchema {
|
||||
type: "time";
|
||||
type: "positive_time_period_dict";
|
||||
}
|
||||
|
||||
export interface HaFormDataContainer {
|
||||
@ -93,11 +94,7 @@ export type HaFormFloatData = number;
|
||||
export type HaFormBooleanData = boolean;
|
||||
export type HaFormSelectData = string;
|
||||
export type HaFormMultiSelectData = string[];
|
||||
export interface HaFormTimeData {
|
||||
hours?: number;
|
||||
minutes?: number;
|
||||
seconds?: number;
|
||||
}
|
||||
export type HaFormTimeData = HaTimeData;
|
||||
|
||||
export interface HaFormElement extends LitElement {
|
||||
schema: HaFormSchema | HaFormSchema[];
|
||||
|
146
src/components/ha-time-input.ts
Normal file
146
src/components/ha-time-input.ts
Normal file
@ -0,0 +1,146 @@
|
||||
import {
|
||||
customElement,
|
||||
html,
|
||||
LitElement,
|
||||
property,
|
||||
query,
|
||||
TemplateResult,
|
||||
} from "lit-element";
|
||||
import { fireEvent } from "../common/dom/fire_event";
|
||||
import "./paper-time-input";
|
||||
|
||||
export interface HaTimeData {
|
||||
hours?: number;
|
||||
minutes?: number;
|
||||
seconds?: number;
|
||||
milliseconds?: number;
|
||||
}
|
||||
|
||||
@customElement("ha-time-input")
|
||||
class HaTimeInput extends LitElement {
|
||||
@property() public data!: HaTimeData;
|
||||
|
||||
@property() public label?: string;
|
||||
|
||||
@property() public suffix?: string;
|
||||
|
||||
@property({ type: Boolean }) public required?: boolean;
|
||||
|
||||
@property({ type: Boolean }) public enableMillisecond?: boolean;
|
||||
|
||||
@query("paper-time-input", true) private _input?: HTMLElement;
|
||||
|
||||
public focus() {
|
||||
if (this._input) {
|
||||
this._input.focus();
|
||||
}
|
||||
}
|
||||
|
||||
protected render(): TemplateResult {
|
||||
return html`
|
||||
<paper-time-input
|
||||
.label=${this.label}
|
||||
.required=${this.required}
|
||||
.autoValidate=${this.required}
|
||||
error-message="Required"
|
||||
enable-second
|
||||
.enableMillisecond=${this.enableMillisecond}
|
||||
format="24"
|
||||
.hour=${this._parseDuration(this._hours)}
|
||||
.min=${this._parseDuration(this._minutes)}
|
||||
.sec=${this._parseDuration(this._seconds)}
|
||||
.millisec=${this._parseDurationMillisec(this._milliseconds)}
|
||||
@hour-changed=${this._hourChanged}
|
||||
@min-changed=${this._minChanged}
|
||||
@sec-changed=${this._secChanged}
|
||||
@millisec-changed=${this._millisecChanged}
|
||||
float-input-labels
|
||||
no-hours-limit
|
||||
always-float-input-labels
|
||||
hour-label="hh"
|
||||
min-label="mm"
|
||||
sec-label="ss"
|
||||
millisec-label="ms"
|
||||
></paper-time-input>
|
||||
`;
|
||||
}
|
||||
|
||||
private get _hours() {
|
||||
return this.data && this.data.hours ? Number(this.data.hours) : 0;
|
||||
}
|
||||
|
||||
private get _minutes() {
|
||||
return this.data && this.data.minutes ? Number(this.data.minutes) : 0;
|
||||
}
|
||||
|
||||
private get _seconds() {
|
||||
return this.data && this.data.seconds ? Number(this.data.seconds) : 0;
|
||||
}
|
||||
|
||||
private get _milliseconds() {
|
||||
return this.data && this.data.milliseconds
|
||||
? Number(this.data.milliseconds)
|
||||
: 0;
|
||||
}
|
||||
|
||||
private _parseDuration(value) {
|
||||
return value.toString().padStart(2, "0");
|
||||
}
|
||||
|
||||
private _parseDurationMillisec(value) {
|
||||
return value.toString().padStart(3, "0");
|
||||
}
|
||||
|
||||
private _hourChanged(ev) {
|
||||
this._durationChanged(ev, "hours");
|
||||
}
|
||||
|
||||
private _minChanged(ev) {
|
||||
this._durationChanged(ev, "minutes");
|
||||
}
|
||||
|
||||
private _secChanged(ev) {
|
||||
this._durationChanged(ev, "seconds");
|
||||
}
|
||||
|
||||
private _millisecChanged(ev) {
|
||||
this._durationChanged(ev, "milliseconds");
|
||||
}
|
||||
|
||||
private _durationChanged(ev, unit) {
|
||||
let value = Number(ev.detail.value);
|
||||
|
||||
if (value === this[`_${unit}`]) {
|
||||
return;
|
||||
}
|
||||
|
||||
let hours = this._hours;
|
||||
let minutes = this._minutes;
|
||||
|
||||
if (unit === "seconds" && value > 59) {
|
||||
minutes += Math.floor(value / 60);
|
||||
value %= 60;
|
||||
}
|
||||
|
||||
if (unit === "minutes" && value > 59) {
|
||||
hours += Math.floor(value / 60);
|
||||
value %= 60;
|
||||
}
|
||||
|
||||
fireEvent(this, "value-changed", {
|
||||
value: {
|
||||
hours,
|
||||
minutes,
|
||||
seconds: this._seconds,
|
||||
milliseconds: this._milliseconds,
|
||||
...{ [unit]: value },
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"ha-time-input": HaTimeInput;
|
||||
}
|
||||
}
|
@ -103,6 +103,10 @@ export class PaperTimeInput extends PolymerElement {
|
||||
[hidden] {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
#millisec {
|
||||
width: 38px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<label hidden$="[[hideLabel]]">[[label]]</label>
|
||||
@ -167,6 +171,28 @@ export class PaperTimeInput extends PolymerElement {
|
||||
always-float-label$="[[alwaysFloatInputLabels]]"
|
||||
disabled="[[disabled]]"
|
||||
hidden$="[[!enableSecond]]"
|
||||
>
|
||||
<span hidden$="[[!enableMillisecond]]" suffix slot="suffix">:</span>
|
||||
</paper-input>
|
||||
|
||||
<!-- Millisec Input -->
|
||||
<paper-input
|
||||
id="millisec"
|
||||
type="number"
|
||||
value="{{millisec}}"
|
||||
label="[[millisecLabel]]"
|
||||
on-change="_formatMillisec"
|
||||
on-focus="_onFocus"
|
||||
required
|
||||
auto-validate="[[autoValidate]]"
|
||||
prevent-invalid-input
|
||||
maxlength="3"
|
||||
max="999"
|
||||
min="0"
|
||||
no-label-float$="[[!floatInputLabels]]"
|
||||
always-float-label$="[[alwaysFloatInputLabels]]"
|
||||
disabled="[[disabled]]"
|
||||
hidden$="[[!enableMillisecond]]"
|
||||
>
|
||||
</paper-input>
|
||||
|
||||
@ -263,6 +289,13 @@ export class PaperTimeInput extends PolymerElement {
|
||||
type: String,
|
||||
notify: true,
|
||||
},
|
||||
/**
|
||||
* milli second
|
||||
*/
|
||||
millisec: {
|
||||
type: String,
|
||||
notify: true,
|
||||
},
|
||||
/**
|
||||
* Suffix for the hour input
|
||||
*/
|
||||
@ -284,6 +317,13 @@ export class PaperTimeInput extends PolymerElement {
|
||||
type: String,
|
||||
value: "",
|
||||
},
|
||||
/**
|
||||
* Suffix for the milli sec input
|
||||
*/
|
||||
millisecLabel: {
|
||||
type: String,
|
||||
value: "",
|
||||
},
|
||||
/**
|
||||
* show the sec field
|
||||
*/
|
||||
@ -291,6 +331,13 @@ export class PaperTimeInput extends PolymerElement {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
/**
|
||||
* show the milli sec field
|
||||
*/
|
||||
enableMillisecond: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
/**
|
||||
* limit hours input
|
||||
*/
|
||||
@ -313,7 +360,7 @@ export class PaperTimeInput extends PolymerElement {
|
||||
type: String,
|
||||
notify: true,
|
||||
readOnly: true,
|
||||
computed: "_computeTime(min, hour, sec, amPm)",
|
||||
computed: "_computeTime(min, hour, sec, millisec, amPm)",
|
||||
},
|
||||
};
|
||||
}
|
||||
@ -332,6 +379,10 @@ export class PaperTimeInput extends PolymerElement {
|
||||
if (this.enableSecond && !this.$.sec.validate()) {
|
||||
valid = false;
|
||||
}
|
||||
// Validate milli second field
|
||||
if (this.enableMillisecond && !this.$.millisec.validate()) {
|
||||
valid = false;
|
||||
}
|
||||
// Validate AM PM if 12 hour time
|
||||
if (this.format === 12 && !this.$.dropdown.validate()) {
|
||||
valid = false;
|
||||
@ -342,17 +393,27 @@ export class PaperTimeInput extends PolymerElement {
|
||||
/**
|
||||
* Create time string
|
||||
*/
|
||||
_computeTime(min, hour, sec, amPm) {
|
||||
_computeTime(min, hour, sec, millisec, amPm) {
|
||||
let str;
|
||||
if (hour || min || (sec && this.enableSecond)) {
|
||||
if (
|
||||
hour ||
|
||||
min ||
|
||||
(sec && this.enableSecond) ||
|
||||
(millisec && this.enableMillisecond)
|
||||
) {
|
||||
hour = hour || "00";
|
||||
min = min || "00";
|
||||
sec = sec || "00";
|
||||
millisec = millisec || "000";
|
||||
str = hour + ":" + min;
|
||||
// add sec field
|
||||
if (this.enableSecond && sec) {
|
||||
str = str + ":" + sec;
|
||||
}
|
||||
// add milli sec field
|
||||
if (this.enableMillisecond && millisec) {
|
||||
str = str + ":" + millisec;
|
||||
}
|
||||
// No ampm on 24 hr time
|
||||
if (this.format === 12) {
|
||||
str = str + " " + amPm;
|
||||
@ -366,6 +427,15 @@ export class PaperTimeInput extends PolymerElement {
|
||||
ev.target.inputElement.inputElement.select();
|
||||
}
|
||||
|
||||
/**
|
||||
* Format milli sec
|
||||
*/
|
||||
_formatMillisec() {
|
||||
if (this.millisec.toString().length === 1) {
|
||||
this.millisec = this.millisec.toString().padStart(3, "0");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Format sec
|
||||
*/
|
||||
|
@ -45,8 +45,15 @@ export interface DeviceAction {
|
||||
entity_id: string;
|
||||
}
|
||||
|
||||
export interface DelayActionParts {
|
||||
milliseconds?: number;
|
||||
seconds?: number;
|
||||
minutes?: number;
|
||||
hours?: number;
|
||||
days?: number;
|
||||
}
|
||||
export interface DelayAction {
|
||||
delay: number;
|
||||
delay: number | Partial<DelayActionParts>;
|
||||
}
|
||||
|
||||
export interface SceneAction {
|
||||
|
@ -1,10 +1,12 @@
|
||||
import "@polymer/paper-input/paper-input";
|
||||
import { customElement, html, LitElement, property } from "lit-element";
|
||||
import { fireEvent } from "../../../../../common/dom/fire_event";
|
||||
import "../../../../../components/entity/ha-entity-picker";
|
||||
import { HaFormTimeData } from "../../../../../components/ha-form/ha-form";
|
||||
import "../../../../../components/ha-service-picker";
|
||||
import { DelayAction } from "../../../../../data/script";
|
||||
import { HomeAssistant } from "../../../../../types";
|
||||
import { ActionElement, handleChangeEvent } from "../ha-automation-action-row";
|
||||
import { ActionElement } from "../ha-automation-action-row";
|
||||
|
||||
@customElement("ha-automation-action-delay")
|
||||
export class HaDelayAction extends LitElement implements ActionElement {
|
||||
@ -17,22 +19,46 @@ export class HaDelayAction extends LitElement implements ActionElement {
|
||||
}
|
||||
|
||||
protected render() {
|
||||
const { delay } = this.action;
|
||||
let data: HaFormTimeData = {};
|
||||
|
||||
if (typeof this.action.delay !== "object") {
|
||||
const parts = this.action.delay?.toString().split(":") || [];
|
||||
data = {
|
||||
hours: Number(parts[0]),
|
||||
minutes: Number(parts[1]),
|
||||
seconds: Number(parts[2]),
|
||||
milliseconds: Number(parts[3]),
|
||||
};
|
||||
} else {
|
||||
const { days, minutes, seconds, milliseconds } = this.action.delay;
|
||||
let { hours } = this.action.delay || 0;
|
||||
hours = (hours || 0) + (days || 0) * 24;
|
||||
data = {
|
||||
hours: hours,
|
||||
minutes: minutes,
|
||||
seconds: seconds,
|
||||
milliseconds: milliseconds,
|
||||
};
|
||||
}
|
||||
|
||||
return html`
|
||||
<paper-input
|
||||
.label=${this.hass.localize(
|
||||
"ui.panel.config.automation.editor.actions.type.delay.delay"
|
||||
)}
|
||||
name="delay"
|
||||
.value=${delay}
|
||||
<ha-time-input
|
||||
.data=${data}
|
||||
enableMillisecond
|
||||
@value-changed=${this._valueChanged}
|
||||
></paper-input>
|
||||
></ha-time-input>
|
||||
`;
|
||||
}
|
||||
|
||||
private _valueChanged(ev: CustomEvent): void {
|
||||
handleChangeEvent(this, ev);
|
||||
private _valueChanged(ev: CustomEvent) {
|
||||
ev.stopPropagation();
|
||||
const value = ev.detail.value;
|
||||
if (!value) {
|
||||
return;
|
||||
}
|
||||
fireEvent(this, "value-changed", {
|
||||
value: { ...this.action, delay: value },
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user