@5minds/node-red-dashboard-2-processcube-dynamic-form 2.0.8 → 2.1.0-develop-9ef07a-mdiwhikf

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.
@@ -15,13 +15,23 @@
15
15
  :collapsed="collapsed" :toggleCollapse="toggleCollapse" />
16
16
  <Transition name="cardCollapse">
17
17
  <div v-if="!collapsed">
18
- <div className="ui-dynamic-form-formfield-positioner" :style="props.inner_card_styling">
18
+ <div className="ui-dynamic-form-formfield-positioner" :style="props.inner_card_styling"
19
+ :data-columns="props.form_columns || 1">
19
20
  <FormKit id="form" type="group">
20
21
  <v-row v-for="(field, index) in fields()" :key="field"
22
+ :class="field.type === 'header' ? 'ui-dynamic-form-header-row' : ''"
21
23
  :style="getRowWidthStyling(field, index)">
22
24
  <v-col cols="12">
23
25
  <component :is="createComponent(field).type"
24
- v-if="createComponent(field).innerText"
26
+ v-if="createComponent(field).innerHTML"
27
+ v-bind="createComponent(field).props"
28
+ :class="createComponent(field).class"
29
+ v-html="createComponent(field).innerHTML" :ref="(el) => {
30
+ if (index === 0) firstFormFieldRef = el;
31
+ }
32
+ " />
33
+ <component :is="createComponent(field).type"
34
+ v-else-if="createComponent(field).innerText"
25
35
  v-bind="createComponent(field).props" :ref="(el) => {
26
36
  if (index === 0) firstFormFieldRef = el;
27
37
  }
@@ -72,29 +82,60 @@
72
82
  </div>
73
83
  </template>
74
84
 
75
- <!-- eslint-disable no-case-declarations -->
76
85
  <script>
77
- import { de } from '@formkit/i18n'
78
- import { FormKit, defaultConfig, plugin } from '@formkit/vue'
79
- import { getCurrentInstance, markRaw, nextTick } from 'vue'
86
+ import { de } from '@formkit/i18n';
87
+ import { FormKit, defaultConfig, plugin } from '@formkit/vue';
88
+ import { getCurrentInstance, markRaw, nextTick } from 'vue';
89
+ import { marked } from 'marked';
90
+ import DOMPurify from 'dompurify';
80
91
 
81
- // eslint-disable-next-line import/no-unresolved
82
- import '@formkit/themes/genesis'
83
- import UIDynamicFormFooterAction from './FooterActions.vue'
84
- import UIDynamicFormTitleText from './TitleText.vue'
92
+ import '@formkit/themes/genesis';
93
+ import UIDynamicFormFooterAction from './FooterActions.vue';
94
+ import UIDynamicFormTitleText from './TitleText.vue';
85
95
 
86
- // eslint-disable-next-line no-unused-vars
87
96
  function requiredIf({ value }, [targetField, expectedValue], node) {
88
- console.debug(arguments)
97
+ console.debug(arguments);
89
98
 
90
- const actual = node?.root?.value?.[targetField]
91
- const isEmpty = value === '' || value === null || value === undefined
99
+ const actual = node?.root?.value?.[targetField];
100
+ const isEmpty = value === '' || value === null || value === undefined;
92
101
 
93
102
  if (actual === expectedValue && isEmpty) {
94
- return false // oder: `return "Dieses Feld ist erforderlich."`
103
+ return false;
95
104
  }
96
105
 
97
- return true
106
+ return true;
107
+ }
108
+
109
+ class MarkdownRenderer extends marked.Renderer {
110
+ link(params) {
111
+ const link = super.link(params);
112
+ return link.replace('<a', "<a target='_blank'");
113
+ }
114
+
115
+ html(params) {
116
+ const result = super.html(params);
117
+ if (result.startsWith('<a ') && !result.includes('target=')) {
118
+ return result.replace('<a ', `<a target="_blank" `);
119
+ }
120
+ return result;
121
+ }
122
+ }
123
+
124
+ class MarkedHooks extends marked.Hooks {
125
+ postprocess(html) {
126
+ return DOMPurify.sanitize(html, { ADD_ATTR: ['target'] });
127
+ }
128
+ }
129
+
130
+ function processMarkdown(content) {
131
+ if (!content) return '';
132
+
133
+ const html = marked.parse(content.toString(), {
134
+ renderer: new MarkdownRenderer(),
135
+ hooks: new MarkedHooks(),
136
+ });
137
+
138
+ return html;
98
139
  }
99
140
 
