From 3973374f3f5216e42bbda2e1124716d61f229fe7 Mon Sep 17 00:00:00 2001 From: Bram Kragten Date: Mon, 21 Oct 2019 21:36:26 +0200 Subject: [PATCH] Add positive_time_period_dict to ha-form (#4090) * Add positive_time_period_dict to ha-form * select input on focus * Update ha-form-positive_time_period_dict.ts --- src/components/ha-form/ha-form-float.ts | 8 +- src/components/ha-form/ha-form-integer.ts | 8 +- .../ha-form-positive_time_period_dict.ts | 119 ++++++++++++++ src/components/ha-form/ha-form.ts | 16 +- src/components/paper-time-input.js | 151 ++++++++++++++++-- 5 files changed, 279 insertions(+), 23 deletions(-) create mode 100644 src/components/ha-form/ha-form-positive_time_period_dict.ts diff --git a/src/components/ha-form/ha-form-float.ts b/src/components/ha-form/ha-form-float.ts index 0d2279ea72..d2d41990aa 100644 --- a/src/components/ha-form/ha-form-float.ts +++ b/src/components/ha-form/ha-form-float.ts @@ -32,7 +32,7 @@ export class HaFormFloat extends LitElement implements HaFormElement { return html` + `; + } + + 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 = minutes + Math.floor(value / 60); + value %= 60; + } + + if (unit === "minutes" && value > 59) { + hours = hours + Math.floor(value / 60); + value %= 60; + } + + fireEvent( + this, + "value-changed", + { + value: { + hours, + minutes, + seconds: this._seconds, + ...{ [unit]: value }, + }, + }, + { bubbles: false } + ); + } +} + +declare global { + interface HTMLElementTagNameMap { + "ha-form-positive_time_period_dict": HaFormTimePeriod; + } +} diff --git a/src/components/ha-form/ha-form.ts b/src/components/ha-form/ha-form.ts index a8fe7d813d..48973c63b9 100644 --- a/src/components/ha-form/ha-form.ts +++ b/src/components/ha-form/ha-form.ts @@ -14,6 +14,7 @@ import "./ha-form-integer"; import "./ha-form-float"; import "./ha-form-boolean"; import "./ha-form-select"; +import "./ha-form-positive_time_period_dict"; import { fireEvent } from "../../common/dom/fire_event"; export type HaFormSchema = @@ -21,7 +22,8 @@ export type HaFormSchema = | HaFormIntegerSchema | HaFormFloatSchema | HaFormBooleanSchema - | HaFormSelectSchema; + | HaFormSelectSchema + | HaFormTimeSchema; export interface HaFormBaseSchema { name: string; @@ -55,6 +57,10 @@ export interface HaFormBooleanSchema extends HaFormBaseSchema { type: "boolean"; } +export interface HaFormTimeSchema extends HaFormBaseSchema { + type: "time"; +} + export interface HaFormDataContainer { [key: string]: HaFormData; } @@ -64,13 +70,19 @@ export type HaFormData = | HaFormIntegerData | HaFormFloatData | HaFormBooleanData - | HaFormSelectData; + | HaFormSelectData + | HaFormTimeData; export type HaFormStringData = string; export type HaFormIntegerData = number; export type HaFormFloatData = number; export type HaFormBooleanData = boolean; export type HaFormSelectData = string; +export interface HaFormTimeData { + hours?: number; + minutes?: number; + seconds?: number; +} export interface HaFormElement extends LitElement { schema: HaFormSchema; diff --git a/src/components/paper-time-input.js b/src/components/paper-time-input.js index 2a2d5bb52b..620da4d7b1 100644 --- a/src/components/paper-time-input.js +++ b/src/components/paper-time-input.js @@ -87,6 +87,10 @@ export class PaperTimeInput extends PolymerElement { label { @apply --paper-font-caption; + color: var( + --paper-input-container-color, + var(--secondary-text-color) + ); } .time-input-wrap { @@ -106,14 +110,17 @@ export class PaperTimeInput extends PolymerElement { id="hour" type="number" value="{{hour}}" + label="[[hourLabel]]" on-change="_shouldFormatHour" - required="" + on-focus="_onFocus" + required + prevent-invalid-input auto-validate="[[autoValidate]]" - prevent-invalid-input="" maxlength="2" max="[[_computeHourMax(format)]]" min="0" - no-label-float="" + no-label-float$="[[!floatInputLabels]]" + always-float-label$="[[alwaysFloatInputLabels]]" disabled="[[disabled]]" > : @@ -124,15 +131,40 @@ export class PaperTimeInput extends PolymerElement { id="min" type="number" value="{{min}}" + label="[[minLabel]]" on-change="_formatMin" - required="" + on-focus="_onFocus" + required auto-validate="[[autoValidate]]" - prevent-invalid-input="" + prevent-invalid-input maxlength="2" max="59" min="0" - no-label-float="" + no-label-float$="[[!floatInputLabels]]" + always-float-label$="[[alwaysFloatInputLabels]]" disabled="[[disabled]]" + > + : + + + + @@ -180,6 +212,20 @@ export class PaperTimeInput extends PolymerElement { type: Boolean, value: false, }, + /** + * float the input labels + */ + floatInputLabels: { + type: Boolean, + value: false, + }, + /** + * always float the input labels + */ + alwaysFloatInputLabels: { + type: Boolean, + value: false, + }, /** * 12 or 24 hr format */ @@ -208,6 +254,48 @@ export class PaperTimeInput extends PolymerElement { type: String, notify: true, }, + /** + * second + */ + sec: { + type: String, + notify: true, + }, + /** + * Suffix for the hour input + */ + hourLabel: { + type: String, + value: "", + }, + /** + * Suffix for the min input + */ + minLabel: { + type: String, + value: ":", + }, + /** + * Suffix for the sec input + */ + secLabel: { + type: String, + value: "", + }, + /** + * show the sec field + */ + enableSecond: { + type: Boolean, + value: false, + }, + /** + * limit hours input + */ + noHoursLimit: { + type: Boolean, + value: false, + }, /** * AM or PM */ @@ -223,7 +311,7 @@ export class PaperTimeInput extends PolymerElement { type: String, notify: true, readOnly: true, - computed: "_computeTime(min, hour, amPm)", + computed: "_computeTime(min, hour, sec, amPm)", }, }; } @@ -238,6 +326,10 @@ export class PaperTimeInput extends PolymerElement { if (!this.$.hour.validate() | !this.$.min.validate()) { valid = false; } + // Validate second field + if (this.enableSecond && !this.$.sec.validate()) { + valid = false; + } // Validate AM PM if 12 hour time if (this.format === 12 && !this.$.dropdown.validate()) { valid = false; @@ -248,15 +340,37 @@ export class PaperTimeInput extends PolymerElement { /** * Create time string */ - _computeTime(min, hour, amPm) { - if (hour && min) { - // No ampm on 24 hr time - if (this.format === 24) { - amPm = ""; + _computeTime(min, hour, sec, amPm) { + let str; + if (hour || min || (sec && this.enableSecond)) { + hour = hour || "00"; + min = min || "00"; + sec = sec || "00"; + str = hour + ":" + min; + // add sec field + if (this.enableSecond && sec) { + str = str + ":" + sec; + } + // No ampm on 24 hr time + if (this.format === 12) { + str = str + " " + amPm; } - return hour + ":" + min + " " + amPm; } - return undefined; + + return str; + } + + _onFocus(ev) { + ev.target.inputElement.inputElement.select(); + } + + /** + * Format sec + */ + _formatSec() { + if (this.sec.toString().length === 1) { + this.sec = this.sec.toString().padStart(2, "0"); + } } /** @@ -264,16 +378,16 @@ export class PaperTimeInput extends PolymerElement { */ _formatMin() { if (this.min.toString().length === 1) { - this.min = this.min < 10 ? "0" + this.min : this.min; + this.min = this.min.toString().padStart(2, "0"); } } /** - * Hour needs a leading zero in 24hr format + * Format hour */ _shouldFormatHour() { if (this.format === 24 && this.hour.toString().length === 1) { - this.hour = this.hour < 10 ? "0" + this.hour : this.hour; + this.hour = this.hour.toString().padStart(2, "0"); } } @@ -281,6 +395,9 @@ export class PaperTimeInput extends PolymerElement { * 24 hour format has a max hr of 23 */ _computeHourMax(format) { + if (this.noHoursLimit) { + return null; + } if (format === 12) { return format; }