@worksafevictoria/wcl7.5 1.17.0-beta.10 → 1.17.0-beta.12
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.
- package/package.json +1 -1
- package/src/components/Containers/SectionGroup/index.vue +0 -1
- package/src/components/Paragraphs/RTWPlanner/Injuries/index.vue +7 -1
- package/src/components/Paragraphs/RTWPlanner/Planners/PlannerNameModal.vue +56 -0
- package/src/components/SubComponents/FormInstance/models/base-form-element.js +4 -3
- package/src/components/SubComponents/FormInstance/services/form-render-parser.js +51 -16
- package/src/components/SubComponents/FormInstance/services/logic-parser.js +81 -9
- package/src/components/SubComponents/FormInstance/services/registry-factory.js +52 -50
- package/src/components/SubComponents/FormInstance/stories/mocks/checkboxesother.json +1 -10
- package/src/components/SubComponents/FormInstance/stories/mocks/emailconfirm.json +1 -10
- package/src/components/SubComponents/FormInstance/stories/mocks/jahd.json +1 -5
- package/src/components/SubComponents/FormInstance/stories/mocks/quad.json +1 -5
- package/src/components/SubComponents/FormInstance/stories/mocks/radiosother.json +1 -9
- package/src/components/SubComponents/FormInstance/stories/mocks/sameas.json +1 -5
- package/src/components/SubComponents/FormInstance/stories/mocks/selectother.json +1 -10
- package/src/components/SubComponents/FormInstance/stories/mocks/styles.json +1 -5
- package/src/components/SubComponents/FormInstance/stories/mocks/table-select.json +1 -15
- package/src/components/SubComponents/FormInstance/stories/mocks/token.json +1 -5
- package/src/components/SubComponents/FormInstance/stories/mocks/twig.json +1 -13
- package/src/components/SubComponents/FormInstance/stories/mocks/wizard.json +1 -13
- package/src/components/SubComponents/FormInstance/tests/form-test-utils.js +3 -0
- package/src/components/SubComponents/FormInstance/tests/form.test.js +2 -1
- package/src/components/SubComponents/FormInstance/tests/radiosother.test.js +12 -11
- package/src/components/SubComponents/FormInstance/tests/rule-disabled.test.js +13 -45
- package/src/components/SubComponents/FormInstance/tests/rule-enabled-value.test.js +8 -24
- package/src/components/SubComponents/FormInstance/tests/rule-hidden.test.js +13 -45
- package/src/components/SubComponents/FormInstance/tests/rule-required-value.test.js +15 -55
- package/src/components/SubComponents/FormInstance/tests/rule-visible.test.js +0 -413
- package/src/components/SubComponents/FormInstance/tests/sameas.test.js +9 -25
- package/src/components/SubComponents/FormInstance/tests/twig.test.js +7 -5
- package/src/index.js +6 -0
package/package.json
CHANGED
|
@@ -8,6 +8,7 @@ import CardGroup from './../../../SubComponents/CardGroup/index.vue'
|
|
|
8
8
|
import Breadcrumb from './../../../SubComponents/Breadcrumb/index.vue'
|
|
9
9
|
import RichText from './../../RichText/index.vue'
|
|
10
10
|
import SelectableCards from './../../SelectableCards/index.vue'
|
|
11
|
+
import PlannerNameModal from './../Planners/PlannerNameModal.vue'
|
|
11
12
|
|
|
12
13
|
const props = defineProps({
|
|
13
14
|
injuryPage: {
|
|
@@ -46,6 +47,7 @@ const props = defineProps({
|
|
|
46
47
|
|
|
47
48
|
const screen = ref(1)
|
|
48
49
|
const selectedCard = ref(null)
|
|
50
|
+
const showModal = ref(false)
|
|
49
51
|
|
|
50
52
|
// local copy of breadcrumb items allowed to mutate
|
|
51
53
|
const breadcrumbItemsLocal = ref([...props.breadcrumbItems])
|
|
@@ -87,7 +89,9 @@ function onCrumbClick({ index }) {
|
|
|
87
89
|
// you can add logic for index === 1 here, or just leave it as no-op.
|
|
88
90
|
}
|
|
89
91
|
|
|
90
|
-
function nextScreenAgent() {
|
|
92
|
+
function nextScreenAgent(card) {
|
|
93
|
+
showModal.value = true
|
|
94
|
+
}
|
|
91
95
|
</script>
|
|
92
96
|
|
|
93
97
|
<template>
|
|
@@ -172,6 +176,8 @@ function nextScreenAgent() {}
|
|
|
172
176
|
@nextScreen="nextScreenAgent"
|
|
173
177
|
/>
|
|
174
178
|
</div>
|
|
179
|
+
|
|
180
|
+
<PlannerNameModal class="injuries-app__new-planner" v-model="showModal" />
|
|
175
181
|
</div>
|
|
176
182
|
</template>
|
|
177
183
|
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
import { computed, ref } from 'vue'
|
|
3
|
+
import { BModal, BFormInput } from 'bootstrap-vue-next'
|
|
4
|
+
import CtaButton from './../../../SubComponents/CtaButton/index.vue'
|
|
5
|
+
|
|
6
|
+
const inputValue = ref('')
|
|
7
|
+
|
|
8
|
+
function handleSubmit() {
|
|
9
|
+
console.log('handle Submit', inputValue.value)
|
|
10
|
+
if (!inputValue.value.trim()) return
|
|
11
|
+
}
|
|
12
|
+
</script>
|
|
13
|
+
|
|
14
|
+
<template>
|
|
15
|
+
<b-modal
|
|
16
|
+
aria-labelledby="injuries-app__modal"
|
|
17
|
+
no-close-on-backdrop
|
|
18
|
+
centered
|
|
19
|
+
no-footer
|
|
20
|
+
size="lg"
|
|
21
|
+
>
|
|
22
|
+
<template #default="{ close }">
|
|
23
|
+
<div class="p-3">
|
|
24
|
+
<h3 class="fw-bold mb-3 modal-title__new-planner">Name your planner</h3>
|
|
25
|
+
<p class="mb-2 modal-description__new-planner">
|
|
26
|
+
Give your planner a name so you can easily find it and pick up where
|
|
27
|
+
you left off.
|
|
28
|
+
</p>
|
|
29
|
+
|
|
30
|
+
<label for="modal2CB" class="fw-bold mb-4">
|
|
31
|
+
Injured workers first name
|
|
32
|
+
</label>
|
|
33
|
+
|
|
34
|
+
<BFormInput
|
|
35
|
+
id="modal2CB"
|
|
36
|
+
name="modal2CB"
|
|
37
|
+
placeholder=""
|
|
38
|
+
v-model="inputValue"
|
|
39
|
+
class="mb-4 input__new-planner"
|
|
40
|
+
/>
|
|
41
|
+
|
|
42
|
+
<CtaButton ref="calNextBtn" @click="handleSubmit">Next</CtaButton>
|
|
43
|
+
</div>
|
|
44
|
+
</template>
|
|
45
|
+
</b-modal>
|
|
46
|
+
</template>
|
|
47
|
+
|
|
48
|
+
<style lang="scss" scoped>
|
|
49
|
+
:deep(.modal-description__new-planner) {
|
|
50
|
+
width: 65%;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
:deep(.input__new-planner) {
|
|
54
|
+
width: 60%;
|
|
55
|
+
}
|
|
56
|
+
</style>
|
|
@@ -54,7 +54,7 @@ export class BaseFormElement {
|
|
|
54
54
|
getLabelPosition() {
|
|
55
55
|
return this.getPosition(
|
|
56
56
|
this.webformElement['#_title_display'] ??
|
|
57
|
-
this.webformElement['#title_display']
|
|
57
|
+
this.webformElement['#title_display'],
|
|
58
58
|
)
|
|
59
59
|
}
|
|
60
60
|
|
|
@@ -160,7 +160,7 @@ export class BaseFormElement {
|
|
|
160
160
|
label: getStyle(this.webformElement['#label_attributes']),
|
|
161
161
|
wrapper: getStyle(this.webformElement['#wrapper_attributes']),
|
|
162
162
|
element: getStyle(this.webformElement['#attributes']),
|
|
163
|
-
additional: this.getAdditionalStyles(this.getCustomClass())
|
|
163
|
+
additional: this.getAdditionalStyles(this.getCustomClass()),
|
|
164
164
|
}
|
|
165
165
|
const hasOverride = Object.values(style).some((attr) => !this.isEmpty(attr))
|
|
166
166
|
return hasOverride ? style : undefined
|
|
@@ -251,7 +251,8 @@ export class BaseFormElement {
|
|
|
251
251
|
if (this.isEmpty(this.webformElement['#states'])) {
|
|
252
252
|
return undefined
|
|
253
253
|
} else {
|
|
254
|
-
|
|
254
|
+
// NEW: Pass the current instance (`this`) to the parser.
|
|
255
|
+
return parseElementStates(this.webformElement, this)
|
|
255
256
|
}
|
|
256
257
|
}
|
|
257
258
|
|
|
@@ -3,6 +3,39 @@ import { converFormIOElementToJSON } from './convert-form-element'
|
|
|
3
3
|
import { updateConditionWithFormReferences } from './logic-linker'
|
|
4
4
|
import { RegisterFactory } from './registry-factory'
|
|
5
5
|
|
|
6
|
+
function extractWebformKeys(webformObject) {
|
|
7
|
+
const result = []
|
|
8
|
+
|
|
9
|
+
const isElement = (obj) => obj && typeof obj === 'object' && obj['#type']
|
|
10
|
+
|
|
11
|
+
const extract = (obj) => {
|
|
12
|
+
if (!obj || typeof obj !== 'object') return null
|
|
13
|
+
|
|
14
|
+
const type = obj['#type']
|
|
15
|
+
|
|
16
|
+
const key = obj['#webform_key'] || null
|
|
17
|
+
const node = key ? { key, children: [], type } : null
|
|
18
|
+
|
|
19
|
+
for (const [childKey, val] of Object.entries(obj)) {
|
|
20
|
+
if (childKey.startsWith('#')) continue
|
|
21
|
+
if (isElement(val)) {
|
|
22
|
+
const childNode = extract(val)
|
|
23
|
+
if (childNode && node) node.children.push(childNode)
|
|
24
|
+
else if (childNode) return childNode
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
return node
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
for (const [topKey, val] of Object.entries(webformObject)) {
|
|
32
|
+
if (typeof val === 'object' && val['#type']) {
|
|
33
|
+
const topNode = extract(val)
|
|
34
|
+
if (topNode) result.push(topNode)
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
return result
|
|
38
|
+
}
|
|
6
39
|
export class FormRenderParser {
|
|
7
40
|
initialise(contentApiUrl, isPreview) {
|
|
8
41
|
this.formSettingsMeta = { contentApiUrl }
|
|
@@ -17,14 +50,16 @@ export class FormRenderParser {
|
|
|
17
50
|
const formlogicList = []
|
|
18
51
|
try {
|
|
19
52
|
webform = this.preProcessWebForm(webform)
|
|
53
|
+
const pathTree = extractWebformKeys(webform)
|
|
20
54
|
const formiodefinition = {
|
|
21
55
|
id: webform['#id'],
|
|
22
56
|
components: this.parseFormContainerComponents(
|
|
23
57
|
webform,
|
|
24
58
|
webFormElementTree,
|
|
25
59
|
null,
|
|
26
|
-
formlogicList
|
|
27
|
-
|
|
60
|
+
formlogicList,
|
|
61
|
+
pathTree,
|
|
62
|
+
),
|
|
28
63
|
}
|
|
29
64
|
|
|
30
65
|
options.breadcrumbSettings = { clickable: false }
|
|
@@ -35,14 +70,12 @@ export class FormRenderParser {
|
|
|
35
70
|
|
|
36
71
|
formiodefinition.display = this.getDisplay(webFormElementTree)
|
|
37
72
|
if (this.isPreview) {
|
|
38
|
-
console.log('drupal webform', webform)
|
|
39
|
-
console.log('formio definition', formiodefinition)
|
|
40
73
|
}
|
|
41
74
|
return {
|
|
42
75
|
definition: formiodefinition,
|
|
43
76
|
tree: webFormElementTree,
|
|
44
77
|
options,
|
|
45
|
-
css
|
|
78
|
+
css,
|
|
46
79
|
}
|
|
47
80
|
} catch (e) {
|
|
48
81
|
console.error(e)
|
|
@@ -54,7 +87,8 @@ export class FormRenderParser {
|
|
|
54
87
|
container,
|
|
55
88
|
webFormElementTree,
|
|
56
89
|
parent,
|
|
57
|
-
formlogicList
|
|
90
|
+
formlogicList,
|
|
91
|
+
tree,
|
|
58
92
|
) => {
|
|
59
93
|
return Object.keys(container)
|
|
60
94
|
.filter((i) => !i.startsWith('#'))
|
|
@@ -63,11 +97,12 @@ export class FormRenderParser {
|
|
|
63
97
|
return RegisterFactory.getFormIOElement(
|
|
64
98
|
webFormElement,
|
|
65
99
|
this.formSettingsMeta,
|
|
66
|
-
parent
|
|
100
|
+
parent,
|
|
101
|
+
tree,
|
|
67
102
|
)
|
|
68
103
|
})
|
|
69
104
|
.filter(
|
|
70
|
-
(formIOElement) => !!formIOElement && formIOElement.isRenderable()
|
|
105
|
+
(formIOElement) => !!formIOElement && formIOElement.isRenderable(),
|
|
71
106
|
)
|
|
72
107
|
.map((formIOElement) => {
|
|
73
108
|
// nested form logic
|
|
@@ -78,11 +113,11 @@ export class FormRenderParser {
|
|
|
78
113
|
subContainer,
|
|
79
114
|
webFormElementTree,
|
|
80
115
|
formIOElement,
|
|
81
|
-
formlogicList
|
|
82
|
-
|
|
116
|
+
formlogicList,
|
|
117
|
+
tree,
|
|
118
|
+
),
|
|
83
119
|
)
|
|
84
120
|
}
|
|
85
|
-
|
|
86
121
|
return formIOElement
|
|
87
122
|
})
|
|
88
123
|
.map((formIOElement) => {
|
|
@@ -90,7 +125,7 @@ export class FormRenderParser {
|
|
|
90
125
|
webFormElementTree[formIOElement.getKey()] = formIOElement
|
|
91
126
|
const formioElementJSON = converFormIOElementToJSON(
|
|
92
127
|
formIOElement,
|
|
93
|
-
formlogicList
|
|
128
|
+
formlogicList,
|
|
94
129
|
).json
|
|
95
130
|
formIOElement.setFormIOdefinitionForElement(formioElementJSON)
|
|
96
131
|
return formioElementJSON
|
|
@@ -103,7 +138,7 @@ export class FormRenderParser {
|
|
|
103
138
|
webform.actions = {
|
|
104
139
|
'#type': 'webform_actions',
|
|
105
140
|
'#webform_id': 'form--actions',
|
|
106
|
-
'#webform_key': 'actions'
|
|
141
|
+
'#webform_key': 'actions',
|
|
107
142
|
}
|
|
108
143
|
}
|
|
109
144
|
return webform
|
|
@@ -115,8 +150,8 @@ export class FormRenderParser {
|
|
|
115
150
|
updateConditionWithFormReferences(
|
|
116
151
|
logic,
|
|
117
152
|
sourceElement,
|
|
118
|
-
webFormElementTree
|
|
119
|
-
)
|
|
153
|
+
webFormElementTree,
|
|
154
|
+
),
|
|
120
155
|
)
|
|
121
156
|
})
|
|
122
157
|
}
|
|
@@ -146,7 +181,7 @@ export class FormRenderParser {
|
|
|
146
181
|
|
|
147
182
|
getDisplay(webFormElementTree) {
|
|
148
183
|
const pageKeys = Object.keys(webFormElementTree).filter((elementKey) =>
|
|
149
|
-
webFormElementTree[elementKey].isPageComponent()
|
|
184
|
+
webFormElementTree[elementKey].isPageComponent(),
|
|
150
185
|
)
|
|
151
186
|
if (pageKeys.length > 0) {
|
|
152
187
|
return 'wizard'
|
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
isEmpty,
|
|
5
5
|
} from '../models/form-utils'
|
|
6
6
|
|
|
7
|
-
export function parseElementStates(webformElement) {
|
|
7
|
+
export function parseElementStates(webformElement, elementInstance) {
|
|
8
8
|
const states = webformElement['#states'] || {}
|
|
9
9
|
let logicList = []
|
|
10
10
|
Object.keys(states)
|
|
@@ -21,9 +21,13 @@ export function parseElementStates(webformElement) {
|
|
|
21
21
|
const state = states[sourceKey]
|
|
22
22
|
let conditonal = `result = (`
|
|
23
23
|
if (Array.isArray(state)) {
|
|
24
|
-
|
|
24
|
+
// Pass instance to ruleToString
|
|
25
|
+
state.forEach((rule) => {
|
|
26
|
+
return (conditonal += ruleToString(rule, elementInstance, conditonal))
|
|
27
|
+
})
|
|
25
28
|
} else {
|
|
26
|
-
|
|
29
|
+
// Pass instance to ruleToString
|
|
30
|
+
conditonal += ruleToString(state, elementInstance, conditonal)
|
|
27
31
|
}
|
|
28
32
|
conditonal += ')'
|
|
29
33
|
logic.trigger.javascript = conditonal
|
|
@@ -54,10 +58,14 @@ function getLogicBasedOnCondition(elementCondition) {
|
|
|
54
58
|
return null
|
|
55
59
|
}
|
|
56
60
|
|
|
57
|
-
function ruleToString(rule) {
|
|
61
|
+
function ruleToString(rule, elementInstance) {
|
|
58
62
|
if (typeof rule === 'object') {
|
|
59
63
|
const conditions = Object.keys(rule).reduce((items, ruleKey) => {
|
|
60
|
-
const condition = ruleItemToString(
|
|
64
|
+
const condition = ruleItemToString(
|
|
65
|
+
rule[ruleKey],
|
|
66
|
+
ruleKey,
|
|
67
|
+
elementInstance,
|
|
68
|
+
)
|
|
61
69
|
if (!isEmpty(condition)) {
|
|
62
70
|
items.push(condition)
|
|
63
71
|
}
|
|
@@ -74,7 +82,7 @@ function ruleToString(rule) {
|
|
|
74
82
|
return ''
|
|
75
83
|
}
|
|
76
84
|
|
|
77
|
-
function ruleItemToString(ruleItem, itemKey) {
|
|
85
|
+
function ruleItemToString(ruleItem, itemKey, elementInstance) {
|
|
78
86
|
// Regex 1: Matches standard selectors (name="foo"). Captures 'foo'.
|
|
79
87
|
const standardMatch = itemKey.match(/name="([^"]+)"/)
|
|
80
88
|
// Regex 2: Matches array selectors (name="foo[bar]"). Captures 'foo' and 'bar'.
|
|
@@ -98,7 +106,13 @@ function ruleItemToString(ruleItem, itemKey) {
|
|
|
98
106
|
const conditions = Object.keys(ruleItem)
|
|
99
107
|
.map((elementProp) =>
|
|
100
108
|
formComponentID
|
|
101
|
-
? getTrigger(
|
|
109
|
+
? getTrigger(
|
|
110
|
+
formComponentID,
|
|
111
|
+
ruleItem,
|
|
112
|
+
elementProp,
|
|
113
|
+
checkboxOptionKey,
|
|
114
|
+
elementInstance,
|
|
115
|
+
)
|
|
102
116
|
: null,
|
|
103
117
|
)
|
|
104
118
|
.filter((trigger) => !!trigger)
|
|
@@ -143,12 +157,29 @@ function createNewLogic(actionName, actionValue) {
|
|
|
143
157
|
}
|
|
144
158
|
}
|
|
145
159
|
|
|
146
|
-
function getTrigger(
|
|
160
|
+
function getTrigger(
|
|
161
|
+
formComponentID,
|
|
162
|
+
ruleItem,
|
|
163
|
+
prop,
|
|
164
|
+
checkboxOptionKey = null,
|
|
165
|
+
elementInstance,
|
|
166
|
+
) {
|
|
147
167
|
if (ruleItem.hasOwnProperty(prop)) {
|
|
148
168
|
const value = ruleItem[prop] ?? ''
|
|
149
169
|
|
|
150
170
|
let variable = `data.{${formComponentID}}`
|
|
151
|
-
|
|
171
|
+
|
|
172
|
+
try {
|
|
173
|
+
if (elementInstance && Array.isArray(elementInstance.tree)) {
|
|
174
|
+
const path = findPathInTree(elementInstance.tree, formComponentID)
|
|
175
|
+
if (path && path.length > 0) {
|
|
176
|
+
variable = buildDataAccessor(path, 'data')
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
} catch (e) {
|
|
180
|
+
let variable = `data.{${formComponentID}}`
|
|
181
|
+
}
|
|
182
|
+
|
|
152
183
|
let valueDelimeter = typeof value === 'string' ? "'" : ''
|
|
153
184
|
let expression = `${valueDelimeter}${value}${valueDelimeter}`
|
|
154
185
|
|
|
@@ -203,3 +234,44 @@ function getTrigger(formComponentID, ruleItem, prop, checkboxOptionKey = null) {
|
|
|
203
234
|
}
|
|
204
235
|
return null
|
|
205
236
|
}
|
|
237
|
+
|
|
238
|
+
function findPathInTree(tree, targetKey) {
|
|
239
|
+
if (!Array.isArray(tree) || !targetKey) return null
|
|
240
|
+
|
|
241
|
+
function dfs(nodes, path) {
|
|
242
|
+
for (const node of nodes) {
|
|
243
|
+
if (!node) continue
|
|
244
|
+
const nodeKey = node.key
|
|
245
|
+
const newPath =
|
|
246
|
+
nodeKey && node.type !== 'webform_wizard_page'
|
|
247
|
+
? path.concat(nodeKey)
|
|
248
|
+
: path
|
|
249
|
+
if (nodeKey === targetKey) return newPath
|
|
250
|
+
if (Array.isArray(node.children) && node.children.length > 0) {
|
|
251
|
+
const found = dfs(node.children, newPath)
|
|
252
|
+
if (found) return found
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
return null
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
return dfs(tree, [])
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
function isIdentifier(key) {
|
|
262
|
+
return /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(String(key))
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
function buildDataAccessor(pathArray, rootName = 'data') {
|
|
266
|
+
if (!Array.isArray(pathArray) || pathArray.length === 0) return rootName
|
|
267
|
+
const parts = []
|
|
268
|
+
for (const key of pathArray) {
|
|
269
|
+
if (isIdentifier(key)) {
|
|
270
|
+
parts.push('.' + key)
|
|
271
|
+
} else {
|
|
272
|
+
const escaped = String(key).replace(/'/g, "\\'")
|
|
273
|
+
parts.push(`['${escaped}']`)
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
return rootName + parts.join('')
|
|
277
|
+
}
|