100
141
  export default {
@@ -102,7 +143,7 @@ export default {
102
143
  components: {
103
144
  FormKit,
104
145
  UIDynamicFormFooterAction,
105
- UIDynamicFormTitleText
146
+ UIDynamicFormTitleText,
106
147
  },
107
148
  inject: ['$socket'],
108
149
  props: {
@@ -111,24 +152,24 @@ export default {
111
152
  props: { type: Object, default: () => ({}) },
112
153
  state: {
113
154
  type: Object,
114
- default: () => ({ enabled: false, visible: false })
115
- }
155
+ default: () => ({ enabled: false, visible: false }),
156
+ },
116
157
  },
117
158
  setup(props) {
118
- console.info('UIDynamicForm setup with:', props)
119
- console.debug('Vue function loaded correctly', markRaw)
159
+ console.info('UIDynamicForm setup with:', props);
160
+ console.debug('Vue function loaded correctly', markRaw);
120
161
 
121
- const instance = getCurrentInstance()
122
- const app = instance.appContext.app
162
+ const instance = getCurrentInstance();
163
+ const app = instance.appContext.app;
123
164
 
124
165
  const formkitConfig = defaultConfig({
125
166
  theme: 'genesis',
126
167
  locales: { de },
127
168
  locale: 'de',
128
169
  // eslint-disable-next-line object-shorthand
129
- rules: { requiredIf: requiredIf }
130
- })
131
- app.use(plugin, formkitConfig)
170
+ rules: { requiredIf: requiredIf },
171
+ });
172
+ app.use(plugin, formkitConfig);
132
173
  },
133
174
  data() {
134
175
  return {
@@ -140,120 +181,121 @@ export default {
140
181
  formIsFinished: false,
141
182
  msg: null,
142
183
  collapsed: false,
143
- firstFormFieldRef: null
144
- }
184
+ firstFormFieldRef: null,
185
+ };
145
186
  },
146
187
  computed: {
147
188
  dynamicClass() {
148
- return `ui-dynamic-form-${this.theme} ui-dynamic-form-common`
189
+ return `ui-dynamic-form-${this.theme} ui-dynamic-form-common`;
149
190
  },
150
191
  dynamicFooterClass() {
151
- return `ui-dynamic-form-footer-${this.theme} ui-dynamic-form-footer-common`
192
+ return `ui-dynamic-form-footer-${this.theme} ui-dynamic-form-footer-common`;
152
193
  },
153
194
  hasUserTask() {
154
- return !!this.userTask
195
+ return !!this.userTask;
155
196
  },
156
197
  totalOutputs() {
157
198
  return (
158
199
  this.props.options.length +
159
200
  (this.props.handle_confirmation_dialogs ? 2 : 0) +
160
201
  (this.props.trigger_on_change ? 1 : 0)
161
- )
202
+ );
162
203
  },
163
204
  isConfirmDialog() {
164
- return this.userTask.userTaskConfig.formFields.some((field) => field.type === 'confirm')
205
+ return this.userTask.userTaskConfig.formFields.some((field) => field.type === 'confirm');
165
206
  },
166
207
  effectiveTitle() {
167
208
  if (this.props.title_text_type === 'str') {
168
- return this.props.title_text
209
+ return this.props.title_text;
169
210
  } else if (this.props.title_text_type === 'msg') {
170
- return this.msg.dynamicTitle
211
+ return this.msg.dynamicTitle;
171
212
  } else {
172
- return ''
213
+ return '';
173
214
  }
174
- }
215
+ },
175
216
  },
176
217
  watch: {
177
218
  formData: {
178
219
  handler(newData, oldData) {
179
220
  if (this.props.trigger_on_change) {
180
- const res = { payload: { formData: newData, userTask: this.userTask } }
181
- this.send(res, this.totalOutputs - 1)
221
+ const res = { payload: { formData: newData, userTask: this.userTask } };
222
+ this.send(res, this.totalOutputs - 1);
182
223
  }
183
224
  },
184
225
  collapsed(newVal) {
185
226
  if (!newVal && this.hasUserTask) {
186
227
  nextTick(() => {
187
- this.focusFirstFormField()
188
- })
228
+ this.focusFirstFormField();
229
+ });
189
230
  }
190
231
  },
191
232
  userTask(newVal) {
192
233
  if (newVal && !this.collapsed) {
193
234
  nextTick(() => {
194
- this.focusFirstFormField()
195
- })
235
+ this.focusFirstFormField();
236
+ });
196
237
  }
197
238
  },
198
- deep: true
199
- }
239
+ deep: true,
240
+ },
200
241
  },
