Skip to content

Commit a9d126d

Browse files
committed
oh-input: Fix editing a number item with unit and accept Enter key
Display the number's unit after the input field for numeric type Make numeric input field right-aligned Improve input-elements alignment Accept Enter key to send the value, with or without a sendButton Honor useDisplayState config Signed-off-by: Jimmy Tanagra <[email protected]>
1 parent 0041fb6 commit a9d126d

File tree

2 files changed

+56
-25
lines changed

2 files changed

+56
-25
lines changed

bundles/org.openhab.ui/web/src/components/widgets/standard/list/oh-input-item.vue

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<template>
22
<oh-list-item :context="context" class="input-listitem">
3-
<div slot="footer" class="padding">
3+
<div slot="footer">
44
<generic-widget-component :context="childContext(afterComponent)" v-on="$listeners" />
55
</div>
66
</oh-list-item>

bundles/org.openhab.ui/web/src/components/widgets/system/oh-input.vue

+55-24
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,47 @@
11
<template>
2-
<f7-input v-if="!config.item || !config.sendButton" class="input-field" ref="input" v-bind="config" :style="config.style"
3-
:value="((config.type && config.type.indexOf('date') === 0) || config.type === 'time') ? valueForDatepicker : value"
4-
:calendar-params="calendarParams" :step="config.step ? config.step : 'any'"
5-
@input="$evt => updated($evt.target.value)" :change="updated" @calendar:change="updated" @texteditor:change="updated" @colorpicker:change="updated">
6-
<template v-if="context.component.slots && context.component.slots.default">
7-
<generic-widget-component :context="childContext(slotComponent)" v-for="(slotComponent, idx) in context.component.slots.default" :key="'default-' + idx" />
8-
</template>
9-
</f7-input>
10-
<f7-row no-gap v-else class="oh-input-with-send-button" :style="config.style">
11-
<f7-input class="input-field col-80" ref="input" v-bind="config"
2+
<f7-row no-gap v-if="!config.item || !config.sendButton" class="oh-input" :style="config.style">
3+
<f7-input class="input-field" ref="input" v-bind="config" :style="{width: '100%', ...config.style}"
124
:value="((config.type && config.type.indexOf('date') === 0) || config.type === 'time') ? valueForDatepicker : value"
135
:calendar-params="calendarParams" :step="config.step ? config.step : 'any'"
6+
@focus="listenForEnterKey"
7+
@blur="stopListeningForEnterKey"
148
@input="$evt => updated($evt.target.value)" :change="updated" @calendar:change="updated" @texteditor:change="updated" @colorpicker:change="updated">
159
<template v-if="context.component.slots && context.component.slots.default">
1610
<generic-widget-component :context="childContext(slotComponent)" v-for="(slotComponent, idx) in context.component.slots.default" :key="'default-' + idx" />
1711
</template>
1812
</f7-input>
13+
<span v-if="unit" class="unit">{{ unit }}</span>
14+
</f7-row>
15+
<f7-row no-gap v-else class="oh-input" :style="config.style">
16+
<f7-input class="input-field" ref="input" v-bind="config"
17+
:value="((config.type && config.type.indexOf('date') === 0) || config.type === 'time') ? valueForDatepicker : value"
18+
:calendar-params="calendarParams" :step="config.step ? config.step : 'any'"
19+
:style="{ width: '100%' }"
20+
@focus="listenForEnterKey"
21+
@blur="stopListeningForEnterKey"
22+
@input="$evt => updated($evt.target.value)" :change="updated" @calendar:change="updated" @texteditor:change="updated" @colorpicker:change="updated">
23+
<template v-if="context.component.slots && context.component.slots.default">
24+
<generic-widget-component :context="childContext(slotComponent)" v-for="(slotComponent, idx) in context.component.slots.default" :key="'default-' + idx" />
25+
</template>
26+
</f7-input>
27+
<span v-if="unit" class="unit">{{ unit }}</span>
1928
<f7-button class="send-button col-10" v-if="this.config.sendButton" @click.stop="sendButtonClicked" v-bind="config.sendButtonConfig || { iconMaterial: 'done', iconColor: 'gray' }" />
2029
</f7-row>
2130
</template>
2231

