From 197008d0d4331c05db8d704075b3a4bfa05ee0ea Mon Sep 17 00:00:00 2001 From: Mark Herwege Date: Wed, 8 Mar 2023 18:12:50 +0100 Subject: [PATCH] number, date and time input using hints Signed-off-by: Mark Herwege --- .../basic/internal/render/InputRenderer.java | 55 +++++++++++++++++-- .../src/main/resources/snippets/input.html | 36 +++++++----- .../org.openhab.ui.basic/web-src/_layout.scss | 29 ++++++++-- .../org.openhab.ui.basic/web-src/smarthome.js | 40 +++++++++++--- 4 files changed, 126 insertions(+), 34 deletions(-) diff --git a/bundles/org.openhab.ui.basic/src/main/java/org/openhab/ui/basic/internal/render/InputRenderer.java b/bundles/org.openhab.ui.basic/src/main/java/org/openhab/ui/basic/internal/render/InputRenderer.java index e01d3ba429..69d04bae31 100644 --- a/bundles/org.openhab.ui.basic/src/main/java/org/openhab/ui/basic/internal/render/InputRenderer.java +++ b/bundles/org.openhab.ui.basic/src/main/java/org/openhab/ui/basic/internal/render/InputRenderer.java @@ -19,6 +19,7 @@ import org.openhab.core.i18n.TranslationProvider; import org.openhab.core.items.Item; import org.openhab.core.items.ItemNotFoundException; +import org.openhab.core.library.types.DateTimeType; import org.openhab.core.model.sitemap.sitemap.Input; import org.openhab.core.model.sitemap.sitemap.Widget; import org.openhab.core.types.State; @@ -58,17 +59,51 @@ public boolean canRender(Widget w) { @Override public EList renderWidget(Widget w, StringBuilder sb, String sitemap) throws RenderException { + Input input = (Input) w; + String snippet = getSnippet("input"); snippet = preprocessSnippet(snippet, w); - String dataState = getValue(w); + String inputHint = input.getInputHint(); + inputHint = inputHint == null ? "text" : inputHint.toLowerCase(); + snippet = snippet.replace("%input_hint%", inputHint); + + String inputType = inputHint; + String inputPattern = ""; + if ("number".equals(inputType)) { + inputType = "text"; + inputPattern = "pattern=\"[0-9]*([\\.|,][0-9]*)?\""; + } else if ("date".equals(inputType)) { + inputPattern = "pattern=\"[0-9]{4}-[0-9]d{2}-[0-9]d{2}\""; + } else if ("time".equals(inputType)) { + inputPattern = "pattern=\"[0-9]{2}:[0-9]{2}\""; + } else if ("datetime".equals(inputType)) { + inputType = "datetime-local"; + inputPattern = "pattern=\"[0-9]{4}-[0-9]d{2}-[0-9]d{2}T[0-9]{2}:[0-9]{2}\""; + } + snippet = snippet.replace("%input_type%", inputType); + snippet = snippet.replace("%input_pattern%", inputPattern); + + String displayState = getValue(w); State state = itemUIRegistry.getState(w); if (state == null || state instanceof UnDefType) { - snippet = snippet.replace("%undef_state%", dataState); + snippet = snippet.replace("%undef_state%", displayState); snippet = snippet.replace("%data_state%", ""); } else { snippet = snippet.replace("%undef_state%", ""); + String dataState = displayState; + if ("number".equals(inputHint)) { + dataState = displayState.trim().split(" ")[0]; + } else if (state instanceof DateTimeType) { + if ("date".equals(inputHint)) { + dataState = ((DateTimeType) state).format("%1$tY-%1$tm-%1$td"); + } else if ("time".equals(inputHint)) { + dataState = ((DateTimeType) state).format("%1$tT"); + } else if ("datetime".equals(inputHint)) { + dataState = ((DateTimeType) state).format("%1$tY-%1$tm-%1$tdT%1$tT"); + } + } snippet = snippet.replace("%data_state%", dataState); } @@ -80,12 +115,24 @@ public EList renderWidget(Widget w, StringBuilder sb, String sitemap) th } String dataType; if (item != null && item.getAcceptedDataTypes().stream().anyMatch(o -> Number.class.isAssignableFrom(o))) { - dataType = "Number"; + dataType = "number"; + } else if (item != null + && item.getAcceptedDataTypes().stream().anyMatch(o -> DateTimeType.class.isAssignableFrom(o))) { + dataType = "datetime"; } else { - dataType = "Text"; + dataType = "text"; } snippet = snippet.replace("%data_type%", dataType); + String unitSnippet = ""; + if ("number".equals(inputHint)) { + String[] dataStateArray = displayState.trim().split(" "); + if (dataStateArray.length > 1) { + unitSnippet = "" + dataStateArray[1] + ""; + } + } + snippet = snippet.replace("%unit_snippet%", unitSnippet); + // Process the color tags snippet = processColor(w, snippet); diff --git a/bundles/org.openhab.ui.basic/src/main/resources/snippets/input.html b/bundles/org.openhab.ui.basic/src/main/resources/snippets/input.html index fc751439b4..84970d7ea3 100644 --- a/bundles/org.openhab.ui.basic/src/main/resources/snippets/input.html +++ b/bundles/org.openhab.ui.basic/src/main/resources/snippets/input.html @@ -6,21 +6,27 @@ %label%
- - +
+ + +
+ %unit_snippet%
diff --git a/bundles/org.openhab.ui.basic/web-src/_layout.scss b/bundles/org.openhab.ui.basic/web-src/_layout.scss index ca74c8f3ff..789d89a54a 100644 --- a/bundles/org.openhab.ui.basic/web-src/_layout.scss +++ b/bundles/org.openhab.ui.basic/web-src/_layout.scss @@ -228,12 +228,8 @@ font-weight: 700; } &__label { - @media screen and (max-width: $layout-tablet-size-threshold) { - margin: 0 -12px; - padding: 0 12px 0 0; - } - margin: 0 -16px; - padding: 0 16px 0 0; + margin: 0; + padding: 0; } } } @@ -265,6 +261,27 @@ } &__input { width: 60%; + display: flex; + align-items: center; + box-sizing: border-box; + @media screen and (max-width: $layout-tablet-size-threshold) { + padding: 0 12px 0 0; + } + padding: 0 16px 0 0; + &-container { + flex-grow: 1; + width: auto; + padding-right: 0; + } + &-unit { + display: inline-block; + box-sizing: border-box; + font-family: "Helvetica","Arial",sans-serif; + font-size: 14px; + font-weight: 700; + text-align: right; + padding-left: 8px; + } } &__title { margin: 0; diff --git a/bundles/org.openhab.ui.basic/web-src/smarthome.js b/bundles/org.openhab.ui.basic/web-src/smarthome.js index 5bd36ed5bd..c901a1ae3c 100644 --- a/bundles/org.openhab.ui.basic/web-src/smarthome.js +++ b/bundles/org.openhab.ui.basic/web-src/smarthome.js @@ -1530,8 +1530,9 @@ var _t = this; - _t.input = _t.parentNode.querySelector("input[type=text]"); + _t.input = _t.parentNode.querySelector("input"); _t.itemType = _t.parentNode.getAttribute(o.itemTypeAttribute); + _t.inputHint = _t.parentNode.getAttribute(o.inputHintAttribute); _t.verify = undefined; var @@ -1539,25 +1540,31 @@ numberPattern = /^(\+|-)?[0-9\.,]+/, dotSeparatorPattern = /^-?(([0-9]{1,3}(,[0-9]{3})*)|([0-9]*))?(\.[0-9]+)?$/, commaSeparatorPattern = /^-?(([0-9]{1,3}(\.[0-9]{3})*)|([0-9]*))?(,[0-9]+)?$/; + function onChange() { var changeValue = _t.input.value, changed = true; - if (_t.itemType === "Number") { + + if (_t.itemType === "number") { changeValue = changeValue.trim(); - var numberValue = changeValue.match(numberPattern)[0]; - if (numberValue === undefined) { - changed = false; - } else { - var unitValue = changeValue.substring(numberValue.length).trim(); - changeValue = numberValue.replace(/^\+/, ""); + var numberValueMatch = changeValue.match(numberPattern); + if (numberValueMatch && (numberValueMatch.length > 0)) { + var numberValue = numberValueMatch[0]; + var unitValue = changeValue.substring(numberValue.length).trim(); + changeValue = numberValue.replace(/^\+/, ""); if (commaSeparatorPattern.test(changeValue) && !dotSeparatorPattern.test(changeValue)) { changeValue = changeValue.replace(/\./g, "").replace(",", "."); } if (unitValue.length > 1) { changeValue = changeValue + " " + unitValue; } + } else { + changed = false; } + } else if (_t.itemtype === "datetime") { + changeValue = changeValue.trim(); + changeValue = new Date(changeValue).getTime(); } if (!changed) { @@ -1580,7 +1587,21 @@ if (_t.verify) { _t.verify.cancel(); } - _t.input.value = value; + if (_t.inputHint === "number") { + var numberValueMatch = value.trim().match(numberPattern); + if (numberValueMatch && (numberValueMatch.length > 0)) { + _t.input.value = numberValueMatch[0]; + } + } else if (_t.inputHint === "date") { + _t.input.value = value.trim().split("T")[0]; + } else if (_t.inputHint === "time") { + _t.input.value = value.trim().split("T")[1].split(".")[0] + } else if (_t.inputHint === "datetime") { + _t.input.value = value.trim().split(".")[0] + } else { + _t.input.value = value; + } + _t.input.parentNode.MaterialTextfield.checkValidity(); lastValue = value; }; @@ -2514,6 +2535,7 @@ })({ itemAttribute: "data-item", itemTypeAttribute: "data-item-type", + inputHintAttribute: "data-input-hint", idAttribute: "data-widget-id", iconAttribute: "data-icon", iconTypeAttribute: "data-icon-type",