201
242
  created() {
202
- const currentPath = window.location.pathname
203
- const lastPart = currentPath.substring(currentPath.lastIndexOf('/'))
243
+ const currentPath = window.location.pathname;
244
+ const lastPart = currentPath.substring(currentPath.lastIndexOf('/'));
204
245
 
205
- const store = this.$store.state
246
+ const store = this.$store.state;
206
247
 
207
248
  for (const key in store.ui.pages) {
208
249
  if (store.ui.pages[key].path === lastPart) {
209
- const theme = store.ui.pages[key].theme
250
+ const theme = store.ui.pages[key].theme;
210
251
  if (store.ui.themes[theme].name === 'ProcessCube Lightmode') {
211
- this.theme = 'light'
252
+ this.theme = 'light';
212
253
  } else if (store.ui.themes[theme].name === 'ProcessCube Darkmode') {
213
- this.theme = 'dark'
254
+ this.theme = 'dark';
214
255
  } else {
215
- this.theme = 'default'
256
+ this.theme = 'default';
216
257
  }
217
- break
258
+ break;
218
259
  }
219
260
  }
220
261
  },
221
262
  mounted() {
222
- const elements = document.querySelectorAll('.formkit-input')
263
+ const elements = document.querySelectorAll('.formkit-input');
223
264
 
224
265
  elements.forEach((element) => {
225
- element.classList.add('test')
226
- })
266
+ element.classList.add('test');
267
+ });
227
268
 
228
269
  this.$socket.on('widget-load:' + this.id, (msg) => {
229
- this.init(msg)
230
- })
270
+ this.init(msg);
271
+ });
231
272
  this.$socket.on('msg-input:' + this.id, (msg) => {
232
273
  // store the latest message in our client-side vuex store when we receive a new message
233
- this.init(msg)
234
- })
274
+ this.init(msg);
275
+ });
235
276
  // tell Node-RED that we're loading a new instance of this widget
236
- this.$socket.emit('widget-load', this.id)
277
+ this.$socket.emit('widget-load', this.id);
237
278
  },
238
279
  unmounted() {
239
280
  /* Make sure, any events you subscribe to on SocketIO are unsubscribed to here */
240
- this.$socket?.off('widget-load' + this.id)
241
- this.$socket?.off('msg-input:' + this.id)
281
+ this.$socket?.off('widget-load' + this.id);
282
+ this.$socket?.off('msg-input:' + this.id);
242
283
  },
243
284
  methods: {
244
285
  createComponent(field) {
245
- const customForm = field.customForm ? JSON.parse(field.customForm) : {}
246
- const hint = customForm.hint
247
- const placeholder = customForm.placeholder
248
- const validation = customForm.validation
249
- const name = field.id
250
- const customProperties = customForm.customProperties ?? []
286
+ console.debug('Creating component for field:', field);
287
+ const customForm = field.customForm ? JSON.parse(field.customForm) : {};
288
+ const hint = customForm.hint;
289
+ const placeholder = customForm.placeholder;
290
+ const validation = customForm.validation;
291
+ const name = field.id;
292
+ const customProperties = customForm.customProperties ?? [];
251
293
  const isReadOnly =
252
294
  this.props.readonly ||
253
295
  this.formIsFinished ||
254
296
  customProperties.find((entry) => ['readOnly', 'readonly'].includes(entry.name) && entry.value === 'true')
255
297
  ? 'true'
256
- : undefined
298
+ : undefined;
257
299
  switch (field.type) {
258
300
  case 'long':
259
301
  return {
@@ -274,11 +316,11 @@ export default {
274
316
  inputClass: `input-${this.theme}`,
275
317
  innerClass: `ui-dynamic-form-input-outlines ${this.theme === 'dark' ? '$remove:formkit-inner' : ''}`,
276
318
  readonly: isReadOnly,
277
- validationVisibility: 'live'
278
- }
279
- }
319
+ validationVisibility: 'live',
320
+ },
321
+ };
280
322
  case 'number':
281
- const step = field.customForm ? JSON.parse(field.customForm).step : undefined
323
+ const step = field.customForm ? JSON.parse(field.customForm).step : undefined;
282
324
  return {
283
325
  type: 'FormKit',
284
326
  props: {
@@ -297,9 +339,9 @@ export default {
297
339
  inputClass: `input-${this.theme}`,
298
340
  innerClass: `ui-dynamic-form-input-outlines ${this.theme === 'dark' ? '$remove:formkit-inner' : ''}`,
299
341
  readonly: isReadOnly,
300
- validationVisibility: 'live'
301
- }
302
- }
342
+ validationVisibility: 'live',
343
+ },
344
+ };
303
345
  case 'date':
