Skip to content

Commit

Permalink
Merge pull request #1382 from bartbutenaers/html-labels
Browse files Browse the repository at this point in the history
Support for html in labels
  • Loading branch information
joepavitt authored Oct 15, 2024
2 parents 2f20bb7 + 8b977fe commit 9dc380b
Show file tree
Hide file tree
Showing 24 changed files with 102 additions and 52 deletions.
2 changes: 1 addition & 1 deletion docs/nodes/widgets/ui-button-group.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ props:
Group: Defines which group of the UI Dashboard this widget will render in.
Size: Controls the width of the button with respect to the parent group. Maximum value is the width of the group.
Label:
description: The text shown within the button.
description: The text shown within the button. Html content is allowed.
dynamic: true
Appearance: Specify whether the shape of the widget should be rectangular or have rounded corners.
Use theme colors: Specify whether the theme colors should be used. If not active, custom colors can be specified for each option separately.
Expand Down
2 changes: 1 addition & 1 deletion docs/nodes/widgets/ui-dropdown.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ props:
Group: Defines which group of the UI Dashboard this widget will render in.
Size: Controls the width of the dropdown with respect to the parent group. Maximum value is the width of the group.
Label:
description: The text shown to the left of the dropdown.
description: The text shown to the left of the dropdown. Html content is allowed.
dynamic: true
Options:
description: A list of the options available in the dropdown. Each row defines a 'label' (shown in the dropdown) and `value` (emitted on selection) property.
Expand Down
2 changes: 1 addition & 1 deletion docs/nodes/widgets/ui-number-input.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ props:
description: If "Icon" is defined, this property controls if icon is render inside or outside the number input box.
dynamic: true
Label:
description: The number shown within the number input field.
description: The number shown within the number input field. Html content is allowed.
dynamic: true
Min:
description: Defines the minimum allowable value for the number input field.
Expand Down
2 changes: 1 addition & 1 deletion docs/nodes/widgets/ui-radio-group.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ description: Facilitate easy option selection with ui-radio-group in Node-RED Da
props:
Group: Defines which group of the UI Dashboard this widget will render in.
Label:
description: The text shown above the radio group to inform the user of what options are available.
description: The text shown above the radio group to inform the user of what options are available. Html content is allowed.
dynamic: true
Options:
description: A list of the options available in the radio group. Each row defines a `label` (shown alongisde each radio button) and `value` (emitted on selection) property.
Expand Down
2 changes: 1 addition & 1 deletion docs/nodes/widgets/ui-slider.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ props:
Group: Defines which group of the UI Dashboard this widget will render in.
Size: Controls the width of the slider with respect to the parent group. Maximum value is the width of the group.
Label:
description: The text shown to the left of the slider.
description: The text shown to the left of the slider. Html content is allowed.
dynamic: true
Thumb Label:
description: Defined when the thumb of the slider will show. Defaults to 'On Drag'.
Expand Down
2 changes: 1 addition & 1 deletion docs/nodes/widgets/ui-switch.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ props:
Group: Defines which group of the UI Dashboard this widget will render in.
Size: Controls the width of the button with respect to the parent group. Maximum value is the width of the group.
Label:
description: The text shown within the button.
description: The text shown within the button. Html content is allowed.
dynamic: true
Layout:
description: Defines how the label and the switch are arranged. Users can choose between different layout options such as aligning elements to the left, left reversed, spread evenly or spread evenly but in reversed order.
Expand Down
2 changes: 1 addition & 1 deletion docs/nodes/widgets/ui-text-input.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ props:
description: If "Icon" is defined, this property controls if icon is render inside or outside the text input box.
dynamic: true
Label:
description: The text shown within the text input field.
description: The text shown within the text input field. Html content is allowed.
dynamic: true
Tooltip: The text shown when hovering over the text input field.
Mode:
Expand Down
2 changes: 1 addition & 1 deletion docs/nodes/widgets/ui-text.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ description: Employ the ui-text widget in Node-RED Dashboard 2.0 to display stat
props:
Group: Defines which group of the UI Dashboard this widget will render in.
Size: Controls the width of the button with respect to the parent group. Maximum value is the width of the group.
Label: The text shown within the button.
Label: The text shown within the button. Html content is allowed.
Layout: Choose how to layout your label (if deifned) & value.
Style: Checkbox to define whether or not to include custom styling for the text. Enabling this will then show the below options.
Font: If "style" is enabled, this will define the font of the text.
Expand Down
4 changes: 2 additions & 2 deletions nodes/widgets/locales/en-US/ui_button_group.html
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<p>To clear any selection, pass an empty array <code>[]</code> as <code>msg.payload</code>.</p>
<h3>Properties</h3>
<p><strong>Label:</strong><br/>
The label that will be displayed on the left side of the button group.</p>
The label that will be displayed on the left side of the button group. Html content is allowed.</p>
<p><strong>Appearance:</strong><br/>
Specify whether the shape of the widget should be rectangular or have rounded corners.</p>
<p><strong>Use theme colors:</strong><br/>
Expand All @@ -29,7 +29,7 @@ <h3>Dynamic Properties (Inputs)</h3>
<p>Any of the following can be appended to a <code>msg.ui_update</code> in order to override or set properties on this node at runtime.</p>
<dl class="message-properties">
<dt class="optional">label <span class="property-type">string</span></dt>
<dd>The label displayed on the left side of the button group.</dd>
<dd>The label displayed on the left side of the button group. Html content is allowed.</dd>
<dt class="optional">options <span class="property-type">array</span></dt>
<dd>
Change the options available in the button group at runtime
Expand Down
4 changes: 2 additions & 2 deletions nodes/widgets/locales/en-US/ui_dropdown.html
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ <h3>Dynamic Properties (Inputs)</h3>
<p>Any of the following can be appended to a <code>msg.ui_update</code> in order to override or set properties on this node at runtime.</p>
<dl class="message-properties">
<dt class="optional">label <span class="property-type">string</span></dt>
<dd>The label displayed to explain the purpose of the dropdown.</dd>
<dd>The label displayed to explain the purpose of the dropdown. Html content is allowed.</dd>
<dt class="optional">options <span class="property-type">array</span></dt>
<dd>
Change the options available in the dropdown at runtime
Expand All @@ -42,4 +42,4 @@ <h3>Dynamic Properties (Inputs)</h3>
<dt class="optional">class <span class="property-type">string</span></dt>
<dd>Add a CSS class, or more, to the Button at runtime.</dd>
</dl>
</script>
</script>
4 changes: 2 additions & 2 deletions nodes/widgets/locales/en-US/ui_number_input.html
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ <h3>Dynamic Properties (Inputs)</h3>
</dl>
<dl class="message-properties">
<dt class="optional">label <span class="property-type">string</span></dt>
<dd>Override the label displayed on the number input.</dd>
<dd>Override the label displayed on the number input. Html content is allowed.</dd>
</dl>
<dl class="message-properties">
<dt class="optional">icon <span class="property-type">string</span></dt>
Expand All @@ -36,4 +36,4 @@ <h3>Dynamic Properties (Inputs)</h3>
<dt class="optional">spinner <span class="property-type">string</span></dt>
<dd>Set the spinner layout as <code>inline</code> or <code>stacked</code> to control how the spinners appear in the number input.</dd>
</dl>
</script>
</script>
4 changes: 2 additions & 2 deletions nodes/widgets/locales/en-US/ui_radio_group.html
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ <h3>Selecting Options via <code>msg.</code></h3>
<h3>Dynamic Properties (Inputs)</h3>
<p>Any of the following can be appended to a <code>msg.ui_update</code> in order to override or set properties on this node at runtime.</p>
<dl class="message-properties">
<dt class="optional">label <span class="property-type">array</span></dt>
<dd>Update the label rendered with the Radio Group</dd>
<dt class="optional">label <span class="property-type">string</span></dt>
<dd>Update the label rendered with the Radio Group. Html content is allowed.</dd>
<dt class="optional">options <span class="property-type">array</span></dt>
<dd>
Change the options available in the dropdown at runtime
Expand Down
6 changes: 3 additions & 3 deletions nodes/widgets/locales/en-US/ui_slider.html
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
<h3>Properties</h3>
<dl class="message-properties">
<dt>Label <span class="property-type">string</span></dt>
<dd>The text shown to the left of the slider.</dd>
<dd>The text shown to the left of the slider. Html content is allowed.</dd>
<dt>Thumb Label <span class="property-type">'never' | 'on drag' | 'always'</span></dt>
<dd>Defined when the thumb of the slider will show. Defaults to 'On Drag'.</dd>
<dt>Show Ticks <span class="property-type">'never' | 'on drag' | 'always'</span></dt>
Expand All @@ -35,7 +35,7 @@ <h3>Dynamic Properties (Inputs)</h3>
<p>Any of the following can be appended to a <code>msg.ui_update.</code> in order to override or set properties on this node at runtime.</p>
<dl class="message-properties">
<dt class="optional">label <span class="property-type">string</span></dt>
<dd>Update the sliders label at runtime.</dd>
<dd>Update the sliders label at runtime. Html content is allowed.</dd>
</dl>
<dl class="message-properties">
<dt class="optional">thumbLabel <span class="property-type">true | false | 'always'</span></dt>
Expand Down Expand Up @@ -81,4 +81,4 @@ <h3>Dynamic Properties (Inputs)</h3>
<dt class="optional">class <span class="property-type">string</span></dt>
<dd>Add a CSS class, or more, to the Button at runtime.</dd>
</dl>
</script>
</script>
4 changes: 2 additions & 2 deletions nodes/widgets/locales/en-US/ui_switch.html
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ <h3>Properties</h3>
<dt>Icon Position<span class="property-type">left | right</span></dt>
<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>
<dd>The text shown within the button. If not provided, then the button will only render the icon. Html content is allowed.</dd>
<dt>Layout <span class="property-type">row-left | row-left-swapped | row-spread | row-spread-swapped</span></dt>
<dd>Specifies how the label and switch input are arranged. The options include:
<ul>
Expand Down Expand Up @@ -64,7 +64,7 @@ <h3>Dynamic Properties (Inputs)</h3>
</dl>
<dl class="message-properties">
<dt class="optional">label <span class="property-type">string</span></dt>
<dd>Change the switch label at runtime.</dd>
<dd>Change the switch label at runtime. Html content is allowed.</dd>
</dl>
<dl class="message-properties">
<dt class="optional">layout <span class="property-type">string</span></dt>
Expand Down
2 changes: 1 addition & 1 deletion nodes/widgets/locales/en-US/ui_text.html
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ <h3>Dynamic Properties (Inputs)</h3>
<p>Any of the following can be appended to a <code>msg.ui_update</code> in order to override or set properties on this node at runtime.</p>
<dl class="message-properties">
<dt class="optional">label <span class="property-type">string</span></dt>
<dd>Override the label displayed alongside the text's value</dd>
<dd>Override the label displayed alongside the text's value. Html content is allowed.</dd>
</dl>
<dl class="message-properties">
<dt class="optional">layout <span class="property-type">string</span></dt>
Expand Down
4 changes: 2 additions & 2 deletions nodes/widgets/locales/en-US/ui_text_input.html
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ <h3>Dynamic Properties (Inputs)</h3>
<dt class="optional">mode <span class="property-type">string</span></dt>
<dd>Change the text input to a "password", "color", or any of the other available "modes".</dd>
<dt class="optional">label <span class="property-type">string</span></dt>
<dd>Override the label displayed with the Text Input.</dd>
<dd>Override the label displayed with the Text Input. Html content is allowed.</dd>
<dt class="optional">icon <span class="property-type">string</span></dt>
<dd>Override the icon defined in the initial configuration</dd>
<dt class="optional">iconPosition <span class="property-type">'left' | 'right'</span></dt>
Expand All @@ -38,4 +38,4 @@ <h3>Dynamic Properties (Inputs)</h3>
<dt class="optional">class <span class="property-type">string</span></dt>
<dd>Add a CSS class, or more, to the Button at runtime.</dd>
</dl>
</script>
</script>
9 changes: 5 additions & 4 deletions ui/src/widgets/ui-button-group/UIButtonGroup.vue
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
<template>
<div class="nrdb-ui-button-group-wrapper">
<label v-if="label" class="v-label">
{{ label }}
</label>
<!-- eslint-disable-next-line vue/no-v-html -->
<label v-if="label" class="v-label" v-html="label" />
<v-btn-toggle v-model="selection" mandatory divided :rounded="props.rounded ? 'xl' : ''" :color="selectedColor" :disabled="!state.enabled" @update:model-value="onChange(selection)">
<v-btn v-for="option in options" :key="option.value" :value="option.value">
<template v-if="option.icon && option.label !== undefined && option.label !== ''" #prepend>
Expand All @@ -16,6 +15,7 @@
</template>

