Skip to content

Commit

Permalink
Merge pull request #1252 from JulianStremel/main
Browse files Browse the repository at this point in the history
Added opt in pointerdown and pointerup event capture on button widget and fixed button theming bug
  • Loading branch information
joepavitt authored Oct 1, 2024
2 parents fa3eaa0 + e6ddd9c commit f9db468
Show file tree
Hide file tree
Showing 7 changed files with 147 additions and 4 deletions.
6 changes: 6 additions & 0 deletions docs/nodes/widgets/ui-button.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,12 @@ props:
Icon Color:
description: Icon color. If not provided, will have the same color as text / label.
dynamic: true
Enable pointerup event:
description: Enables the capturing of pointerup events on the button
dynamic: false
Enable pointerdown event:
description: Enables the capturing of pointerdown events on the button
dynamic: false
Emulate Button Click: If enabled, any received message will trigger a button click, emitting the relevant payload and topic.
controls:
enabled:
Expand Down
4 changes: 4 additions & 0 deletions nodes/widgets/locales/en-US/ui_button.html
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@ <h3>Properties</h3>
<dd>If "Icon" is defined, this property controls which side of the "Label" the icon will render on</dd>
<dt>Label <span class="property-type">string</span></dt>
<dd>The text shown within the button. If not provided, then the button will only render the icon. It supports HTML content</dd>
<dt>Enable pointerdown event <span class="property-type">bool</span></dt>
<dd>If enabled, the button will emit a message on pointerdown event with the given payload</dd>
<dt>Enable pointerup event <span class="property-type">bool</span></dt>
<dd>If enabled, the button will emit a message on pointerup event with the given payload</dd>
<dt>Emulate Button Click <span class="property-type">bool</span></dt>
<dd>If enabled, any received message will trigger a button click, emitting the relevant payload and topic</dd>
<dt>Background Color<span class="property-type">string</span></dt>
Expand Down
2 changes: 2 additions & 0 deletions nodes/widgets/locales/en-US/ui_button.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@
"payload": "Payload",
"topic": "Topic",
"emulateClick": "If msg arrives on input, emulate a button click:",
"enablePointerup": "Enable pointerup event",
"enablePointerdown": "Enable pointerdown event",
"buttonColor": "Background",
"optionalButtonColor": "(Optional) e.g. 'green'/'#a5a5a5'",
"textColor": "Text",
Expand Down
56 changes: 56 additions & 0 deletions nodes/widgets/ui_button.html
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,16 @@
topicType: { value: 'msg' },
buttonColor: { value: '' },
textColor: { value: '' },
iconColor: { value: '' },

// pointerup/down event support
enablePointerdown: { value: false },
pointerdownPayload: { value: '', validate: (hasProperty(RED.validators, 'typedInput') ? RED.validators.typedInput('pointerdownPayloadType') : function (v) { return true }) },
pointerdownPayloadType: { value: 'str' },
enablePointerup: { value: false },
pointerupPayload: { value: '', validate: (hasProperty(RED.validators, 'typedInput') ? RED.validators.typedInput('pointerupPayloadType') : function (v) { return true }) },
pointerupPayloadType: { value: 'str' },

iconColor: { value: '' }
},
inputs: 1,
Expand Down Expand Up @@ -83,6 +93,34 @@
types: ['str', 'msg', 'flow', 'global']
})

$('#node-input-enablePointerdown').on('change', function () {
if (this.checked) {
$('.form-row-pointerdown').show()
} else {
$('.form-row-pointerdown').hide()
}
})

$('#node-input-pointerdownPayload').typedInput({
default: 'str',
typeField: $('#node-input-pointerdownPayloadType'),
types: ['str', 'num', 'bool', 'json', 'bin', 'date', 'flow', 'global']
});

$('#node-input-enablePointerup').on('change', function () {
if (this.checked) {
$('.form-row-pointerup').show()
} else {
$('.form-row-pointerup').hide()
}
})

$('#node-input-pointerupPayload').typedInput({
default: 'str',
typeField: $('#node-input-pointerdownPayloadType'),
types: ['str', 'num', 'bool', 'json', 'bin', 'date', 'flow', 'global']
});