304
346
  return {
305
347
  type: 'FormKit',
@@ -317,13 +359,13 @@ export default {
317
359
  innerClass: `ui-dynamic-form-input-outlines ${this.theme === 'dark' ? '$remove:formkit-inner' : ''}`,
318
360
  readonly: isReadOnly,
319
361
  validation,
320
- validationVisibility: 'live'
321
- }
322
- }
362
+ validationVisibility: 'live',
363
+ },
364
+ };
323
365
  case 'enum':
324
366
  const enums = field.enumValues.map((obj) => {
325
- return { value: obj.id, label: obj.name }
326
- })
367
+ return { value: obj.id, label: obj.name };
368
+ });
327
369
  return {
328
370
  type: 'FormKit',
329
371
  props: {
@@ -342,13 +384,13 @@ export default {
342
384
  readonly: isReadOnly,
343
385
  disabled: isReadOnly,
344
386
  validation,
345
- validationVisibility: 'live'
346
- }
347
- }
387
+ validationVisibility: 'live',
388
+ },
389
+ };
348
390
  case 'select':
349
391
  const selections = JSON.parse(field.customForm).entries.map((obj) => {
350
- return { value: obj.key, label: obj.value }
351
- })
392
+ return { value: obj.key, label: obj.value };
393
+ });
352
394
  return {
353
395
  type: 'FormKit',
354
396
  props: {
@@ -368,9 +410,9 @@ export default {
368
410
  readonly: isReadOnly,
369
411
  disabled: isReadOnly,
370
412
  validation,
371
- validationVisibility: 'live'
372
- }
373
- }
413
+ validationVisibility: 'live',
414
+ },
415
+ };
374
416
  case 'string':
375
417
  return {
376
418
  type: 'FormKit',
@@ -389,14 +431,14 @@ export default {
389
431
  innerClass: `ui-dynamic-form-input-outlines ${this.theme === 'dark' ? '$remove:formkit-inner' : ''}`,
390
432
  readonly: isReadOnly,
391
433
  validation,
392
- validationVisibility: 'live'
393
- }
394
- }
434
+ validationVisibility: 'live',
435
+ },
436
+ };
395
437
  case 'confirm':
396
438
  return {
397
439
  type: 'h3',
398
- innerText: field.label
399
- }
440
+ innerText: field.label,
441
+ };
400
442
  case 'boolean':
401
443
  return {
402
444
  type: 'FormKit',
@@ -414,11 +456,11 @@ export default {
414
456
  readonly: isReadOnly,
415
457
  disabled: isReadOnly,
416
458
  validation,
417
- validationVisibility: 'live'
418
- }
419
- }
459
+ validationVisibility: 'live',
460
+ },
461
+ };
420
462
  case 'file':
421
- const multiple = field.customForm ? JSON.parse(field.customForm).multiple === 'true' : false
463
+ const multiple = field.customForm ? JSON.parse(field.customForm).multiple === 'true' : false;
422
464
  return {
423
465
  type: 'FormKit',
424
466
  props: {
@@ -438,13 +480,13 @@ export default {
438
480
  disabled: isReadOnly,
439
481
  multiple,
440
482
  validation,
441
- validationVisibility: 'live'
442
- }
443
- }
483
+ validationVisibility: 'live',
484
+ },
485
+ };
444
486
  case 'checkbox':
445
487
  const options = JSON.parse(field.customForm).entries.map((obj) => {
446
- return { value: obj.key, label: obj.value }
447
- })
488
+ return { value: obj.key, label: obj.value };
489
+ });
448
490
  return {
449
491
  type: 'FormKit',
450
492
  props: {
@@ -463,9 +505,9 @@ export default {
463
505
  readonly: isReadOnly,
464
506
  disabled: isReadOnly,
465
507
  validation,
466
- validationVisibility: 'live'
467
- }
468
- }
508
+ validationVisibility: 'live',
509
+ },
510
+ };
469
511
  case 'color':
470
512
  return {
471
513
  type: 'FormKit',
@@ -480,9 +522,9 @@ export default {
480
522
  readonly: isReadOnly,
481
523
  disabled: isReadOnly,
482
524
  validation,
483
- validationVisibility: 'live'
484
- }
485
- }
525
+ validationVisibility: 'live',
526
+ },
527
+ };
486
528
  case 'datetime-local':
487
529
  return {
488
530
  type: 'FormKit',
@@ -500,9 +542,9 @@ export default {
500
542
  innerClass: `ui-dynamic-form-input-outlines ${this.theme === 'dark' ? '$remove:formkit-inner' : ''}`,
501
543
  readonly: isReadOnly,
502
544
  validation,
503
- validationVisibility: 'live'
504
- }
505
- }
545
+ validationVisibility: 'live',
546
+ },
547
+ };
506
548
  case 'email':