2332
<style lang="stylus">
24-
.oh-input-with-send-button
33+
input[type=number]
34+
text-align right
35+
.oh-input
36+
flex-wrap nowrap !important
37+
align-items center !important
38+
.unit
39+
margin-left 4px
2540
.input-field
2641
padding-left 8px
2742
padding-right 8px
28-
--f7-input-font-size 1rem
2943
.send-button
30-
--f7-button-padding-horizontal 0px
44+
--f7-button-padding-horizontal 0
3145
</style>
3246

3347
<script>
@@ -59,17 +73,23 @@ export default {
5973
}
6074
} else if (this.config.variable && variableLocation[this.config.variable] !== undefined) {
6175
return variableLocation[this.config.variable]
62-
} else if (this.config.sendButton && this.pendingUpdate !== null) {
76+
} else if (this.pendingUpdate !== null) {
6377
return this.pendingUpdate
64-
} else if (this.config.item && this.context.store[this.config.item].state !== 'NULL' && this.context.store[this.config.item].state !== 'UNDEF' && this.context.store[this.config.item].state !== 'Invalid Date') {
65-
if (this.config.useDisplayState) {
66-
return this.context.store[this.config.item].displayState || this.context.store[this.config.item].state
67-
} else {
68-
return this.context.store[this.config.item].state
78+
} else if (this.config.item) {
79+
const item = this.context.store[this.config.item]
80+
if (item.state !== 'NULL' && item.state !== 'UNDEF' && item.state !== 'Invalid Date') {
81+
let value = this.config.useDisplayState ? item.displayState || item.state : item.state
82+
if (this.config.type === 'number' && this.unit) {
83+
value = value.split(' ')[0]
84+
}
85+
return value
6986
}
7087
}
7188
return this.config.defaultValue
7289
},
90+
unit () {
91+
return this.config.type === 'number' && this.config.item && this.context.store[this.config.item].unit
92+
},
7393
calendarParams () {
7494
if (this.config.type !== 'datepicker') return null
7595
let params = { dateFormat: { year: 'numeric', month: 'numeric', day: 'numeric' } }
@@ -121,9 +141,7 @@ export default {
121141
} else if (this.config.type === 'datepicker' && Array.isArray(value) && this.valueForDatepicker[0].getTime() === value[0].getTime()) {
122142
return
123143
}
124-
if (this.config.sendButton) {
125-
this.$set(this, 'pendingUpdate', value)
126-
}
144+
this.$set(this, 'pendingUpdate', value)
127145
if (this.config.variable) {
128146
const variableScope = this.getVariableScope(this.context.ctxVars, this.context.varScope, this.config.variable)
129147
const variableLocation = (variableScope) ? this.context.ctxVars[variableScope] : this.context.vars
@@ -133,13 +151,26 @@ export default {
133151
this.$set(variableLocation, this.config.variable, value)
134152
}
135153
},
154+
listenForEnterKey (evt) {
155+
evt.target.addEventListener('keyup', this.keyUp)
156+
},
157+
stopListeningForEnterKey (evt) {
158+
evt.target.removeEventListener('keyup', this.keyUp)
159+
},
160+
keyUp (evt) {
161+
if (evt.key === 'Enter') {
162+
this.sendButtonClicked()
163+
}
164+
},
136165
sendButtonClicked () {
137166
if (this.config.item && this.pendingUpdate) {
138167
let cmd = this.pendingUpdate
139-
if (this.config.type === 'datepicker' && Array.isArray(cmd)) {
168+
if (this.unit) {
169+
cmd += ' ' + this.unit
170+
} else if (this.config.type === 'datepicker' && Array.isArray(cmd)) {
140171
cmd = dayjs(cmd[0]).format()
172+
if (cmd === 'Invalid Date') return
141173
}
142-
if (cmd === 'Invalid Date') return
143174
this.$store.dispatch('sendCommand', { itemName: this.config.item, cmd })
144175
this.$set(this, 'pendingUpdate', null)
145176
}

0 commit comments

Comments
 (0)