if (!this.iconPosition) {
$('#node-input-iconPosition').val('left')
}
Expand Down Expand Up @@ -151,6 +189,24 @@
<label for="node-input-tooltip"><i class="fa fa-info-circle"></i> <span data-i18n="ui-button.label.tooltip"></label>
<input type="text" id="node-input-tooltip" data-i18n="[placeholder]ui-button.label.optionalTooltip">
</div>-->
<div class="form-row">
<label style="width:auto" for="node-input-enablePointerdown"><i class="fa fa-hand-pointer-o"></i> <span data-i18n="ui-button.label.enablePointerdown"></span></label>
<input type="checkbox" id="node-input-enablePointerdown" style="display:inline-block; width:auto; vertical-align:top;">
</div>
<div class="form-row form-row-pointerdown">
<label for="node-input-pointerdownPayload" style="padding-left: 25px; margin-right: -25px"> <span data-i18n="ui-button.label.payload"></label>
<input type="text" id="node-input-pointerdownPayload" style="width:70%">
<input type="hidden" id="node-input-pointerdownPayloadType">
</div>
<div class="form-row">
<label style="width:auto" for="node-input-enablePointerup"><i class="fa fa-hand-pointer-o"></i> <span data-i18n="ui-button.label.enablePointerup"></span></label>
<input type="checkbox" id="node-input-enablePointerup" style="display:inline-block; width:auto; vertical-align:top;">
</div>
<div class="form-row form-row-pointerup">
<label for="node-input-pointerupPayload" style="padding-left: 25px; margin-right: -25px"><span data-i18n="ui-button.label.payload"></label>
<input type="text" id="node-input-pointerupPayload" style="width:70%">
<input type="hidden" id="node-input-pointerupPayloadType">
</div>
<div class="form-row">
<label style="width:auto" for="node-input-payload"><i class="fa fa-envelope-o"></i> <span data-i18n="ui-button.label.whenClicked"></label>
</div>
Expand Down
30 changes: 26 additions & 4 deletions nodes/widgets/ui_button.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,33 @@ module.exports = function (RED) {

const beforeSend = async function (msg) {
let error = null
let payload = null
let payloadType = null

// retrieve the payload we're sending from this button
let payloadType = config.payloadType
let payload = config.payload
msg._event = msg._event || { type: 'inject' }

switch (msg._event.type) {
case 'pointerup':
payload = config.pointerupPayload
payloadType = config.pointerupPayloadType
break
case 'pointerdown':
payload = config.pointerdownPayload
payloadType = config.pointerdownPayloadType
break
case 'click':
payload = config.payload
payloadType = config.payloadType
break
case 'inject':
payload = config.payload
payloadType = config.payloadType
break
default:
payload = config.payload
payloadType = config.payloadType
break
}

if (payloadType === 'flow' || payloadType === 'global') {
try {
Expand Down Expand Up @@ -43,7 +66,6 @@ module.exports = function (RED) {
}
}
}

msg.payload = payload

const updates = msg.ui_update
Expand Down
1 change: 1 addition & 0 deletions ui/src/stylesheets/common.css
Original file line number Diff line number Diff line change
Expand Up @@ -481,5 +481,6 @@ NB! supresses the gridarea for messages, but those are not in use*/
.v-btn.v-btn--density-default,
.v-btn.v-btn--density-compact,
.v-btn.v-btn--density-comfortable {
height: auto;
min-height: var(--widget-row-height);
}
52 changes: 52 additions & 0 deletions ui/src/widgets/ui-button/UIButton.vue
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
block variant="flat" :disabled="!state.enabled" :prepend-icon="prependIcon" :append-icon="appendIcon"
:class="{ 'nrdb-ui-button--icon': iconOnly }" :color="buttonColor" :style="{ 'min-width': iconOnly ?? 'auto' }"
@click="action"
@pointerdown="pointerdown"
@pointerup="pointerup"
@pointermove="checkIsPointerOverButton"
>
<template v-if="prependIcon" #prepend>
<v-icon :color="iconColor" />
Expand All @@ -26,6 +29,11 @@ export default {
props: { type: Object, default: () => ({}) },
state: { type: Object, default: () => ({}) }
},
data () {
return {
isPointerOverButton: true // Tracks if the pointer is still over the button
}
},
computed: {
...mapState('data', ['messages']),
prependIcon () {
Expand Down Expand Up @@ -62,6 +70,23 @@ export default {
},
methods: {
action ($evt) {
if (!this.isPointerOverButton) {
return
}
const evt = {
type: $evt.type,
clientX: $evt.clientX,
clientY: $evt.clientY,
bbox: $evt.target.getBoundingClientRect()
}
const msg = this.messages[this.id] || {}
msg._event = evt
this.$socket.emit('widget-action', this.id, msg)
},
pointerdown: function ($evt) {
if (!this.props.enablePointerdown) {
return
}
const evt = {
type: $evt.type,
clientX: $evt.clientX,
Expand All @@ -70,8 +95,35 @@ export default {
}
const msg = this.messages[this.id] || {}
msg._event = evt
$evt.target.setPointerCapture($evt.pointerId)
this.$socket.emit('widget-action', this.id, msg)
},
pointerup: function ($evt) {
if (!this.props.enablePointerup) {
return
}
const evt = {
type: $evt.type,
clientX: $evt.clientX,
clientY: $evt.clientY,
bbox: $evt.target.getBoundingClientRect()
}
const msg = this.messages[this.id] || {}
msg._event = evt
$evt.target.releasePointerCapture($evt.pointerId)
this.$socket.emit('widget-action', this.id, msg)
},
checkIsPointerOverButton: function ($evt) {
// Check if pointer is still over the button
const buttonRect = $evt.target.getBoundingClientRect()
this.isPointerOverButton = (
$evt.clientX >= buttonRect.left &&
$evt.clientX <= buttonRect.right &&
$evt.clientY >= buttonRect.top &&
$evt.clientY <= buttonRect.bottom
)
},
makeMdiIcon (icon) {
return 'mdi-' + icon.replace(/^mdi-/, '')
},
Expand Down

0 comments on commit f9db468

Please sign in to comment.