507
549
  return {
508
550
  type: 'FormKit',
@@ -521,29 +563,29 @@ export default {
521
563
  innerClass: `ui-dynamic-form-input-outlines ${this.theme === 'dark' ? '$remove:formkit-inner' : ''}`,
522
564
  readonly: isReadOnly,
523
565
  validation,
524
- validationVisibility: 'live'
525
- }
526
- }
566
+ validationVisibility: 'live',
567
+ },
568
+ };
527
569
  case 'header':
528
- let typeToUse = 'h1'
570
+ let typeToUse = 'h1';
529
571
  if (field.customForm && JSON.parse(field.customForm).style === 'heading_2') {
530
- typeToUse = 'h2'
572
+ typeToUse = 'h2';
531
573
  }
532
574
  if (field.customForm && JSON.parse(field.customForm).style === 'heading_3') {
533
- typeToUse = 'h3'
575
+ typeToUse = 'h3';
534
576
  }
535
577
  return {
536
578
  type: typeToUse,
537
- innerText: this.formData[field.id]
538
- }
579
+ innerText: this.formData[field.id],
580
+ };
539
581
  case 'hidden':
540
582
  return {
541
583
  type: 'input',
542
584
  props: {
543
585
  type: 'hidden',
544
- value: this.formData[field.id]
545
- }
546
- }
586
+ value: this.formData[field.id],
587
+ },
588
+ };
547
589
  case 'month':
548
590
  return {
549
591
  type: 'FormKit',
@@ -561,14 +603,17 @@ export default {
561
603
  innerClass: `ui-dynamic-form-input-outlines ${this.theme === 'dark' ? '$remove:formkit-inner' : ''}`,
562
604
  readonly: isReadOnly,
563
605
  validation,
564
- validationVisibility: 'live'
565
- }
566
- }
606
+ validationVisibility: 'live',
607
+ },
608
+ };
567
609
  case 'paragraph':
610
+ const paragraphContent = this.formData[field.id] || field.defaultValue || field.label || '';
611
+ const processedHtml = processMarkdown(paragraphContent);
568
612
  return {
569
- type: 'p',
570
- innerText: this.formData[field.id]
571
- }
613
+ type: 'div',
614
+ innerHTML: processedHtml,
615
+ class: 'ui-dynamic-form-paragraph',
616
+ };
572
617
  case 'password':
573
618
  return {
574
619
  type: 'FormKit',
@@ -587,13 +632,13 @@ export default {
587
632
  innerClass: `ui-dynamic-form-input-outlines ${this.theme === 'dark' ? '$remove:formkit-inner' : ''}`,
588
633
  readonly: isReadOnly,
589
634
  validation,
590
- validationVisibility: 'live'
591
- }
592
- }
635
+ validationVisibility: 'live',
636
+ },
637
+ };
593
638
  case 'radio':
594
639
  const radioOptions = JSON.parse(field.customForm).entries.map((obj) => {
595
- return { value: obj.key, label: obj.value }
596
- })
640
+ return { value: obj.key, label: obj.value };
641
+ });
597
642
  return {
598
643
  type: 'FormKit',
599
644
  props: {
@@ -612,11 +657,11 @@ export default {
612
657
  readonly: isReadOnly,
613
658
  disabled: isReadOnly,
614
659
  validation,
615
- validationVisibility: 'live'
616
- }
617
- }
660
+ validationVisibility: 'live',
661
+ },
662
+ };
618
663
  case 'range':
619
- const customForm = JSON.parse(field.customForm)
664
+ const customForm = JSON.parse(field.customForm);
620
665
  return {
621
666
  type: 'v-slider',
622
667
  props: {
@@ -637,9 +682,9 @@ export default {
637
682
  readonly: isReadOnly,
638
683
  disabled: isReadOnly,
639
684
  validation,
640
- validationVisibility: 'live'
641
- }
642
- }
685
+ validationVisibility: 'live',
686
+ },
687
+ };
643
688
  case 'tel':
644
689
  return {
645
690
  type: 'FormKit',
@@ -658,11 +703,11 @@ export default {
658
703
  innerClass: `ui-dynamic-form-input-outlines ${this.theme === 'dark' ? '$remove:formkit-inner' : ''}`,
659
704
  readonly: isReadOnly,
660
705
  validation,
661
- validationVisibility: 'live'
662
- }
663
- }
706
+ validationVisibility: 'live',
707
+ },
708
+ };
664
709
  case 'textarea':
665
- const rows = field.customForm ? JSON.parse(field.customForm).rows : undefined
710
+ const rows = field.customForm ? JSON.parse(field.customForm).rows : undefined;
666
711
  return {
667
712
  type: 'FormKit',
668
713
  props: {
@@ -681,9 +726,9 @@ export default {
681
726
  innerClass: `ui-dynamic-form-input-outlines ${this.theme === 'dark' ? '$remove:formkit-inner' : ''}`,
682
727
  readonly: isReadOnly,
683
728
  validation,
684
- validationVisibility: 'live'
685
- }
686
- }
729
+ validationVisibility: 'live',
730
+ },
731
+ };
687
732
  case 'time':
