@flowfuse/node-red-dashboard 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (67) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +53 -0
  3. package/dist/css/app.d047b42b.css +1 -0
  4. package/dist/css/chunk-vendors.2378ce49.css +24 -0
  5. package/dist/fonts/materialdesignicons-webfont.3de8526e.woff +0 -0
  6. package/dist/fonts/materialdesignicons-webfont.477c6ab0.woff2 +0 -0
  7. package/dist/fonts/materialdesignicons-webfont.48a1ce0c.eot +0 -0
  8. package/dist/fonts/materialdesignicons-webfont.dfd403cf.ttf +0 -0
  9. package/dist/index.html +1 -0
  10. package/dist/js/app.854a8cd5.js +2 -0
  11. package/dist/js/app.854a8cd5.js.map +1 -0
  12. package/dist/js/chunk-vendors.174e8921.js +43 -0
  13. package/dist/js/chunk-vendors.174e8921.js.map +1 -0
  14. package/nodes/config/locales/en-US/ui_base.json +19 -0
  15. package/nodes/config/locales/en-US/ui_group.html +4 -0
  16. package/nodes/config/locales/en-US/ui_group.json +16 -0
  17. package/nodes/config/ui_base.html +807 -0
  18. package/nodes/config/ui_base.js +678 -0
  19. package/nodes/config/ui_group.html +55 -0
  20. package/nodes/config/ui_group.js +34 -0
  21. package/nodes/config/ui_page.html +84 -0
  22. package/nodes/config/ui_page.js +33 -0
  23. package/nodes/config/ui_theme.html +101 -0
  24. package/nodes/config/ui_theme.js +15 -0
  25. package/nodes/store/index.js +34 -0
  26. package/nodes/utils/index.js +35 -0
  27. package/nodes/widgets/locales/en-US/ui_button.html +7 -0
  28. package/nodes/widgets/locales/en-US/ui_button.json +24 -0
  29. package/nodes/widgets/locales/en-US/ui_chart.html +41 -0
  30. package/nodes/widgets/locales/en-US/ui_chart.json +17 -0
  31. package/nodes/widgets/locales/en-US/ui_dropdown.html +24 -0
  32. package/nodes/widgets/locales/en-US/ui_form.html +16 -0
  33. package/nodes/widgets/locales/en-US/ui_form.json +36 -0
  34. package/nodes/widgets/locales/en-US/ui_markdown.html +10 -0
  35. package/nodes/widgets/locales/en-US/ui_slider.html +9 -0
  36. package/nodes/widgets/locales/en-US/ui_switch.html +32 -0
  37. package/nodes/widgets/locales/en-US/ui_template.html +59 -0
  38. package/nodes/widgets/locales/en-US/ui_template.json +18 -0
  39. package/nodes/widgets/locales/en-US/ui_text.html +16 -0
  40. package/nodes/widgets/locales/en-US/ui_text_input.html +19 -0
  41. package/nodes/widgets/ui_button.html +146 -0
  42. package/nodes/widgets/ui_button.js +65 -0
  43. package/nodes/widgets/ui_chart.html +314 -0
  44. package/nodes/widgets/ui_chart.js +195 -0
  45. package/nodes/widgets/ui_dropdown.html +199 -0
  46. package/nodes/widgets/ui_dropdown.js +19 -0
  47. package/nodes/widgets/ui_form.html +368 -0
  48. package/nodes/widgets/ui_form.js +18 -0
  49. package/nodes/widgets/ui_markdown.html +134 -0
  50. package/nodes/widgets/ui_markdown.js +14 -0
  51. package/nodes/widgets/ui_notification.html +139 -0
  52. package/nodes/widgets/ui_notification.js +14 -0
  53. package/nodes/widgets/ui_radio_group.html +186 -0
  54. package/nodes/widgets/ui_radio_group.js +20 -0
  55. package/nodes/widgets/ui_slider.html +162 -0
  56. package/nodes/widgets/ui_slider.js +31 -0
  57. package/nodes/widgets/ui_switch.html +194 -0
  58. package/nodes/widgets/ui_switch.js +98 -0
  59. package/nodes/widgets/ui_table.html +149 -0
  60. package/nodes/widgets/ui_table.js +16 -0
  61. package/nodes/widgets/ui_template.html +283 -0
  62. package/nodes/widgets/ui_template.js +19 -0
  63. package/nodes/widgets/ui_text.html +358 -0
  64. package/nodes/widgets/ui_text.js +98 -0
  65. package/nodes/widgets/ui_text_input.html +141 -0
  66. package/nodes/widgets/ui_text_input.js +37 -0
  67. package/package.json +114 -0
