@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,283 @@
1
+ <script type="text/javascript">
2
+ (function () {
3
+ // convert to i18 text
4
+ function c_ (x) {
5
+ return RED._('@flowforge/node-red-dashboard/ui-template:ui-template.' + x)
6
+ }
7
+ // TODO: move this to util.js for reuse & unit testing
8
+ function hasProperty (obj, prop) {
9
+ return Object.prototype.hasOwnProperty.call(obj, prop)
10
+ }
11
+ RED.nodes.registerType('ui-template', {
12
+ category: RED._('@flowforge/node-red-dashboard/ui-base:ui-base.label.category'),
13
+ color: RED._('@flowforge/node-red-dashboard/ui-base:ui-base.colors.dark'),
14
+ defaults: {
15
+ group: { type: 'ui-group', required: true }, // for when template is scoped to 'local' (default)
16
+ dashboard: { type: 'ui-base', required: false }, // for when template is scoped to 'site'
17
+ page: { type: 'ui-page', required: false }, // for when template is scoped to 'page'
18
+ name: { value: '' },
19
+ order: { value: 0 },
20
+ width: {
21
+ value: 0,
22
+ validate: function (v) {
23
+ let valid = true
24
+ if (this.templateScope !== 'global') {
25
+ const width = v || 0
26
+ const currentGroup = $('#node-input-group').val() || this.group
27
+ const groupNode = RED.nodes.node(currentGroup)
28
+ valid = !groupNode || +width <= +groupNode.width
29
+ $('#node-input-size').toggleClass('input-error', !valid)
30
+ }
31
+ return valid
32
+ }
33
+ },
34
+ height: { value: 0 },
35
+ head: { value: '' },
36
+ format: { value: '<div>{{ msg.payload }}</div>' },
37
+ storeOutMessages: { value: true },
38
+ fwdInMessages: { value: true },
39
+ resendOnRefresh: { value: true },
40
+ templateScope: { value: 'local' },
41
+ className: { value: '' }
42
+ },
43
+ inputs: 1,
44
+ outputs: 1,
45
+ icon: 'font-awesome/fa-code',
46
+ paletteLabel: 'template',
47
+ label: function () {
48
+ if (this.name) { return this.name }
49
+ const knownLabels = {
50
+ local: 'template',
51
+ 'site:style': 'site style',
52
+ 'page:style': 'page style'
53
+ }
54
+ return knownLabels[this.templateScope] || 'template'
55
+ },
56
+ labelStyle: function () { return this.name ? 'node_label_italic' : '' },
57
+ oneditprepare: function () {
58
+ if (RED.editor.__debug === true) {
59
+ console.log('ui-template: oneditprepare') // useful for locating this code in the browser debugger
60
+ }
61
+ if (hasProperty(RED.editor, 'editText') && typeof RED.editor.editText === 'function') {
62
+ $('#node-template-expand-editor').show()
63
+ } else {
64
+ $('#node-template-expand-editor').hide()
65
+ }
66
+ const that = this
67
+ const $templateScope = $('#node-input-templateScope')
68
+
69
+ $('#node-input-size').elementSizer({
70
+ width: '#node-input-width',
71
+ height: '#node-input-height',
72
+ group: '#node-input-group'
73
+ })
74
+
75
+ if (typeof this.storeOutMessages === 'undefined') {
76
+ this.storeOutMessages = true
77
+ $('#node-input-storeOutMessages').prop('checked', true)
78
+ }
79
+
80
+ if (typeof this.fwdInMessages === 'undefined') {
81
+ this.fwdInMessages = true
82
+ $('#node-input-fwdInMessages').prop('checked', true)
83
+ }
84
+
85
+ if (typeof this.templateScope === 'undefined') {
86
+ this.templateScope = 'local'
87
+ $templateScope.val(this.templateScope)
88
+ }
89
+
90
+ $templateScope.on('change', function () {
91
+ that._def.defaults.group.required = false
92
+ that._def.defaults.page.required = false
93
+ that._def.defaults.dashboard.required = false
94
+ $('#template-row-group, #template-row-page, #template-row-dashboard, #template-row-class').hide()
95
+ switch ($templateScope.val()) {
96
+ case 'site:style':
97
+ $('#template-row-dashboard').show()
98
+ that._def.defaults.dashboard.required = true
99
+ that.editor.getSession().setMode('ace/mode/css')
100
+ break
101
+ case 'page:style':
102
+ $('#template-row-page').show()
103
+ that._def.defaults.dashboard.required = true
104
+ that.editor.getSession().setMode('ace/mode/css')
105
+ break
106
+ case 'site:script':
107
+ $('#template-row-dashboard').show()
108
+ that._def.defaults.dashboard.required = true
109
+ that.editor.getSession().setMode('ace/mode/javascript')
110
+ break
111
+ case 'page:script':
112
+ $('#template-row-page').show()
113
+ that._def.defaults.dashboard.required = true
114
+ that.editor.getSession().setMode('ace/mode/javascript')
115
+ break
116
+ default:
117
+ $('#template-row-group, #template-row-class').show()
118
+ that._def.defaults.group.required = true
119
+ that.editor.getSession().setMode('ace/mode/html')
120
+ break
121
+ }
122
+ resize.call(that)
123
+ })
124
+
125
+ this.editor = RED.editor.createEditor({
126
+ id: 'node-input-format-editor',
127
+ mode: 'ace/mode/html',
128
+ value: $('#node-input-format').val()
129
+ })
130
+
131
+ RED.library.create({
132
+ url: 'uitemplates', // where to get the data from
133
+ type: 'ui-template', // the type of object the library is for
134
+ editor: this.editor, // the field name the main text body goes to
135
+ mode: 'ace/mode/html',
136
+ fields: ['name']
137
+ })
138
+
139
+ this.editor.focus()
140
+
141
+ RED.popover.tooltip($('#node-template-expand-editor'), c_('label.expand'))
142
+
143
+ $('#node-template-expand-editor').on('click', function (e) {
144
+ e.preventDefault()
145
+ const value = that.editor.getValue()
146
+ RED.editor.editText({
147
+ mode: $templateScope.val() === 'global' ? 'css' : 'html',
148
+ value,
149
+ width: 'Infinity',
150
+ cursor: that.editor.getCursorPosition(),
151
+ complete: function (v, cursor) {
152
+ that.editor.setValue(v, -1)
153
+ that.editor.gotoLine(cursor.row + 1, cursor.column, false)
154
+ setTimeout(function () { that.editor.focus() }, 300)
155
+ }
156
+ })
157
+ })
158
+
159
+ // use jQuery UI tooltip to convert the plain old title attribute to a nice tooltip
160
+ $('.ui-node-popover-title').tooltip({
161
+ show: {
162
+ effect: 'slideDown',
163
+ delay: 150
164
+ }
165
+ })
166
+
167
+ $templateScope.trigger('change') // trigger the change event to hide/show the group/dashboard row
168
+ },
169
+ oneditsave: function () {
170
+ const annot = this.editor.getSession().getAnnotations()
171
+ this.noerr = 0
172
+ $('#node-input-noerr').val(0)
173
+ for (let k = 0; k < annot.length; k++) {
174
+ if (annot[k].type === 'error') {
175
+ $('#node-input-noerr').val(annot.length)
176
+ this.noerr = annot.length
177
+ }
178
+ }
179
+ $('#node-input-format').val(this.editor.getValue())
180
+ this.editor.destroy()
181
+ delete this.editor
182
+ },
183
+ oneditcancel: function () {
184
+ this.editor.destroy()
185
+ delete this.editor
186
+ },
187
+ oneditresize: resize.bind(this)
188
+ })
189
+
190
+ function resize (size) {
191
+ const rows = $('#dialog-form>div:not(.node-text-editor-row)')
192
+ let fixRowsHeight = 0
193
+ for (let i = 0; i < rows.size(); i++) {
194
+ fixRowsHeight += $(rows[i]).height()
195
+ }
196
+ const dialogHeight = $('#dialog-form').height()
197
+ const height = dialogHeight - fixRowsHeight
198
+ $('.node-text-editor').css('height', height + 'px')
199
+ if (RED.editor.__debug === true) {
200
+ console.log('dialogHeight', dialogHeight, 'fixRowsHeight', fixRowsHeight, 'height', height, 'editorRow')
201
+ }
202
+ this.editor && this.editor.resize()
203
+ }
204
+ })()
205
+ </script>
206
+
207
+ <script type="text/html" data-template-name="ui-template">
208
+ <div class="form-row">
209
+ <label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="node-red:common.label.name"></span></label>
210
+ <div style="display:inline-block; width:calc(100% - 105px)">
211
+ <input type="text" id="node-input-name" data-i18n="[placeholder]node-red:common.label.name">
212
+ </div>
213
+ </div>
214
+ <div class="form-row">
215
+ <label for="node-input-temlplateScope"><i class="fa fa-dot-circle-o"></i> <span data-i18n="ui-template.label.scope"></span></label>
216
+ <select style="width:76%" id="node-input-templateScope">
217
+ <option value="local" data-i18n="ui-template.label.local"></option>
218
+ <option value="site:style" data-i18n="ui-template.label.site-style"></option>
219
+ <option value="page:style" data-i18n="ui-template.label.page-style"></option>
220
+ <!-- FUTURE? <option value="site:script" data-i18n="ui-template.label.site-script"></option>
221
+ <option value="page:script" data-i18n="ui-template.label.page-script"></option> -->
222
+ </select>
223
+ </div>
224
+ <div id="template-row-group" class="form-row">
225
+ <label for="node-input-group"><i class="fa fa-table"></i> Group</label>
226
+ <input type="text" id="node-input-group">
227
+ </div>
228
+ <div id="template-row-dashboard" class="form-row">
229
+ <label for="node-input-dashboard"><i class="fa fa-bookmark"></i> Dashboard</label>
230
+ <input type="text" id="node-input-dashboard">
231
+ </div>
232
+ <div id="template-row-page" class="form-row">
233
+ <label for="node-input-page"><i class="fa fa-bookmark"></i> Page</label>
234
+ <input type="text" id="node-input-page">
235
+ </div>
236
+ <div class="form-row">
237
+ <label><i class="fa fa-object-group"></i> Size</label>
238
+ <input type="hidden" id="node-input-width">
239
+ <input type="hidden" id="node-input-height">
240
+ <button class="editor-button" id="node-input-size"></button>
241
+ </div>
242
+ <!--<div class="form-row" id="template-row-size">
243
+ <label><i class="fa fa-object-group"></i> <span data-i18n="ui-template.label.size"></span></label>
244
+ <input type="hidden" id="node-input-width">
245
+ <input type="hidden" id="node-input-height">
246
+ <button class="editor-button" id="node-input-size"></button>
247
+ </div>-->
248
+ <div class="form-row">
249
+ <label for="node-input-className"><i class="fa fa-code"></i> Class</label>
250
+ <div style="display: inline;">
251
+ <input style="width: 70%;" type="text" id="node-input-className" placeholder="Optional CSS class name(s)" style="flex-grow: 1;">
252
+ <a
253
+ data-html="true"
254
+ 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."
255
+ class="red-ui-button ui-node-popover-title"
256
+ 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;">
257
+ <i style="font-family: ui-serif;">fx</i>
258
+ </a>
259
+ </div>
260
+ </div>
261
+ <div class="form-row" style="margin-bottom:0px;">
262
+ <label for="node-input-format"><i class="fa fa-copy"></i> <span data-i18n="ui-template.label.template"></span></label>
263
+ <input type="hidden" id="node-input-format">
264
+ <button id="node-template-expand-editor" class="red-ui-button red-ui-button-small" style="float:right"><i class="fa fa-expand"></i></button>
265
+ </div>
266
+ <div class="form-row node-text-editor-row" style="display: block;">
267
+ <div style="height:250px; min-height:100px" class="node-text-editor" id="node-input-format-editor" ></div>
268
+ </div>
269
+ <!--<div id="template-pass-store">
270
+ <div class="form-row" style="margin-bottom:0px;">
271
+ <input type="checkbox" id="node-input-fwdInMessages" style="display:inline-block; margin-left:8px; width:auto; vertical-align:top;">
272
+ <label for="node-input-fwdInMessages" style="width:70%;"> <span data-i18n="ui-template.label.pass-through"></span></label>
273
+ </div>
274
+ <div class="form-row" style="margin-bottom:0px;">
275
+ <input type="checkbox" id="node-input-storeOutMessages" style="display:inline-block; margin-left:8px; width:auto; vertical-align:top;">
276
+ <label for="node-input-storeOutMessages" style="width:70%;"> <span data-i18n="ui-template.label.store-state"></span></label>
277
+ </div>
278
+ <div class="form-row" style="margin-bottom:0px;">
279
+ <input type="checkbox" id="node-input-resendOnRefresh" style="display:inline-block; margin-left:8px; width:auto; vertical-align:top;">
280
+ <label for="node-input-resendOnRefresh" style="width:70%;"> <span data-i18n="ui-template.label.resend"></span></label>
281
+ </div>
282
+ </div> -->
283
+ </script>
@@ -0,0 +1,19 @@
1
+ module.exports = function (RED) {
2
+ function TemplateNode (config) {
3
+ const node = this
4
+
5
+ // create node in Node-RED
6
+ RED.nodes.createNode(this, config)
7
+
8
+ // which group are we rendering this widget
9
+ const group = RED.nodes.getNode(config.group)
10
+
11
+ const evts = {
12
+ onAction: true // TODO: think we need an onSend event for template nodes that matches up with a `widget-send` message
13
+ }
14
+ // inform the dashboard UI that we are adding this node
15
+ group.register(node, config, evts)
16
+ }
17
+
18
+ RED.nodes.registerType('ui-template', TemplateNode)
19
+ }
@@ -0,0 +1,358 @@
1
+ <script type="text/javascript">
2
+ (function () {
3
+ const fonts = [
4
+ {
5
+ value: 'Arial,Arial,Helvetica,sans-serif',
6
+ name: 'Arial'
7
+ },
8
+ {
9
+ value: 'Arial Black,Arial Black,Gadget,sans-serif',
10
+ name: 'Arial Black'
11
+ },
12
+ {
13
+ value: 'Arial Narrow,Nimbus Sans L,sans-serif',
14
+ name: 'Arial Narrow'
15
+ },
16
+ {
17
+ value: 'Century Gothic,CenturyGothic,AppleGothic,sans-serif',
18
+ name: 'Century Gothic'
19
+ },
20
+ {
21
+ value: 'Copperplate,Copperplate Gothic Light,fantasy',
22
+ name: 'Copperplate'
23
+ },
24
+ {
25
+ value: 'Courier,monospace',
26
+ name: 'Courier'
27
+ },
28
+ {
29
+ value: 'Georgia,Georgia,serif',
30
+ name: 'Georgia'
31
+ },
32
+ {
33
+ value: 'Gill Sans,Geneva,sans-serif',
34
+ name: 'Gill Sans'
35
+ },
36
+ {
37
+ value: 'Impact,Impact,Charcoal,sans-serif',
38
+ name: 'Impact'
39
+ },
40
+ {
41
+ value: 'Lucida Sans Typewriter,Lucida Console,Monaco,monospace',
42
+ name: 'Lucida Console'
43
+ },
44
+ {
45
+ value: 'Lucida Sans Unicode,Lucida Grande,sans-serif',
46
+ name: 'Lucida Sans'
47
+ },
48
+ {
49
+ value: 'Palatino Linotype,Palatino,Book Antiqua,serif',
50
+ name: 'Palatino Linotype'
51
+ },
52
+ {
53
+ value: 'Tahoma,Geneva,sans-serif',
54
+ name: 'Tahoma'
55
+ },
56
+ {
57
+ value: 'Times New Roman,Times,serif',
58
+ name: 'Times New Roman'
59
+ },
60
+ {
61
+ value: 'Trebuchet MS,Helvetica,sans-serif',
62
+ name: 'Trebuchet MS'
63
+ },
64
+ {
65
+ value: 'Verdana,Verdana,Geneva,sans-serif',
66
+ name: 'Verdana'
67
+ }
68
+ ]
69
+
70
+ RED.nodes.registerType('ui-text', {
71
+ category: RED._('@flowforge/node-red-dashboard/ui-base:ui-base.label.category'),
72
+ color: RED._('@flowforge/node-red-dashboard/ui-base:ui-base.colors.medium'),
73
+ defaults: {
74
+ group: { type: 'ui-group', required: true },
75
+ order: { value: 0 },
76
+ width: {
77
+ value: 0,
78
+ validate: function (v) {
79
+ const width = v || 0
80
+ const currentGroup = $('#node-input-group').val() || this.group
81
+ const groupNode = RED.nodes.node(currentGroup)
82
+ const valid = !groupNode || +width <= +groupNode.width
83
+ $('#node-input-size').toggleClass('input-error', !valid)
84
+ return valid
85
+ }
86
+ },
87
+ height: { value: 0 },
88
+ name: { value: '' },
89
+ label: { value: 'text' },
90
+ format: { value: '{{msg.payload}}' },
91
+ layout: { value: 'row-spread' },
92
+ style: { value: false },
93
+ font: { value: '' },
94
+ fontSize: { value: 16 },
95
+ color: { value: '#000' },
96
+ className: { value: '' }
97
+ },
98
+ inputs: 1,
99
+ outputs: 0,
100
+ align: 'right',
101
+ icon: 'font-awesome/fa-font',
102
+ paletteLabel: 'text',
103
+ label: function () { return this.name || (~this.label.indexOf('{' + '{') ? null : this.label) || 'text' },
104
+ labelStyle: function () { return this.name ? 'node_label_italic' : '' },
105
+ oneditprepare: function () {
106
+ $('#node-input-size').elementSizer({
107
+ width: '#node-input-width',
108
+ height: '#node-input-height',
109
+ group: '#node-input-group'
110
+ })
111
+
112
+ $('.nr-db-text-layout-' + (this.layout || 'row-spread')).addClass('selected');
113
+ ['.nr-db-text-layout-row-left', '.nr-db-text-layout-row-center', '.nr-db-text-layout-row-right', '.nr-db-text-layout-row-spread', '.nr-db-text-layout-col-center']
114
+ .forEach(function (id) {
115
+ $(id).click(function (e) {
116
+ $('.nr-db-text-layout').removeClass('selected')
117
+ $(this).addClass('selected')
118
+ $('#node-input-layout').val(id.substring('.nr-db-text-layout-'.length))
119
+ e.preventDefault()
120
+ })
121
+ })
122
+
123
+ const select = $('#node-select-font')
124
+
125
+ // add font options
126
+ fonts.forEach((font) => {
127
+ const name = font.name
128
+ const val = font.value
129
+ $('<option/>', {
130
+ value: val
131
+ }).text(name).appendTo(select)
132
+ })
133
+
134
+ // when a font is selected
135
+ $(select).change(() => {
136
+ const val = $('#node-select-font').val()
137
+ // update hidden input
138
+ $('#node-input-font').val(val)
139
+ // update test text
140
+ $('#node-test-text').css({
141
+ 'font-family': val
142
+ })
143
+ })
144
+ $(select).val(this.font)
145
+ $(select).change()
146
+
147
+ // make the fontsize a numeric spinner
148
+ $('#node-input-fontSize').spinner({
149
+ min: 1,
150
+ max: 100,
151
+ spin: () => {
152
+ // update the test text when value is changed
153
+ const val = $('#node-input-fontSize').val()
154
+ $('#node-test-text').css({
155
+ 'font-size': val + 'px'
156
+ })
157
+ }
158
+ })
159
+
160
+ // add change handler to color picker to update test text
161
+ $('#node-input-color').change(() => {
162
+ const val = $('#node-input-color').val()
163
+ $('#node-test-text').css({
164
+ color: val
165
+ })
166
+ })
167
+
168
+ // add change handler to show/hide style config options
169
+ $('#node-input-style').change(() => {
170
+ const val = $('#node-input-style').prop('checked')
171
+ if (val) {
172
+ $('#node-styles').show()
173
+ } else {
174
+ $('#node-styles').hide()
175
+ }
176
+ })
177
+ $('#node-input-style').change()
178
+
179
+ // when opening the config, make sure the test text is updated
180
+ if (this.fontSize) {
181
+ $('#node-test-text').css({
182
+ 'font-size': this.fontSize + 'px'
183
+ })
184
+ }
185
+ if (this.color) {
186
+ $('#node-test-text').css({
187
+ color: this.color
188
+ })
189
+ }
190
+
191
+ // use jQuery UI tooltip to convert the plain old title attribute to a nice tooltip
192
+ $('.ui-node-popover-title').tooltip({
193
+ show: {
194
+ effect: 'slideDown',
195
+ delay: 150
196
+ }
197
+ })
198
+ }
199
+ })
200
+ })()
201
+ </script>
202
+
203
+ <script type="text/html" data-template-name="ui-text">
204
+ <div class="form-row">
205
+ <label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
206
+ <input type="text" id="node-input-name">
207
+ </div>
208
+ <div class="form-row">
209
+ <label for="node-input-group"><i class="fa fa-table"></i> Group</label>
210
+ <input type="text" id="node-input-group">
211
+ </div>
212
+ <div class="form-row">
213
+ <label><i class="fa fa-object-group"></i> Size</label>
214
+ <input type="hidden" id="node-input-width">
215
+ <input type="hidden" id="node-input-height">
216
+ <button class="editor-button" id="node-input-size"></button>
217
+ </div>
218
+ <div class="form-row">
219
+ <label for="node-input-label"><i class="fa fa-i-cursor"></i> Label</label>
220
+ <input type="text" id="node-input-label">
221
+ </div>
222
+ <div class="form-row">
223
+ <label for="node-input-className"><i class="fa fa-code"></i> Class</label>
224
+ <div style="display: inline;">
225
+ <input style="width: 70%;" type="text" id="node-input-className" placeholder="Optional CSS class name(s)" style="flex-grow: 1;">
226
+ <a
227
+ data-html="true"
228
+ 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."
229
+ class="red-ui-button ui-node-popover-title"
230
+ 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;">
231
+ <i style="font-family: ui-serif;">fx</i>
232
+ </a>
233
+ </div>
234
+ </div>
235
+ <!--<div class="form-row">
236
+ <label for="node-input-format"><i class="fa fa-i-cursor"></i> Value format</label>
237
+ <input type="text" id="node-input-format" placeholder="{{msg.payload}}">
238
+ </div>-->
239
+ <div class="form-row">
240
+ <label style="vertical-align: top"><i class="fa fa-th-large"></i> Layout</label>
241
+ <div style="display:inline-block">
242
+ <input type="hidden" id="node-input-layout">
243
+ <input type="hidden" id="node-input-layoutAlign" >
244
+ <div>
245
+ <a href="#" class="nr-db-text-layout nr-db-text-layout-row nr-db-text-layout-row-left">
246
+ <span class="nr-db-text-layout-label">label</span>
247
+ <span class="nr-db-text-layout-value">value</span>
248
+ <div class="nr-db-text-layout-checkbox"></div>
249
+ </a>
250
+ <a href="#" class="nr-db-text-layout nr-db-text-layout-row nr-db-text-layout-row-center">
251
+ <span class="nr-db-text-layout-label">label</span>
252
+ <span class="nr-db-text-layout-value">value</span>
253
+ <div class="nr-db-text-layout-checkbox"></div>
254
+ </a>
255
+ <a href="#" class="nr-db-text-layout nr-db-text-layout-row nr-db-text-layout-row-right">
256
+ <span class="nr-db-text-layout-label">label</span>
257
+ <span class="nr-db-text-layout-value">value</span>
258
+ <div class="nr-db-text-layout-checkbox"></div>
259
+ </a>
260
+ </div>
261
+ <div>
262
+ <a href="#" class="nr-db-text-layout nr-db-text-layout-row nr-db-text-layout-row-spread">
263
+ <span class="nr-db-text-layout-label">label</span>
264
+ <span class="nr-db-text-layout-value">value</span>
265
+ <div class="nr-db-text-layout-checkbox"></div>
266
+ </a>
267
+ <a href="#" class="nr-db-text-layout nr-db-text-layout-col nr-db-text-layout-col-center">
268
+ <span class="nr-db-text-layout-label">label</span>
269
+ <span class="nr-db-text-layout-value">value</span>
270
+ <div class="nr-db-text-layout-checkbox"></div>
271
+ </a>
272
+ </div>
273
+ </div>
274
+ </div>
275
+
276
+ <div class="form-row">
277
+ <label><i class="fa fa-cog"></i> Style</label>
278
+ <input type="checkbox" id="node-input-style" style="display: inline-block; width: auto; vertical-align: top; margin: 0 3px 0 0;"/>
279
+ <label for="node-input-style" style="width: 70%;"> Apply Style</label>
280
+ </div>
281
+
282
+ <div id="node-styles">
283
+ <div class="form-row">
284
+ <label for="node-input-font"><i class="fa fa-font"></i> Font</label>
285
+ <select id="node-select-font">
286
+ </select>
287
+ <input type="hidden" id="node-input-font"/>
288
+ </div>
289
+ <div class="form-row">
290
+ <label for="node-input-fontSize"><i class="fa fa-text-height"></i> Text Size</label>
291
+ <input id="node-input-fontSize" value="16" style="width: 50px;"/>
292
+ </div>
293
+ <div class="form-row">
294
+ <label for="node-input-color"><i class="fa fa-tint"></i> Text Color</label>
295
+ <input type="color" id="node-input-color" style="width: 50px;"/>
296
+ </div>
297
+ <div class="form-row">
298
+ <label>&nbsp;</label>
299
+ <input id="node-test-text" value="Enter Sample Here"/ style="width: 280px;">
300
+ </div>
301
+ </div>
302
+ </script>
303
+
304
+ <style>
305
+ .nr-db-text-layout {
306
+ position:relative;
307
+ display: inline-block;
308
+ width: 90px;
309
+ height: 60px;
310
+ border-radius:3px;
311
+ border:1px solid var(--red-ui-form-input-border-color, #bbb);
312
+ cursor:pointer;
313
+ color: #666;
314
+ margin-right: 10px;
315
+ margin-bottom: 10px;
316
+ }
317
+ .nr-db-text-layout.selected, .nr-db-text-layout:hover {
318
+ border-color: var(--red-ui-form-input-border-selected-color, #333);
319
+ color: var(--red-ui-secondary-text-color-selected, #333);
320
+ }
321
+ .nr-db-text-layout span {
322
+ position: absolute;
323
+ }
324
+ .nr-db-text-layout-value {
325
+ font-weight: bold;
326
+ }
327
+ .nr-db-text-layout-row span { top: 20px; }
328
+ .nr-db-text-layout-row-left .nr-db-text-layout-label { left: 2px; }
329
+ .nr-db-text-layout-row-left .nr-db-text-layout-value { left: 34px; }
330
+ .nr-db-text-layout-row-spread .nr-db-text-layout-label { left: 2px; }
331
+ .nr-db-text-layout-row-spread .nr-db-text-layout-value { right: 2px; }
332
+ .nr-db-text-layout-row-center .nr-db-text-layout-label { left: 11px; }
333
+ .nr-db-text-layout-row-center .nr-db-text-layout-value { right: 11px; }
334
+ .nr-db-text-layout-row-right .nr-db-text-layout-label { right: 40px; }
335
+ .nr-db-text-layout-row-right .nr-db-text-layout-value { right: 2px; }
336
+
337
+ .nr-db-text-layout-col span { width: 90px; text-align: center; left: 0px;}
338
+ .nr-db-text-layout-col-center .nr-db-text-layout-label { top: 12px; }
339
+ .nr-db-text-layout-col-center .nr-db-text-layout-value { top: 26px; }
340
+ .nr-db-text-layout-checkbox {
341
+ display: none;
342
+ width: 10px;
343
+ height: 10px;
344
+ border-radius: 10px;
345
+ border: 1px solid var(--red-ui-primary-border-color, #bbb);
346
+ position: absolute;
347
+ right: -5px;
348
+ top: -5px;
349
+ background: var(--red-ui-secondary-background, #fff);
350
+ }
351
+ .nr-db-text-layout.selected .nr-db-text-layout-checkbox {
352
+ display:inline-block;
353
+ box-shadow: inset 0px 0px 0px 2px #fff;
354
+ background: #333;
355
+ border-color: #333;
356
+ }
357
+
358
+ </style>