<script>
import DOMPurify from 'dompurify'
import { mapState } from 'vuex'
export default {
Expand Down Expand Up @@ -44,7 +44,8 @@ export default {
return this.look === 'default' ? null : this.look
},
label: function () {
return this.getProperty('label')
// Sanetize the html to avoid XSS attacks
return DOMPurify.sanitize(this.getProperty('label'))
},
options: function () {
const options = this.getProperty('options')
Expand Down
22 changes: 17 additions & 5 deletions ui/src/widgets/ui-dropdown/UIDropdown.vue
Original file line number Diff line number Diff line change
@@ -1,19 +1,30 @@
<template>
<v-combobox
v-if="typeIsComboBox === true" v-model="value" :disabled="!state.enabled" :class="className" :label="label"
v-if="typeIsComboBox === true" v-model="value" :disabled="!state.enabled" :class="className"
:multiple="multiple" :chips="chips" :clearable="clearable" :items="options" item-title="label"
item-value="value" variant="outlined" hide-details="auto" auto-select-first
:error-messages="options?.length ? '' : 'No options available'" @update:model-value="onChange"
/>
>
<template #label>
<!-- eslint-disable-next-line vue/no-v-html -->
<span v-html="label" />
</template>
</v-combobox>
<v-select
v-else v-model="value" :disabled="!state.enabled" :class="className" :label="label" :multiple="multiple"
v-else v-model="value" :disabled="!state.enabled" :class="className" :multiple="multiple"
:chips="chips" :clearable="clearable" :items="options" item-title="label" item-value="value" variant="outlined"
hide-details="auto" :error-messages="options?.length ? '' : 'No options available'"
@update:model-value="onChange"
/>
>
<template #label>
<!-- eslint-disable-next-line vue/no-v-html -->
<span v-html="label" />
</template>
</v-select>
</template>

<script>
import DOMPurify from 'dompurify'
import { mapState } from 'vuex'
export default {
Expand Down Expand Up @@ -65,7 +76,8 @@ export default {
return this.getProperty('clearable')
},
label: function () {
return this.getProperty('label')
// Sanetize the html to avoid XSS attacks
return DOMPurify.sanitize(this.getProperty('label'))
},
typeIsComboBox: function () {
return this.props.typeIsComboBox ?? true
Expand Down
13 changes: 10 additions & 3 deletions ui/src/widgets/ui-number-input/UINumberInput.vue
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,23 @@
<template #activator="{ props }">
<v-number-input
v-model="value" :class="{'compressed': isCompressed, 'stacked-spinner': spinner === 'stacked'}" :reverse="false" :controlVariant="spinner" :hideInput="false" :inset="false"
v-bind="props" :disabled="!state.enabled" :label="label"
v-bind="props" :disabled="!state.enabled"
:rules="validation" :clearable="clearable" variant="outlined" hide-details="auto"
:prepend-icon="prependIcon" :append-icon="appendIcon" :append-inner-icon="appendInnerIcon"
:prepend-inner-icon="prependInnerIcon" :min="min" :max="max" :step="step" @update:model-value="onChange" @keyup.enter="onEnter" @blur="onBlur" @click:clear="onClear"
/>
>
<template #label>
<!-- eslint-disable-next-line vue/no-v-html -->
<span v-html="label" />
</template>
</v-number-input>
</template>
</v-tooltip>
</div>
</template>

<script>
import DOMPurify from 'dompurify'
// eslint-disable-next-line import/no-unresolved
import { VNumberInput } from 'vuetify/labs/VNumberInput'
import { mapState } from 'vuex' // eslint-disable-line import/order
Expand All @@ -42,7 +48,8 @@ export default {
computed: {
...mapState('data', ['messages']),
label () {
return this.getProperty('label')
// Sanetize the html to avoid XSS attacks
return DOMPurify.sanitize(this.getProperty('label'))
},
tooltip () {
return this.props.tooltip
Expand Down
10 changes: 8 additions & 2 deletions ui/src/widgets/ui-radio-group/UIRadioGroup.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,13 @@
<v-radio-group
v-model="value" class="nrdb-ui-radio-group" :disabled="!state.enabled"
:class="'nrdb-ui-radio-group--cols-' + columns + ' ' + className"
:label="label" variant="outlined" hide-details="auto"
variant="outlined" hide-details="auto"
@update:model-value="onChange"
>
<template #label>
<!-- eslint-disable-next-line vue/no-v-html -->
<span v-html="label" />
</template>
<v-radio
v-for="option in options" :key="option.value"
:label="option.label" :value="option.value"
Expand All @@ -13,6 +17,7 @@
</template>

<script>
import DOMPurify from 'dompurify'
import { mapState } from 'vuex' // eslint-disable-line import/order
export default {
Expand All @@ -32,7 +37,8 @@ export default {
computed: {
...mapState('data', ['messages']),
label: function () {
return this.getProperty('label')
// Sanetize the html to avoid XSS attacks
return DOMPurify.sanitize(this.getProperty('label'))
},
columns: function () {
return this.getProperty('columns')
Expand Down
13 changes: 10 additions & 3 deletions ui/src/widgets/ui-slider/UISlider.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<!-- eslint-disable vuetify/no-deprecated-events -->
<template>
<v-slider
v-model="value" :disabled="!state.enabled" :label="label" hide-details="auto"
v-model="value" :disabled="!state.enabled" hide-details="auto"
:class="className" :style="`--nrdb-slider-track-color:${colorTrack};--nrdb-slider-tick-scaleY:${tickScaleY};--nrdb-slider-tick-scaleX:${tickScaleX};`"
:thumb-label="thumbLabel"
:append-icon="iconAppend" :prepend-icon="iconPrepend"
Expand All @@ -11,10 +11,16 @@
:color="color" :track-color="colorTrack" :thumb-color="colorThumb"
:max="max" :step="step || 1" :show-ticks="showTicks"
@update:model-value="onChange" @end="onBlur"
/>
>
<template #label>
<!-- eslint-disable-next-line vue/no-v-html -->
<span v-html="label" />
</template>
</v-slider>
</template>

<script>
import DOMPurify from 'dompurify'
import { mapState } from 'vuex' // eslint-disable-line import/order

export default {
Expand Down Expand Up @@ -45,7 +51,8 @@ export default {
return this.props.height > this.props.width ? 0.5 : 3
},
label: function () {
return this.getProperty('label')
// Sanetize the html to avoid XSS attacks
return DOMPurify.sanitize(this.getProperty('label'))
},
thumbLabel: function () {
return this.getProperty('thumbLabel')
Expand Down
Loading

0 comments on commit 9dc380b

Please sign in to comment.