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