688
733
  return {
689
734
  type: 'FormKit',
@@ -702,9 +747,9 @@ export default {
702
747
  innerClass: `ui-dynamic-form-input-outlines ${this.theme === 'dark' ? '$remove:formkit-inner' : ''}`,
703
748
  readonly: isReadOnly,
704
749
  validation,
705
- validationVisibility: 'live'
706
- }
707
- }
750
+ validationVisibility: 'live',
751
+ },
752
+ };
708
753
  case 'url':
709
754
  return {
710
755
  type: 'FormKit',
@@ -723,9 +768,9 @@ export default {
723
768
  innerClass: `ui-dynamic-form-input-outlines ${this.theme === 'dark' ? '$remove:formkit-inner' : ''}`,
724
769
  readonly: isReadOnly,
725
770
  validation,
726
- validationVisibility: 'live'
727
- }
728
- }
771
+ validationVisibility: 'live',
772
+ },
773
+ };
729
774
  case 'week':
730
775
  return {
731
776
  type: 'FormKit',
@@ -744,9 +789,9 @@ export default {
744
789
  innerClass: `ui-dynamic-form-input-outlines ${this.theme === 'dark' ? '$remove:formkit-inner' : ''}`,
745
790
  readonly: isReadOnly,
746
791
  validation,
747
- validationVisibility: 'live'
748
- }
749
- }
792
+ validationVisibility: 'live',
793
+ },
794
+ };
750
795
  default:
751
796
  return {
752
797
  type: 'FormKit',
@@ -763,223 +808,223 @@ export default {
763
808
  innerClass: `ui-dynamic-form-input-outlines ${this.theme === 'dark' ? '$remove:formkit-inner' : ''}`,
764
809
  readonly: isReadOnly,
765
810
  validation,
766
- validationVisibility: 'live'
767
- }
768
- }
811
+ validationVisibility: 'live',
812
+ },
813
+ };
769
814
  }
770
815
  },
771
816
  toggleCollapse() {
772
- this.collapsed = !this.collapsed
817
+ this.collapsed = !this.collapsed;
773
818
  },
774
819
  getRowWidthStyling(field, index) {
775
- let style = ''
820
+ let style = '';
776
821
  if (index === 0) {
777
- style += 'margin-top: 12px;'
822
+ style += 'margin-top: 12px;';
778
823
  }
779
824
  if (field.type === 'header') {
780
- style += 'flex-basis: 100%;'
825
+ style += 'flex-basis: 100%;';
781
826
  } else {
782
- style += `flex-basis: ${(1 / this.props.form_columns) * 100}%;`
827
+ style += `flex-basis: 100%;`;
783
828
  }
784
- return style
829
+ return style;
785
830
  },
786
831
  fields() {
787
- const aFields = this.userTask.userTaskConfig?.formFields ?? []
832
+ const aFields = this.userTask.userTaskConfig?.formFields ?? [];
788
833
  const fieldMap = aFields.map((field) => ({
789
834
  ...field,
790
- items: mapItems(field.type, field)
791
- }))
835
+ items: mapItems(field.type, field),
836
+ }));
792
837
 
793
- return fieldMap
838
+ return fieldMap;
794
839
  },
795
840
  /*
796
- widget-action just sends a msg to Node-RED, it does not store the msg state server-side
797
- alternatively, you can use widget-change, which will also store the msg in the Node's datastore
798
- */
841
+ widget-action just sends a msg to Node-RED, it does not store the msg state server-side
842
+ alternatively, you can use widget-change, which will also store the msg in the Node's datastore
843
+ */
799
844
  send(msg, index) {
800
- const msgArr = []
801
- msgArr[index] = msg
802
- this.$socket.emit('widget-action', this.id, msgArr)
845
+ const msgArr = [];
846
+ msgArr[index] = msg;
847
+ this.$socket.emit('widget-action', this.id, msgArr);
803
848
  },