@@ -0,0 +1,139 @@
1
+ <style>
2
+ #ui-chart-colors input[type="color"] {
3
+ font-weight: bold;
4
+ }
5
+ #ui-chart-colors input[type="color"]::-webkit-color-swatch,
6
+ #ui-chart-colors input[type="color"]::-moz-color-swatch {
7
+ border: none;
8
+ }
9
+ </style>
10
+
11
+ <script type="text/javascript">
12
+ (function () {
13
+ RED.nodes.registerType('ui-notification', {
14
+ category: RED._('@flowforge/node-red-dashboard/ui-base:ui-base.label.category'),
15
+ color: RED._('@flowforge/node-red-dashboard/ui-base:ui-base.colors.medium'),
16
+ defaults: {
17
+ ui: { type: 'ui-base', value: '', required: true },
18
+ position: { value: 'top right' },
19
+ colorDefault: { value: true },
20
+ color: { value: null },
21
+ displayTime: { value: '3' },
22
+ showCountdown: { value: true },
23
+ outputs: { value: 0 },
24
+ allowDismiss: { value: 'OK' },
25
+ dismissText: { value: 'Close' },
26
+ raw: { value: false },
27
+ className: { value: '' },
28
+ name: { value: '' }
29
+ },
30
+ inputs: 1,
31
+ outputs: 0,
32
+ align: 'right',
33
+ icon: 'font-awesome/fa-envelope-o',
34
+ paletteLabel: 'notification',
35
+ label: function () { return this.name || (this.position === 'prompt' ? 'show dialog' : (this.position === 'dialog' ? 'show dialog' : 'show notification')) },
36
+ labelStyle: function () { return this.name ? 'node_label_italic' : '' },
37
+ oneditprepare: function () {
38
+ $('#node-input-topic').typedInput({
39
+ default: 'str',
40
+ typeField: $('#node-input-topicType'),
41
+ types: ['str', 'msg', 'flow', 'global']
42
+ })
43
+
44
+ $('#node-input-allowDismiss').on('change', function () {
45
+ const allowDismiss = $('#node-input-allowDismiss').is(':checked')
46
+ if (allowDismiss) {
47
+ $('#node-notification-dismissText').show()
48
+ } else {
49
+ $('#node-notification-dismissText').hide()
50
+ }
51
+ })
52
+
53
+ $('#node-input-colorDefault').on('change', function () {
54
+ const defaultColor = $('#node-input-colorDefault').is(':checked')
55
+ console.log(defaultColor)
56
+ if (defaultColor) {
57
+ $('#node-input-color').hide()
58
+ } else {
59
+ $('#node-input-color').show()
60
+ }
61
+ })
62
+
63
+ // use jQuery UI tooltip to convert the plain old title attribute to a nice tooltip
64
+ $('.ui-node-popover-title').tooltip({
65
+ show: {
66
+ effect: 'slideDown',
67
+ delay: 150
68
+ }
69
+ })
70
+ }
71
+ })
72
+ })()
73
+ </script>
74
+
75
+ <script type="text/html" data-template-name="ui-notification">
76
+ <div class="form-row">
77
+ <label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
78
+ <input type="text" id="node-input-name" placeholder="Name">
79
+ </div>
80
+ <div class="form-row">
81
+ <label for="node-input-ui"><i class="fa fa-bookmark"></i> UI</label>
82
+ <input type="text" id="node-input-ui">
83
+ </div>
84
+ <div class="form-row">
85
+ <label for="node-input-position"><i class="fa fa-th-large"></i> Position</label>
86
+ <select type="text" id="node-input-position" style="display:inline-block; width:70%; vertical-align:baseline;">
87
+ <option value="top right">Top Right</option>
88
+ <option value="top center">Top Center</option>
89
+ <option value="top left">Top Left</option>
90
+ <option value="bottom right">Bottom Right</option>
91
+ <option value="bottom right">Bottom Center</option>
92
+ <option value="bottom left">Bottom Left</option>
93
+ <option value="center center">Center</option>
94
+ </select>
95
+ </div>
96
+ <div class="form-row">
97
+ <label for="node-input-color"><i class="fa fa-paint-brush"></i> Color</label>
98
+ <div style="display: inline-flex; gap: 8px; align-items: center;">
99
+ <input type="checkbox" id="node-input-colorDefault" style="width: auto; margin: 0;">
100
+ <label for="node-input-colorDefault" style="margin: 0; line-height: 34px;">Default</label>
101
+ <input type="color" id="node-input-color" placeholder="#FFFFFF">
102
+ </div>
103
+ </div>
104
+ <div class="form-row" id="node-toast-displaytime">
105
+ <label for="node-input-displayTime"><i class="fa fa-clock-o"></i> Timeout (S)</label>
106
+ <input type="text" id="node-input-displayTime" placeholder="[msg.timeout]">
107
+ </div>
108
+ <div class="form-row form-row-flex" id="node-notification-showCountdown">
109
+ <input type="checkbox" id="node-input-showCountdown">
110
+ <label for="node-input-showCountdown">Show timeout countdown bar on notification</label>
111
+ </div>
112
+ <div class="form-row form-row-flex" id="node-notification-allowDismiss">
113
+ <input type="checkbox" id="node-input-allowDismiss">
114
+ <label for="node-input-allowDismiss"> Allow Manual Dismissal</label>
115
+ </div>
116
+ <div class="form-row form-row-flex" style="margin-left: 32px;" id="node-notification-dismissText">
117
+ <label for="node-input-dismissText"><i class="fa fa-check"></i> Button Label</label>
118
+ <input type="text" id="node-input-dismissText" placeholder="Close">
119
+ </div>
120
+ <div class="form-row form-row-flex" id="node-toast-raw">
121
+ <input type="checkbox" id="node-input-raw" style="display:inline-block; width:auto; vertical-align:baseline;">
122
+ <label style="width:auto" for="node-input-raw"> Accept raw HTML/JavaScript input in msg.payload to format popup.</label>
123
+ </div>
124
+ <div class="form-row">
125
+ <label for="node-input-className"><i class="fa fa-code"></i> Class</label>
126
+ <div style="display: inline;">
127
+ <input style="width: 70%;" type="text" id="node-input-className" placeholder="Optional CSS class name(s)" style="flex-grow: 1;">
128
+ <a
129
+ data-html="true"
130
+ title="Dynamic Property: Class names can also be set by sending a message to the node with a msg.topic of 'ui-property:class' and a payload containing the class name(s) to be applied. NOTE: classes set at runtime will be applied in addition to any class(es) set in the nodes class field."
131
+ class="red-ui-button ui-node-popover-title"
132
+ style="margin-left: 4px; cursor: help; font-size: 0.625rem; border-radius: 50%; width: 24px; height: 24px; display: inline-flex; justify-content: center; align-items: center;">
133
+ <i style="font-family: ui-serif;">fx</i>
134
+ </a>
135
+ </div>
136
+ </div>
137
+ <div class="form-tips"><b>Note</b>: checking <i>Accept raw HTML/JavaScript</i> can allow injection of code.
138
+ Ensure the input comes from trusted sources.</span></div>
139
+ </script>
@@ -0,0 +1,14 @@
1
+ module.exports = function (RED) {
2
+ function NotificationNode (config) {
3
+ const node = this
4
+
5
+ RED.nodes.createNode(this, config)
6
+
7
+ // which group are we rendering this widget
8
+ const ui = RED.nodes.getNode(config.ui)
9
+
10
+ // inform the dashboard UI that we are adding this node
11
+ ui.register(null, null, node, config)
12
+ }
13
+ RED.nodes.registerType('ui-notification', NotificationNode)
14
+ }
@@ -0,0 +1,186 @@
1
+ <script type="text/javascript">
2
+ (function () {
3
+ function hasProperty (obj, prop) {
4
+ return Object.prototype.hasOwnProperty.call(obj, prop)
5
+ }
6
+ RED.nodes.registerType('ui-radio-group', {
7
+ category: RED._('@flowforge/node-red-dashboard/ui-base:ui-base.label.category'),
8
+ color: RED._('@flowforge/node-red-dashboard/ui-base:ui-base.colors.light'),
9
+ defaults: {
10
+ group: { type: 'ui-group', required: true },
11
+ name: { value: '' },
12
+ label: { value: 'Select Option:' },
13
+ order: { value: 0 },
14
+ width: {
15
+ value: 0,
16
+ validate: function (v) {
17
+ const width = v || 0
18
+ const currentGroup = $('#node-input-group').val() || this.group
19
+ const groupNode = RED.nodes.node(currentGroup)
20
+ const valid = !groupNode || +width <= +groupNode.width
21
+ $('#node-input-size').toggleClass('input-error', !valid)
22
+ return valid
23
+ }
24
+ },
25
+ height: { value: 0 },
26
+ columns: { value: 1 },
27
+ passthru: { value: false },
28
+ options: {
29
+ value: [{ value: '', label: '' }],
30
+ validate: function (v) {
31
+ const unique = new Set(v.map(function (o) { return o.value }))
32
+ return v.length === unique.size
33
+ }
34
+ },
35
+ payload: { value: '' },
36
+ topic: { value: 'topic', validate: (hasProperty(RED.validators, 'typedInput') ? RED.validators.typedInput('topicType') : function (v) { return true }) },
37
+ topicType: { value: 'msg' },
38
+ className: { value: '' }
39
+ },
40
+ inputs: 1,
41
+ outputs: 1,
42
+ icon: 'font-awesome/fa-dot-circle-o',
43
+ paletteLabel: 'radio group',
44
+ label: function () { return this.name || (~this.label.indexOf('{' + '{') ? null : this.label) || 'radio group' },
45
+ labelStyle: function () { return this.name ? 'node_label_italic' : '' },
46
+ oneditprepare: function () {
47
+ if (this.multiple === undefined) {
48
+ $('#node-input-multiple').prop('checked', false)
49
+ }
50
+ // $("#node-input-size").elementSizer({
51
+ // width: "#node-input-width",
52
+ // height: "#node-input-height",
53
+ // group: "#node-input-group"
54
+ // });
55
+ const un = new Set(this.options.map(function (o) { return o.value }))
56
+ if (this.options.length === un.size) { $('#valWarning').hide() } else { $('#valWarning').show() }
57
+
58
+ function generateOption (i, option) {
59
+ const container = $('<li/>', { style: 'background: var(--red-ui-secondary-background, #fff); margin:0; padding:8px 0px 0px; border-bottom: 1px solid var(--red-ui-form-input-border-color, #ccc);' })
60
+ const row = $('<div/>').appendTo(container)
61
+ $('<div/>', { style: 'padding-top:5px; padding-left:175px;' }).appendTo(container)
62
+ $('<div/>', { style: 'padding-top:5px; padding-left:120px;' }).appendTo(container)
63
+
64
+ $('<i style="color: var(--red-ui-form-text-color, #eee); cursor:move; margin-left:3px;" class="node-input-option-handle fa fa-bars"></i>').appendTo(row)
65
+
66
+ $('<input/>', { class: 'node-input-option-value', type: 'text', style: 'margin-left:7px; width:calc(50% - 32px);', placeholder: 'Value', value: option.value }).appendTo(row).typedInput({ default: option.type || 'str', types: ['str', 'num', 'bool'] })
67
+ $('<input/>', { class: 'node-input-option-label', type: 'text', style: 'margin-left:7px; width:calc(50% - 32px);', placeholder: 'Label', value: option.label }).appendTo(row)
68
+
69
+ const finalSpan = $('<span/>', { style: 'float:right; margin-right:8px;' }).appendTo(row)
70
+ const deleteButton = $('<a/>', { href: '#', class: 'editor-button editor-button-small', style: 'margin-top:7px; margin-left:5px;' }).appendTo(finalSpan)
71
+ $('<i/>', { class: 'fa fa-remove' }).appendTo(deleteButton)
72
+
73
+ deleteButton.click(function () {
74
+ container.css({ background: 'var(--red-ui-secondary-background-inactive, #fee)' })
75
+ container.fadeOut(300, function () {
76
+ $(this).remove()
77
+ })
78
+ })
79
+
80
+ $('#node-input-option-container').append(container)
81
+ }
82
+
83
+ $('#node-input-add-option').click(function () {
84
+ generateOption($('#node-input-option-container').children().length + 1, {})
85
+ $('#node-input-option-container-div').scrollTop($('#node-input-option-container-div').get(0).scrollHeight)
86
+ })
87
+
88
+ for (let i = 0; i < this.options.length; i++) {
89
+ const option = this.options[i]
90
+ generateOption(i + 1, option)
91
+ }
92
+
93
+ $('#node-input-option-container').sortable({
94
+ axis: 'y',
95
+ handle: '.node-input-option-handle',
96
+ cursor: 'move'
97
+ })
98
+
99
+ $('#node-input-topic').typedInput({
100
+ default: 'str',
101
+ typeField: $('#node-input-topicType'),
102
+ types: ['str', 'msg', 'flow', 'global']
103
+ })
104
+
105
+ // use jQuery UI tooltip to convert the plain old title attribute to a nice tooltip
106
+ $('.ui-node-popover-title').tooltip({
107
+ show: {
108
+ effect: 'slideDown',
109
+ delay: 150
110
+ }
111
+ })
112
+ },
113
+ oneditsave: function () {
114
+ const options = $('#node-input-option-container').children()
115
+ const node = this
116
+ node.options = []
117
+ options.each(function (i) {
118
+ const option = $(this)
119
+ const o = {
120
+ label: option.find('.node-input-option-label').val(),
121
+ value: option.find('.node-input-option-value').typedInput('value'),
122
+ type: option.find('.node-input-option-value').typedInput('type')
123
+ }
124
+ if (option.find('.node-input-option-value').typedInput('type') === 'num') {
125
+ o.value = Number(o.value)
126
+ }
127
+ if (option.find('.node-input-option-value').typedInput('type') === 'bool') {
128
+ o.value = (o.value === 'true')
129
+ }
130
+ node.options.push(o)
131
+ })
132
+ }
133
+ })
134
+ })()
135
+ </script>
136
+
137
+ <script type="text/html" data-template-name="ui-radio-group">
138
+ <div class="form-row">
139
+ <label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
140
+ <input type="text" id="node-input-name">
141
+ </div>
142
+ <div class="form-row">
143
+ <label for="node-input-group"><i class="fa fa-table"></i> Group</label>
144
+ <input type="text" id="node-input-group">
145
+ </div>
146
+ <div class="form-row">
147
+ <label for="node-input-label"><i class="fa fa-tag"></i> Label</label>
148
+ <input type="text" id="node-input-label" placeholder="optional label">
149
+ </div>
150
+ <div class="form-row">
151
+ <label for="node-input-className"><i class="fa fa-code"></i> Class</label>
152
+ <div style="display: inline;">
153
+ <input style="width: 70%;" type="text" id="node-input-className" placeholder="Optional CSS class name(s)" style="flex-grow: 1;">
154
+ <a
155
+ data-html="true"
156
+ title="Dynamic Property: Class names can also be set by sending a message to the node with a msg.topic of 'ui-property:class' and a payload containing the class name(s) to be applied. NOTE: classes set at runtime will be applied in addition to any class(es) set in the nodes class field."
157
+ class="red-ui-button ui-node-popover-title"
158
+ style="margin-left: 4px; cursor: help; font-size: 0.625rem; border-radius: 50%; width: 24px; height: 24px; display: inline-flex; justify-content: center; align-items: center;">
159
+ <i style="font-family: ui-serif;">fx</i>
160
+ </a>
161
+ </div>
162
+ </div>
163
+ <div class="form-row node-input-option-container-row" style="margin-bottom: 0px;width: 100%">
164
+ <label for="node-input-width" style="vertical-align:top"><i class="fa fa-list-alt"></i> Options</label>
165
+ <div id="node-input-option-container-div" style="box-sizing:border-box; border-radius:5px; height:257px; padding:5px; border:1px solid var(--red-ui-form-input-border-color, #ccc); overflow-y:scroll; display:inline-block; width:calc(70% + 15px);">
166
+ <span id="valWarning" style="color: var(--red-ui-text-color-error, #910000)"><b>All Values must be unique.</b></span>
167
+ <ol id="node-input-option-container" style="list-style-type:none; margin:0;"></ol>
168
+ </div>
169
+ </div>
170
+ <div class="form-row">
171
+ <a href="#" class="editor-button editor-button-small" id="node-input-add-option" style="margin-top:4px; margin-left:103px;"><i class="fa fa-plus"></i> <span>option</span></a>
172
+ </div>
173
+ <div class="form-row">
174
+ <label for="node-input-columns"><i class="fa fa-tag"></i> Columns</label>
175
+ <input type="number" id="node-input-columns" placeholder="columns" min="1" max="5">
176
+ </div>
177
+ <div class="form-row">
178
+ <label for="node-input-topic"><i class="fa fa-tasks"></i> Topic</label>
179
+ <input type="text" id="node-input-topic" style="width:70%" placeholder="optional msg.topic">
180
+ <input type="hidden" id="node-input-topicType">
181
+ </div>
182
+ <div class="form-row">
183
+ <label style="width:auto" for="node-input-passthru"><i class="fa fa-arrow-right"></i> If <code>msg</code> arrives on input, pass through to output: </label>
184
+ <input type="checkbox" checked id="node-input-passthru" style="display:inline-block; width:auto; vertical-align:top;">
185
+ </div>
186
+ </script>
@@ -0,0 +1,20 @@
1
+ module.exports = function (RED) {
2
+ function RadioGroupNode (config) {
3
+ // create node in Node-RED
4
+ RED.nodes.createNode(this, config)
5
+
6
+ const node = this
7
+
8
+ // which group are we rendering this widget
9
+ const group = RED.nodes.getNode(config.group)
10
+
11
+ const evts = {
12
+ onChange: true
13
+ }
14
+
15
+ // inform the dashboard UI that we are adding this node
16
+ group.register(node, config, evts)
17
+ }
18
+
19
+ RED.nodes.registerType('ui-radio-group', RadioGroupNode)
20
+ }
@@ -0,0 +1,162 @@
1
+ <script type="text/javascript">
2
+ (function () {
3
+ function hasProperty (obj, prop) {
4
+ return Object.prototype.hasOwnProperty.call(obj, prop)
5
+ }
6
+ RED.nodes.registerType('ui-slider', {
7
+ category: RED._('@flowforge/node-red-dashboard/ui-base:ui-base.label.category'),
8
+ color: RED._('@flowforge/node-red-dashboard/ui-base:ui-base.colors.light'),
9
+ defaults: {
10
+ group: { type: 'ui-group', required: true },
11
+ name: { value: '' },
12
+ label: { value: 'slider' },
13
+ tooltip: { value: '' },
14
+ order: { value: 0 },
15
+ width: {
16
+ value: 0,
17
+ validate: function (v) {
18
+ const width = v || 0
19
+ const currentGroup = $('#node-input-group').val() || this.group
20
+ const groupNode = RED.nodes.node(currentGroup)
21
+ const valid = !groupNode || +width <= +groupNode.width
22
+ $('#node-input-size').toggleClass('input-error', !valid)
23
+ return valid
24
+ }
25
+ },
26
+ height: { value: 0 },
27
+ passthru: { value: false },
28
+ outs: { value: 'all' },
29
+ topic: { value: 'topic', validate: (hasProperty(RED.validators, 'typedInput') ? RED.validators.typedInput('topicType') : function (v) { return true }) },
30
+ topicType: { value: 'msg' },
31
+ thumbLabel: { value: true },
32
+ min: { value: 0, required: true, validate: RED.validators.number() },
33
+ max: { value: 10, required: true, validate: RED.validators.number() },
34
+ step: { value: 1 },
35
+ className: { value: '' }
36
+ },
37
+ inputs: 1,
38
+ outputs: 1,
39
+ outputLabels: function () { return this.min + ' - ' + this.max },
40
+ icon: 'font-awesome/fa-sliders',
41
+ paletteLabel: 'slider',
42
+ label: function () { return this.name || (~this.label.indexOf('{' + '{') ? null : this.label) || 'slider' },
43
+ labelStyle: function () { return this.name ? 'node_label_italic' : '' },
44
+ oneditprepare: function () {
45
+ $('#node-input-size').elementSizer({
46
+ width: '#node-input-width',
47
+ height: '#node-input-height',
48
+ group: '#node-input-group'
49
+ })
50
+ $('#node-input-topic').typedInput({
51
+ default: 'str',
52
+ typeField: $('#node-input-topicType'),
53
+ types: ['str', 'msg', 'flow', 'global']
54
+ })
55
+ // if (!$("#node-input-outs").val()) { $("#node-input-outs").val("all") }
56
+
57
+ // use jQuery UI tooltip to convert the plain old title attribute to a nice tooltip
58
+ $('.ui-node-popover-title').tooltip({
59
+ show: {
60
+ effect: 'slideDown',
61
+ delay: 150
62
+ }
63
+ })
64
+ }
65
+ })
66
+ })()
67
+ </script>
68
+
69
+ <script type="text/html" data-template-name="ui-slider">
70
+ <div class="form-row">
71
+ <label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
72
+ <input type="text" id="node-input-name">
73
+ <input type="hidden" id="node-input-topicType">
74
+ </div>
75
+ <div class="ui-slider">
76
+ <div class="form-row">
77
+ <label for="node-input-group"><i class="fa fa-table"></i> Group</label>
78
+ <input type="text" id="node-input-group">
79
+ </div>
80
+ <div class="form-row">
81
+ <label><i class="fa fa-object-group"></i> Size</label>
82
+ <input type="hidden" id="node-input-width">
83
+ <input type="hidden" id="node-input-height">
84
+ <button class="editor-button" id="node-input-size"></button>
85
+ </div>
86
+ <div class="form-row">
87
+ <label for="node-input-className"><i class="fa fa-code"></i> Class</label>
88
+ <div style="display: inline;">
89
+ <input style="width: 70%;" type="text" id="node-input-className" placeholder="Optional CSS class name(s)" style="flex-grow: 1;">
90
+ <a
91
+ data-html="true"
92
+ title="Dynamic Property: Class names can also be set by sending a message to the node with a msg.topic of 'ui-property:class' and a payload containing the class name(s) to be applied. NOTE: classes set at runtime will be applied in addition to any class(es) set in the nodes class field."
93
+ class="red-ui-button ui-node-popover-title"
94
+ style="margin-left: 4px; cursor: help; font-size: 0.625rem; border-radius: 50%; width: 24px; height: 24px; display: inline-flex; justify-content: center; align-items: center;">
95
+ <i style="font-family: ui-serif;">fx</i>
96
+ </a>
97
+ </div>
98
+ </div>
99
+ <div class="form-row">
100
+ <label for="node-input-label"><i class="fa fa-i-cursor"></i> Label</label>
101
+ <input type="text" id="node-input-label">
102
+ </div>
103
+ <div class="form-row">
104
+ <label><i class="fa fa-i-cursor"></i> Thumb</label>
105
+ <input type="checkbox" id="node-input-thumbLabel" style="display: inline-block; width: auto; vertical-align: top; margin: 0 3px 0 0;"/>
106
+ <label for="node-input-thumbLabel" style="width: 70%;"> Show Thumb Label</label>
107
+ </div>
108
+ <!--<div class="form-row">
109
+ <label for="node-input-tooltip"><i class="fa fa-info-circle"></i> Tooltip</label>
110
+ <input type="text" id="node-input-tooltip" placeholder="optional tooltip">
111
+ </div>-->
112
+ <div class="form-row">
113
+ <label for="node-input-min"><i class="fa fa-arrows-h"></i> Range</label>
114
+ <div style="display: grid; grid-template-columns: repeat(3, 1fr); width: 70%">
115
+ <div>
116
+ <span for="node-input-min">min</span>
117
+ <input type="text" id="node-input-min" style="width:60px">
118
+ </div>
119
+ <div>
120
+ <span for="not-input-step">step</span>
121
+ <input type="text" id="node-input-step" style="width:60px">
122
+ </div>
123
+ <div>
124
+ <span for="not-input-max">max</span>
125
+ <input type="text" id="node-input-max" style="width:60px">
126
+ </div>
127
+ </div>
128
+ </div>
129
+ <!-- <div class="form-row">
130
+ <label for="node-input-outs"><i class="fa fa-sign-out"></i> Output</label>
131
+ <select id="node-input-outs" style="width:204px">
132
+ <option value="all">continuously while sliding</option>
133
+ <option value="end">only on release</option>
134
+ </select>
135
+ </div>-->
136
+ <div class="form-row">
137
+ <label style="width:auto" for="node-input-passthru"><i class="fa fa-arrow-right"></i> If <code>msg</code> arrives on input, pass through to output: </label>
138
+ <input type="checkbox" checked id="node-input-passthru" style="display:inline-block; width:auto; vertical-align:top;">
139
+ </div>
140
+ <div class="form-row">
141
+ <label style="width:auto" for="node-input-payload"><i class="fa fa-envelope-o"></i> When changed, send:</label>
142
+ </div>
143
+ <!-- <div class="form-row">
144
+ <label style="padding-left:25px; margin-right:-25px">Payload</label>
145
+ <label style="width:auto">Current value</label>
146
+ </div> -->
147
+ <div class="form-row">
148
+ <label for="node-input-topic" style="padding-left:25px; margin-right:-25px">Topic</label>
149
+ <input type="text" id="node-input-topic">
150
+ </div>
151
+ </div>
152
+ </script>
153
+
154
+ <style id="nr-db2-ui-slider-styles">
155
+ .red-ui-editor div.ui-slider .form-row {
156
+ display: flex;
157
+ align-items: center;
158
+ }
159
+ .red-ui-editor div.ui-slider .form-row label {
160
+ margin-bottom: 0;
161
+ }
162
+ </style>
@@ -0,0 +1,31 @@
1
+ module.exports = function (RED) {
2
+ function SliderNode (config) {
3
+ RED.nodes.createNode(this, config)
4
+ const node = this
5
+
6
+ // which group are we rendering this widget
7
+ const group = RED.nodes.getNode(config.group)
8
+
9
+ this.pt = config.passthru
10
+ this.state = [' ', ' ']
11
+
12
+ node.status({})
13
+
14
+ const evts = {
15
+ onChange: true,
16
+ beforeSend: function (msg) {
17
+ if (!node.pt) {
18
+ node.state[0] = msg.payload
19
+ node.status({ shape: 'dot', fill: 'grey', text: node.state[0] + ' | ' + node.state[1] })
20
+ } else if (node._wireCount === 0) {
21
+ node.status({ shape: 'dot', fill: 'grey', text: msg.payload })
22
+ }
23
+ return msg
24
+ }
25
+ }
26
+
27
+ // inform the dashboard UI that we are adding this node
28
+ group.register(node, config, evts)
29
+ }
30
+ RED.nodes.registerType('ui-slider', SliderNode)
31
+ }