804
849
  init(msg) {
805
- this.msg = msg
850
+ this.msg = msg;
806
851
  if (!msg) {
807
- return
852
+ return;
808
853
  }
809
854
 
810
- this.actions = this.props.options
855
+ this.actions = this.props.options;
811
856
 
812
- const hasTask = msg.payload && msg.payload.userTask
857
+ const hasTask = msg.payload && msg.payload.userTask;
813
858
 
814
859
  if (hasTask) {
815
- this.userTask = msg.payload.userTask
860
+ this.userTask = msg.payload.userTask;
816
861
  } else {
817
- this.userTask = null
818
- this.formData = {}
819
- return
862
+ this.userTask = null;
863
+ this.formData = {};
864
+ return;
820
865
  }
821
866
 
822
- const formFields = this.userTask.userTaskConfig.formFields
823
- const formFieldIds = formFields.map((ff) => ff.id)
824
- const initialValues = this.userTask.startToken
825
- const finishedFormData = msg.payload.formData
826
- this.formIsFinished = !!msg.payload.formData
867
+ const formFields = this.userTask.userTaskConfig.formFields;
868
+ const formFieldIds = formFields.map((ff) => ff.id);
869
+ const initialValues = this.userTask.startToken;
870
+ const finishedFormData = msg.payload.formData;
871
+ this.formIsFinished = !!msg.payload.formData;
827
872
  if (this.formIsFinished) {
828
- this.collapsed = this.props.collapse_when_finished
873
+ this.collapsed = this.props.collapse_when_finished;
829
874
  }
830
875
 
831
876
  if (formFields) {
832
877
  formFields.forEach((field) => {
833
- this.formData[field.id] = field.defaultValue
878
+ this.formData[field.id] = field.defaultValue;
834
879
 
835
880
  if (field.type === 'confirm') {
836
- const customForm = field.customForm ? JSON.parse(field.customForm) : {}
837
- const confirmText = customForm.confirmButtonText ?? 'Confirm'
838
- const declineText = customForm.declineButtonText ?? 'Decline'
881
+ const customForm = field.customForm ? JSON.parse(field.customForm) : {};
882
+ const confirmText = customForm.confirmButtonText ?? 'Confirm';
883
+ const declineText = customForm.declineButtonText ?? 'Decline';
839
884
  this.actions = [
840
885
  {
841
886
  alignment: 'right',
842
887
  primary: 'false',
843
888
  label: declineText,
844
- condition: ''
889
+ condition: '',
845
890
  },
846
891
  {
847
892
  alignment: 'right',
848
893
  primary: 'true',
849
894
  label: confirmText,
850
- condition: ''
851
- }
852
- ]
895
+ condition: '',
896
+ },
897
+ ];
853
898
  }
854
- })
899
+ });
855
900
  }
856
901
 
857
902
  if (initialValues) {
858
903
  Object.keys(initialValues)
859
904
  .filter((key) => formFieldIds.includes(key))
860
905
  .forEach((key) => {
861
- this.formData[key] = initialValues[key]
862
- })
906
+ this.formData[key] = initialValues[key];
907
+ });
863
908
  }
864
909
 
865
910
  if (this.formIsFinished) {
866
911
  Object.keys(finishedFormData)
867
912
  .filter((key) => formFieldIds.includes(key))
868
913
  .forEach((key) => {
869
- this.formData[key] = finishedFormData[key]
870
- })
914
+ this.formData[key] = finishedFormData[key];
915
+ });
871
916
  }
872
917
 
873
918
  nextTick(() => {
874
- this.focusFirstFormField()
875
- })
919
+ this.focusFirstFormField();
920
+ });
876
921
  },
877
922
  actionFn(action) {
878
923
  if (action.label === 'Speichern' || action.label === 'Speichern und nächster') {
879
- const formkitInputs = this.$refs.form.$el.querySelectorAll('.formkit-outer')
880
- let allComplete = true
924
+ const formkitInputs = this.$refs.form.$el.querySelectorAll('.formkit-outer');
925
+ let allComplete = true;
881
926
 
882
927
  formkitInputs.forEach((input) => {
883
- const dataComplete = input.getAttribute('data-complete')
884
- const dataInvalid = input.getAttribute('data-invalid')
928
+ const dataComplete = input.getAttribute('data-complete');
929
+ const dataInvalid = input.getAttribute('data-invalid');
885
930
 
886
931
  if (dataComplete == null && dataInvalid === 'true') {
887
- allComplete = false
932
+ allComplete = false;
888
933
  }
889
- })
934
+ });
890
935
 
891
- if (!allComplete) return
936
+ if (!allComplete) return;
892
937
  }
893
938
 
894
939
  if (this.checkCondition(action.condition)) {
895
- this.showError('')
940
+ this.showError('');
896
941
 
897
- const processedFormData = { ...this.formData }
898
- const formFields = this.userTask.userTaskConfig.formFields
942
+ const processedFormData = { ...this.formData };
943
+ const formFields = this.userTask.userTaskConfig.formFields;
899
944
 
900
- formFields.forEach(field => {
901
- const fieldValue = processedFormData[field.id]
945
+ formFields.forEach((field) => {
946
+ const fieldValue = processedFormData[field.id];
902
947
 
903
948
  if (field.type === 'number' || field.type === 'long') {
904
949
  if (fieldValue !== null && fieldValue !== undefined && fieldValue !== '') {
905
950
  if (field.type === 'long') {
906
- const intValue = Number.parseInt(fieldValue, 10)
951
+ const intValue = Number.parseInt(fieldValue, 10);
907
952
  if (!isNaN(intValue)) {
908
- processedFormData[field.id] = intValue
953
+ processedFormData[field.id] = intValue;
909
954
  }
910
955
  } else {
911
- const numValue = Number.parseFloat(fieldValue)
956
+ const numValue = Number.parseFloat(fieldValue);
912
957
  if (!isNaN(numValue)) {
913
- processedFormData[field.id] = numValue
958
+ processedFormData[field.id] = numValue;
914
959
  }
915
960
  }
916
961
  }
917
962
  }
918
- })
963
+ });
919
964
 
920
- const msg = this.msg ?? {}
921
- msg.payload = { formData: processedFormData, userTask: this.userTask }
965
+ const msg = this.msg ?? {};
966
+ msg.payload = { formData: processedFormData, userTask: this.userTask };
922
967
  this.send(
923
968
  msg,
924
969
  this.actions.findIndex((element) => element.label === action.label) +
925
970
  (this.isConfirmDialog ? this.props.options.length : 0)
926
- )
971
+ );
927
972
  // TODO: mm - end
928
973
  } else {
929
- this.showError(action.errorMessage)
974
+ this.showError(action.errorMessage);
930
975
  }
931
976
  },
932
977
  checkCondition(condition) {
933
- if (condition === '') return true
978
+ if (condition === '') return true;
934
979
  try {
935
980
  // eslint-disable-next-line no-new-func
936
- const func = Function('fields', 'userTask', 'msg', '"use strict"; return (' + condition + ')')
937
- const result = func(this.formData, this.userTask, this.msg)
938
- return Boolean(result)
981
+ const func = Function('fields', 'userTask', 'msg', '"use strict"; return (' + condition + ')');
982
+ const result = func(this.formData, this.userTask, this.msg);
983
+ return Boolean(result);
939
984
  } catch (err) {
940
- console.error('Error while evaluating condition: ' + err)
941
- return false
985
+ console.error('Error while evaluating condition: ' + err);
986
+ return false;
942
987
  }
943
988
  },
944
989
  showError(errMsg) {
945
- this.errorMsg = errMsg
990
+ this.errorMsg = errMsg;
946
991
  },
947
992
  focusFirstFormField() {
948
993
  if (this.collapsed || !this.hasUserTask) {
949
- return
994
+ return;
950
995
  }
951
996
 
952
997
  if (this.firstFormFieldRef) {
953
- let inputElement = null
998
+ let inputElement = null;
954
999
 
955
1000
  if (this.firstFormFieldRef.node && this.firstFormFieldRef.node.input instanceof HTMLElement) {
956
- inputElement = this.firstFormFieldRef.node.input
1001
+ inputElement = this.firstFormFieldRef.node.input;
957
1002
  } else if (this.firstFormFieldRef.$el instanceof HTMLElement) {
958
1003
  if (['INPUT', 'TEXTAREA', 'SELECT'].includes(this.firstFormFieldRef.$el.tagName)) {
959
- inputElement = this.firstFormFieldRef.$el
1004
+ inputElement = this.firstFormFieldRef.$el;
960
1005
  } else {
961
- inputElement = this.firstFormFieldRef.$el.querySelector('input:not([type="hidden"]), textarea, select')
1006
+ inputElement = this.firstFormFieldRef.$el.querySelector('input:not([type="hidden"]), textarea, select');
962
1007
  }
963
1008
  }
964
1009
 
965
1010
  if (inputElement) {
966
- inputElement.focus()
1011
+ inputElement.focus();
967
1012
  } else {
968
- console.warn('Could not find a focusable input element for the first form field.')
1013
+ console.warn('Could not find a focusable input element for the first form field.');
969
1014
  }
970
1015
  }
971
- }
972
- }
973
- }
1016
+ },
1017
+ },
1018
+ };
974
1019
 
975
1020
  function mapItems(type, field) {
976
1021
  if (type === 'enum') {
977
1022
  return field.enumValues.map((enumValue) => ({
978
1023
  title: enumValue.name,
979
- value: enumValue.id
980
- }))
1024
+ value: enumValue.id,
1025
+ }));
981
1026
  } else {
982
- return null
1027
+ return null;
983
1028
  }
984
1029
  }
985
1030
  </script>