fcad-core-dragon 2.1.1 → 2.1.2

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 (160) hide show
  1. package/.editorconfig +7 -7
  2. package/.gitlab-ci.yml +124 -0
  3. package/.prettierrc +11 -11
  4. package/.vscode/extensions.json +8 -8
  5. package/.vscode/settings.json +46 -16
  6. package/CHANGELOG +520 -520
  7. package/README.md +57 -57
  8. package/documentation/.vitepress/config.js +114 -114
  9. package/documentation/api-examples.md +49 -49
  10. package/documentation/composants/app-base-button.md +58 -58
  11. package/documentation/composants/app-base-error-display.md +59 -59
  12. package/documentation/composants/app-base-popover.md +68 -68
  13. package/documentation/composants/app-comp-audio.md +75 -75
  14. package/documentation/composants/app-comp-branch-buttons.md +111 -111
  15. package/documentation/composants/app-comp-button-progress.md +53 -53
  16. package/documentation/composants/app-comp-carousel.md +53 -53
  17. package/documentation/composants/app-comp-container.md +53 -53
  18. package/documentation/composants/app-comp-input-checkbox-next.md +42 -42
  19. package/documentation/composants/app-comp-input-dropdown-next.md +34 -34
  20. package/documentation/composants/app-comp-input-radio-next.md +39 -39
  21. package/documentation/composants/app-comp-input-text-next.md +35 -35
  22. package/documentation/composants/app-comp-input-text-table-next.md +34 -34
  23. package/documentation/composants/app-comp-input-text-to-fill-dropdown-next.md +53 -53
  24. package/documentation/composants/app-comp-input-text-to-fill-next.md +31 -31
  25. package/documentation/composants/app-comp-jauge.md +31 -31
  26. package/documentation/composants/app-comp-menu-item.md +55 -55
  27. package/documentation/composants/app-comp-menu.md +29 -29
  28. package/documentation/composants/app-comp-navigation.md +41 -41
  29. package/documentation/composants/app-comp-note-call.md +53 -53
  30. package/documentation/composants/app-comp-note-credit.md +53 -53
  31. package/documentation/composants/app-comp-play-bar-next.md +53 -53
  32. package/documentation/composants/app-comp-pop-up-next.md +93 -93
  33. package/documentation/composants/app-comp-quiz-next.md +235 -235
  34. package/documentation/composants/app-comp-quiz-recall.md +53 -53
  35. package/documentation/composants/app-comp-svg-next.md +53 -53
  36. package/documentation/composants/app-comp-table-of-content.md +50 -50
  37. package/documentation/composants/app-comp-video-player.md +82 -82
  38. package/documentation/composants.md +46 -46
  39. package/documentation/composants_critiques/ModelPageComposant.md +53 -53
  40. package/documentation/composants_critiques/app-base-module.md +43 -43
  41. package/documentation/composants_critiques/app-base-page.md +48 -48
  42. package/documentation/composants_critiques/app-base.md +311 -311
  43. package/documentation/composants_critiques/main.md +15 -15
  44. package/documentation/demarrage.md +50 -50
  45. package/documentation/deploiement.md +57 -57
  46. package/documentation/index.md +33 -33
  47. package/documentation/markdown-examples.md +85 -85
  48. package/documentation/public/vite.svg +14 -14
  49. package/documentation/public/vuejs.svg +1 -1
  50. package/documentation/public/vuetify.svg +5 -5
  51. package/eslint.config.js +60 -60
  52. package/junit-report.xml +182 -0
  53. package/package.json +66 -59
  54. package/playwright/index.html +12 -0
  55. package/playwright/index.js +21 -0
  56. package/playwright-ct.config.js +95 -0
  57. package/src/$locales/en.json +157 -157
  58. package/src/$locales/fr.json +120 -120
  59. package/src/assets/data/onboardingMessages.json +47 -47
  60. package/src/components/AppBase.vue +1171 -1169
  61. package/src/components/AppBaseButton.vue +90 -95
  62. package/src/components/AppBaseErrorDisplay.vue +438 -438
  63. package/src/components/AppBaseFlipCard.vue +84 -84
  64. package/src/components/AppBaseModule.vue +1639 -1634
  65. package/src/components/AppBasePage.vue +867 -866
  66. package/src/components/AppBasePopover.vue +41 -41
  67. package/src/components/AppBaseSkeleton.vue +66 -66
  68. package/src/components/AppCompAudio.vue +261 -256
  69. package/src/components/AppCompBranchButtons.vue +508 -508
  70. package/src/components/AppCompButtonProgress.vue +137 -132
  71. package/src/components/AppCompCarousel.vue +342 -336
  72. package/src/components/AppCompContainer.vue +29 -29
  73. package/src/components/AppCompInputCheckBoxNx.vue +325 -323
  74. package/src/components/AppCompInputDropdownNx.vue +302 -299
  75. package/src/components/AppCompInputRadioNx.vue +287 -284
  76. package/src/components/AppCompInputTextNx.vue +156 -153
  77. package/src/components/AppCompInputTextTableNx.vue +205 -202
  78. package/src/components/AppCompInputTextToFillDropdownNx.vue +343 -340
  79. package/src/components/AppCompInputTextToFillNx.vue +316 -313
  80. package/src/components/AppCompJauge.vue +81 -81
  81. package/src/components/AppCompMenu.vue +6 -1
  82. package/src/components/AppCompMenuItem.vue +246 -240
  83. package/src/components/AppCompNavigation.vue +977 -972
  84. package/src/components/AppCompNoteCall.vue +167 -161
  85. package/src/components/AppCompNoteCredit.vue +496 -491
  86. package/src/components/AppCompPlayBarNext.vue +2290 -2288
  87. package/src/components/AppCompPopUpNext.vue +508 -504
  88. package/src/components/AppCompQuizNext.vue +515 -510
  89. package/src/components/AppCompQuizRecall.vue +355 -350
  90. package/src/components/AppCompSVGNext.vue +346 -346
  91. package/src/components/AppCompSettingsMenu.vue +177 -172
  92. package/src/components/AppCompTableOfContent.vue +433 -427
  93. package/src/components/AppCompVideoPlayer.vue +377 -377
  94. package/src/components/AppCompViewDisplay.vue +6 -6
  95. package/src/components/BaseModule.vue +55 -55
  96. package/src/composables/useIdleDetector.js +56 -56
  97. package/src/composables/useQuiz.js +89 -89
  98. package/src/composables/useTimer.js +172 -172
  99. package/src/directives/nvdaFix.js +53 -53
  100. package/src/externalComps/ModuleView.vue +22 -22
  101. package/src/externalComps/SummaryView.vue +91 -91
  102. package/src/main.js +493 -476
  103. package/src/module/stores/appStore.js +960 -947
  104. package/src/module/xapi/ADL.js +520 -520
  105. package/src/module/xapi/Crypto/Hasher.js +241 -241
  106. package/src/module/xapi/Crypto/WordArray.js +278 -278
  107. package/src/module/xapi/Crypto/algorithms/BufferedBlockAlgorithm.js +103 -103
  108. package/src/module/xapi/Crypto/algorithms/C_algo.js +315 -315
  109. package/src/module/xapi/Crypto/algorithms/HMAC.js +9 -9
  110. package/src/module/xapi/Crypto/algorithms/SHA1.js +9 -9
  111. package/src/module/xapi/Crypto/encoders/Base.js +105 -105
  112. package/src/module/xapi/Crypto/encoders/Base64.js +99 -99
  113. package/src/module/xapi/Crypto/encoders/Hex.js +61 -61
  114. package/src/module/xapi/Crypto/encoders/Latin1.js +61 -61
  115. package/src/module/xapi/Crypto/encoders/Utf8.js +45 -45
  116. package/src/module/xapi/Crypto/index.js +53 -53
  117. package/src/module/xapi/Statement/activity.js +47 -47
  118. package/src/module/xapi/Statement/agent.js +55 -55
  119. package/src/module/xapi/Statement/group.js +26 -26
  120. package/src/module/xapi/Statement/index.js +259 -259
  121. package/src/module/xapi/Statement/statement.js +253 -253
  122. package/src/module/xapi/Statement/statementRef.js +23 -23
  123. package/src/module/xapi/Statement/substatement.js +22 -22
  124. package/src/module/xapi/Statement/verb.js +36 -36
  125. package/src/module/xapi/activitytypes.js +17 -17
  126. package/src/module/xapi/launch.js +157 -157
  127. package/src/module/xapi/utils.js +167 -167
  128. package/src/module/xapi/verbs.js +294 -294
  129. package/src/module/xapi/wrapper.js +1895 -1895
  130. package/src/module/xapi/xapiStatement.js +444 -444
  131. package/src/plugins/analytics.js +34 -34
  132. package/src/plugins/bus.js +12 -8
  133. package/src/plugins/gsap.js +17 -17
  134. package/src/plugins/helper.js +355 -358
  135. package/src/plugins/i18n.js +27 -26
  136. package/src/plugins/idb.js +227 -227
  137. package/src/plugins/save.js +37 -37
  138. package/src/plugins/scorm.js +287 -287
  139. package/src/plugins/xapi.js +11 -11
  140. package/src/public/index.html +33 -33
  141. package/src/router/index.js +57 -57
  142. package/src/router/routes.js +312 -312
  143. package/src/shared/generalfuncs.js +344 -344
  144. package/src/shared/validators.js +1018 -1018
  145. package/tests/component/AppBaseButton.spec.js +53 -0
  146. package/tests/component/pinia.spec.js +24 -0
  147. package/{src/components/tests__ → tests/unit}/AppBaseButton.spec.js +53 -53
  148. package/tests/unit/AppCompInputCheckBoxNx.spec.js +59 -0
  149. package/tests/unit/AppCompInputDropdownNx.spec.js +51 -0
  150. package/tests/unit/AppCompInputRadioNx.spec.js +59 -0
  151. package/tests/unit/AppCompInputTextNx.spec.js +44 -0
  152. package/tests/unit/AppCompInputTextTableNx.spec.js +77 -0
  153. package/tests/unit/AppCompInputTextToFillDropdownNx.spec.js +60 -0
  154. package/tests/unit/AppCompInputTextToFillNx.spec.js +45 -0
  155. package/tests/unit/AppCompQuizNext.spec.js +114 -0
  156. package/tests/unit/AppCompVideoPlayer.spec.js +177 -0
  157. package/{src/components/tests__ → tests/unit}/useTimer.spec.js +91 -91
  158. package/vitest.config.js +28 -19
  159. package/vitest.setup.js +28 -0
  160. package/src/components/AppBaseButton.test.js +0 -21
@@ -1,313 +1,316 @@
1
- <!-- About this Component--
2
- * Renders a Series of inputs to collect input for the Quiz component.
3
- * Related Quiz to question: TEXTE_TROUE
4
- * Receives the a data object defined by user
5
- * Used by AppCompQuiz
6
- * Uses useQuiz composable
7
- -->
8
- <template>
9
- <div v-if="inputElements.length > 0" :id="id" class="input-box">
10
- <fieldset :aria-label="fieldsetLabel">
11
- <div
12
- v-for="textInput in inputElements"
13
- :key="textInput.id"
14
- class="texteatrou"
15
- >
16
- <span
17
- v-if="textInput.type == 'text' && textInput.content.trim() !== ''"
18
- v-html="textInput.content"
19
- ></span>
20
- <label :for="`${id}_${textInput.id}-champ`" style="display: none">
21
- {{ $t('text.quiz') }}
22
- </label>
23
-
24
- <v-text-field
25
- v-if="textInput.type == 'input'"
26
- :id="`${id}_${textInput.id}-champ`"
27
- :model-value="inputsValue[textInput.index]"
28
- :placeholder="$t('text.place_holder.for_textarea')"
29
- no-resize
30
- :class="`${retro[textInput.id.substr(textInput.id.length - 1)]}`"
31
- class="input-textatrou"
32
- :aria-describedby="`${id}_${textInput.id}-msg-erreur`"
33
- :aria-labelledby="`${id}_${textInput.id}-label`"
34
- @update:model-value="onSelectUpdate($event, textInput.index)"
35
- />
36
- <span
37
- :id="`${id}_${textInput.id}-msg-erreur`"
38
- :key="`msg_chx_${id}_${textInput.id}`"
39
- class="sr-only"
40
- >
41
- {{ messageAccessibility[textInput.index] }}
42
- </span>
43
- </div>
44
- </fieldset>
45
- </div>
46
- </template>
47
- <script>
48
- import { useQuiz } from '../composables/useQuiz'
49
- import { validateObjType } from '../shared/validators'
50
- export default {
51
- name: 'AppCompInputTextToFillNext',
52
- /* PROPS USED FOR PARENT TO COMMUNICATE DATA TO CHILD */
53
- props: {
54
- modelValue: {
55
- type: Array,
56
- default: () => []
57
- },
58
- inputData: {
59
- type: Array,
60
- default: () => []
61
- },
62
- textBase: {
63
- type: String,
64
- default: ''
65
- },
66
- solution: {
67
- type: Array,
68
- default: () => []
69
- },
70
-
71
- id: {
72
- type: String,
73
- default: ''
74
- }
75
- },
76
- emits: ['update:modelValue', 'enable-submit'],
77
- setup(props) {
78
- const { retroType, addRetroStyle, resetRetroStyle } = useQuiz()
79
-
80
- return { retroType, addRetroStyle, resetRetroStyle }
81
- },
82
- data() {
83
- return {
84
- quizInputDataValue: [],
85
- textInputs: [],
86
- quizSolution: null,
87
- inputElements: [],
88
- result: null,
89
- retro: [],
90
- messageAccessibility: [],
91
- inputCount: null
92
- }
93
- },
94
- computed: {
95
- fieldsetLabel() {
96
- return `${this.$t('quizState.textToFillFieldset1')} ${this.inputCount} ${this.$t('quizState.textToFillFieldset2')}`
97
- },
98
-
99
- /* INTERNAL REACTIVE VALUE THAT BIND WITH MODELVALUE PROPS */
100
- inputsValue: {
101
- get() {
102
- return this.modelValue
103
- },
104
- set(newValue) {
105
- this.$emit('update:modelValue', [...newValue])
106
- }
107
- }
108
- },
109
-
110
- watch: {
111
- /**
112
- * @description watcher to track the inputs content
113
- * remove an element from the inputs array (modelValue) when it is empty
114
- */
115
- inputsValue: {
116
- async handler() {
117
- const filled = this.modelValue.filter((val) => val && val.trim() !== '')
118
- if (this.inputCount == null)
119
- this.inputCount = await this.getInputElements()
120
- this.$emit('enable-submit', filled.length == this.inputCount)
121
- },
122
- deep: true,
123
- immediate: true
124
- }
125
- },
126
- created() {
127
- this.createTextWithInput(this.textBase)
128
- },
129
- mounted() {},
130
-
131
- methods: {
132
- /**
133
- * @description validate the raw data received by the component to render is view
134
- * @returns {Object} errors - errorList: to display in view and errorConsole, to be displayed in console
135
- */
136
- validateInputData() {
137
- let errors = null //array for errors dectected
138
- let stringType = ['id', 'value']
139
-
140
- if (!this.inputData.length) return errors
141
- for (let i = 0; i < this.inputData.length; i++) {
142
- errors = validateObjType(
143
- this.inputData[i],
144
- { stringType },
145
- null,
146
- `choix_reponse #${i + 1}`
147
- )
148
- const { errorList, errorInConsole } = errors
149
-
150
- if (errorList.length || errorInConsole.length) return errors
151
- }
152
-
153
- return errors
154
- },
155
- /**
156
- * @description create the object to genate the text and inputs
157
- * @param {String} str the text with holes to fill
158
- */
159
- createTextWithInput(str) {
160
- const regex = /\$%\S*%\$/g // regex pattern to match exp: $%number%$
161
-
162
- let splittedText = str.split(regex)
163
- let listInput = []
164
-
165
- for (let i = 0; i < splittedText.length - 1; i++) {
166
- listInput.push({
167
- id: `text-${i}`,
168
- type: 'text',
169
- content: splittedText[i]
170
- })
171
-
172
- if (i < splittedText.length - 1)
173
- listInput.push({ id: `input-${i}`, type: 'input', index: i })
174
- }
175
-
176
- this.inputElements = listInput
177
- },
178
- /**
179
- * @description Method to force update of this.inputsValue.
180
- * this force the old value and new value of the input to be tracked by VUE.
181
- * @param newValue, the new value of the input
182
- * @param index index of the selected element
183
- */
184
-
185
- onSelectUpdate(newValue, index) {
186
- if (this.$el && this.$el.id !== this.id) return
187
- this.resetRetroStyle([this.retro, this.messageAccessibility])
188
-
189
- const updated = [...this.inputsValue] //create new array from inputsValue
190
- updated[index] = newValue
191
- this.inputsValue = updated //trigger vue reactivity for inputsValue
192
- },
193
-
194
- /**
195
- * @description Component validation method to validate the user input against the solution
196
- * can handle logic of Css style to apply (correct/wrong Answer) and return the result
197
- * @return {Object} result
198
- */
199
- validateAnswer() {
200
- let mappedResults
201
- if (this.solution != null) {
202
- mappedResults = this.inputsValue.map((a, i) => {
203
- a = a.trim().toLowerCase()
204
- const s = Object.values(this.solution[i])[0]
205
- return { filled: a, correct: s.includes(a) }
206
- })
207
- } else {
208
- mappedResults = this.inputsValue.map((a, i) => {
209
- return { filled: a, correct: false }
210
- })
211
- }
212
-
213
- //========================================================
214
- //Set the valition style
215
- let { classRetro, mesA11y } = this.addRetroStyle(
216
- this.solution,
217
- mappedResults,
218
- this.inputsValue.length
219
- )
220
- this.retro = classRetro
221
- this.messageAccessibility = mesA11y
222
- //Retrive the user response from validation
223
- this.result = mappedResults.filter((a) => a.filled)
224
-
225
- let retro = this.retroType(this.solution, this.result)
226
-
227
- let cAns
228
- if (this.solution != null) cAns = this.computeResult(this.result)
229
- else cAns = false
230
- //========================================================
231
- //Return this to parent
232
- return {
233
- userAnswer: this.result,
234
- correctAnswer: cAns,
235
- retroType: retro
236
- }
237
- },
238
-
239
- /**
240
- * @description - compute the correct elements in user response
241
- * compare with the solution and return wether user succeeded or failed
242
- * @param {Object} result - user responses
243
- * @retuns boolean
244
- */
245
- computeResult(result) {
246
- const res = this.result.filter((el) => el.correct)
247
- return res.length == this.solution.length
248
- },
249
- /**
250
- * @description - Method to ge the Number of input elements in the component
251
- * This is used to determine if the user has filled all inputs before enabling the submit button
252
- * @returns {Promise} resolves to the number of input elements
253
- */
254
- async getInputElements() {
255
- await this.$nextTick()
256
- // Ensure this is the targeted element
257
- if (this.$el.id !== this.id) return
258
- return this.inputElements.filter((el) => el.type == 'input').length
259
- }
260
- }
261
- }
262
- </script>
263
- <style lang="scss">
264
- .texteatrou {
265
- display: inline;
266
- position: relative;
267
-
268
- .v-input {
269
- display: inline-block;
270
- }
271
- }
272
-
273
- .texteatrou > input {
274
- display: inline;
275
- width: auto;
276
- }
277
-
278
- fieldset {
279
- border: inherit;
280
- }
281
-
282
- .texteatrou {
283
- position: relative;
284
-
285
- .v-input {
286
- width: 240px;
287
- height: 29px;
288
- position: relative;
289
-
290
- .v-input__details {
291
- display: none !important;
292
- }
293
-
294
- .v-input__control {
295
- height: 29px;
296
- width: 240px;
297
-
298
- .v-field__field {
299
- min-height: 29px;
300
- height: 29px;
301
-
302
- .v-field__input {
303
- padding-top: 2px;
304
- padding-bottom: 2px;
305
- padding-right: 30px;
306
- height: 29px;
307
- min-height: 29px;
308
- }
309
- }
310
- }
311
- }
312
- }
313
- </style>
1
+ <!-- About this Component--
2
+ * Renders a Series of inputs to collect input for the Quiz component.
3
+ * Related Quiz to question: TEXTE_TROUE
4
+ * Receives the a data object defined by user
5
+ * Used by AppCompQuiz
6
+ * Uses useQuiz composable
7
+ -->
8
+ <template>
9
+ <div v-if="inputElements.length > 0" :id="id" class="input-box">
10
+ <fieldset :aria-label="fieldsetLabel">
11
+ <div
12
+ v-for="textInput in inputElements"
13
+ :key="textInput.id"
14
+ class="texteatrou"
15
+ >
16
+ <span
17
+ v-if="textInput.type == 'text' && textInput.content.trim() !== ''"
18
+ v-html="textInput.content"
19
+ ></span>
20
+ <label :for="`${id}_${textInput.id}-champ`" style="display: none">
21
+ {{ $t('text.quiz') }}
22
+ </label>
23
+
24
+ <v-text-field
25
+ v-if="textInput.type == 'input'"
26
+ :id="`${id}_${textInput.id}-champ`"
27
+ :model-value="inputsValue[textInput.index]"
28
+ :placeholder="$t('text.place_holder.for_textarea')"
29
+ no-resize
30
+ :class="`${retro[textInput.id.substr(textInput.id.length - 1)]}`"
31
+ class="input-textatrou"
32
+ :aria-describedby="`${id}_${textInput.id}-msg-erreur`"
33
+ :aria-labelledby="`${id}_${textInput.id}-label`"
34
+ @update:model-value="onSelectUpdate($event, textInput.index)"
35
+ />
36
+ <span
37
+ :id="`${id}_${textInput.id}-msg-erreur`"
38
+ :key="`msg_chx_${id}_${textInput.id}`"
39
+ class="sr-only"
40
+ >
41
+ {{ messageAccessibility[textInput.index] }}
42
+ </span>
43
+ </div>
44
+ </fieldset>
45
+ </div>
46
+ </template>
47
+ <script>
48
+ import { useQuiz } from '../composables/useQuiz'
49
+ import { validateObjType } from '../shared/validators'
50
+ import { useI18n } from 'vue-i18n'
51
+
52
+ export default {
53
+ name: 'AppCompInputTextToFillNext',
54
+ /* PROPS USED FOR PARENT TO COMMUNICATE DATA TO CHILD */
55
+ props: {
56
+ modelValue: {
57
+ type: Array,
58
+ default: () => []
59
+ },
60
+ inputData: {
61
+ type: Array,
62
+ default: () => []
63
+ },
64
+ textBase: {
65
+ type: String,
66
+ default: ''
67
+ },
68
+ solution: {
69
+ type: Array,
70
+ default: () => []
71
+ },
72
+
73
+ id: {
74
+ type: String,
75
+ default: ''
76
+ }
77
+ },
78
+ emits: ['update:modelValue', 'enable-submit'],
79
+ setup(props) {
80
+ const { t } = useI18n()
81
+ const { retroType, addRetroStyle, resetRetroStyle } = useQuiz()
82
+
83
+ return { retroType, addRetroStyle, resetRetroStyle, t }
84
+ },
85
+ data() {
86
+ return {
87
+ quizInputDataValue: [],
88
+ textInputs: [],
89
+ quizSolution: null,
90
+ inputElements: [],
91
+ result: null,
92
+ retro: [],
93
+ messageAccessibility: [],
94
+ inputCount: null
95
+ }
96
+ },
97
+ computed: {
98
+ fieldsetLabel() {
99
+ return `${this.$t('quizState.textToFillFieldset1')} ${this.inputCount} ${this.$t('quizState.textToFillFieldset2')}`
100
+ },
101
+
102
+ /* INTERNAL REACTIVE VALUE THAT BIND WITH MODELVALUE PROPS */
103
+ inputsValue: {
104
+ get() {
105
+ return this.modelValue
106
+ },
107
+ set(newValue) {
108
+ this.$emit('update:modelValue', [...newValue])
109
+ }
110
+ }
111
+ },
112
+
113
+ watch: {
114
+ /**
115
+ * @description watcher to track the inputs content
116
+ * remove an element from the inputs array (modelValue) when it is empty
117
+ */
118
+ inputsValue: {
119
+ async handler() {
120
+ const filled = this.modelValue.filter((val) => val && val.trim() !== '')
121
+ if (this.inputCount == null)
122
+ this.inputCount = await this.getInputElements()
123
+ this.$emit('enable-submit', filled.length == this.inputCount)
124
+ },
125
+ deep: true,
126
+ immediate: true
127
+ }
128
+ },
129
+ created() {
130
+ this.createTextWithInput(this.textBase)
131
+ },
132
+ mounted() {},
133
+
134
+ methods: {
135
+ /**
136
+ * @description validate the raw data received by the component to render is view
137
+ * @returns {Object} errors - errorList: to display in view and errorConsole, to be displayed in console
138
+ */
139
+ validateInputData() {
140
+ let errors = null //array for errors dectected
141
+ let stringType = ['id', 'value']
142
+
143
+ if (!this.inputData.length) return errors
144
+ for (let i = 0; i < this.inputData.length; i++) {
145
+ errors = validateObjType(
146
+ this.inputData[i],
147
+ { stringType },
148
+ null,
149
+ `choix_reponse #${i + 1}`
150
+ )
151
+ const { errorList, errorInConsole } = errors
152
+
153
+ if (errorList.length || errorInConsole.length) return errors
154
+ }
155
+
156
+ return errors
157
+ },
158
+ /**
159
+ * @description create the object to genate the text and inputs
160
+ * @param {String} str the text with holes to fill
161
+ */
162
+ createTextWithInput(str) {
163
+ const regex = /\$%\S*%\$/g // regex pattern to match exp: $%number%$
164
+
165
+ let splittedText = str.split(regex)
166
+ let listInput = []
167
+
168
+ for (let i = 0; i < splittedText.length - 1; i++) {
169
+ listInput.push({
170
+ id: `text-${i}`,
171
+ type: 'text',
172
+ content: splittedText[i]
173
+ })
174
+
175
+ if (i < splittedText.length - 1)
176
+ listInput.push({ id: `input-${i}`, type: 'input', index: i })
177
+ }
178
+
179
+ this.inputElements = listInput
180
+ },
181
+ /**
182
+ * @description Method to force update of this.inputsValue.
183
+ * this force the old value and new value of the input to be tracked by VUE.
184
+ * @param newValue, the new value of the input
185
+ * @param index index of the selected element
186
+ */
187
+
188
+ onSelectUpdate(newValue, index) {
189
+ if (this.$el && this.$el.id !== this.id) return
190
+ this.resetRetroStyle([this.retro, this.messageAccessibility])
191
+
192
+ const updated = [...this.inputsValue] //create new array from inputsValue
193
+ updated[index] = newValue
194
+ this.inputsValue = updated //trigger vue reactivity for inputsValue
195
+ },
196
+
197
+ /**
198
+ * @description Component validation method to validate the user input against the solution
199
+ * can handle logic of Css style to apply (correct/wrong Answer) and return the result
200
+ * @return {Object} result
201
+ */
202
+ validateAnswer() {
203
+ let mappedResults
204
+ if (this.solution != null) {
205
+ mappedResults = this.inputsValue.map((a, i) => {
206
+ a = a.trim().toLowerCase()
207
+ const s = Object.values(this.solution[i])[0]
208
+ return { filled: a, correct: s.includes(a) }
209
+ })
210
+ } else {
211
+ mappedResults = this.inputsValue.map((a, i) => {
212
+ return { filled: a, correct: false }
213
+ })
214
+ }
215
+
216
+ //========================================================
217
+ //Set the valition style
218
+ let { classRetro, mesA11y } = this.addRetroStyle(
219
+ this.solution,
220
+ mappedResults,
221
+ this.inputsValue.length
222
+ )
223
+ this.retro = classRetro
224
+ this.messageAccessibility = mesA11y
225
+ //Retrive the user response from validation
226
+ this.result = mappedResults.filter((a) => a.filled)
227
+
228
+ let retro = this.retroType(this.solution, this.result)
229
+
230
+ let cAns
231
+ if (this.solution != null) cAns = this.computeResult(this.result)
232
+ else cAns = false
233
+ //========================================================
234
+ //Return this to parent
235
+ return {
236
+ userAnswer: this.result,
237
+ correctAnswer: cAns,
238
+ retroType: retro
239
+ }
240
+ },
241
+
242
+ /**
243
+ * @description - compute the correct elements in user response
244
+ * compare with the solution and return wether user succeeded or failed
245
+ * @param {Object} result - user responses
246
+ * @retuns boolean
247
+ */
248
+ computeResult(result) {
249
+ const res = this.result.filter((el) => el.correct)
250
+ return res.length == this.solution.length
251
+ },
252
+ /**
253
+ * @description - Method to ge the Number of input elements in the component
254
+ * This is used to determine if the user has filled all inputs before enabling the submit button
255
+ * @returns {Promise} resolves to the number of input elements
256
+ */
257
+ async getInputElements() {
258
+ await this.$nextTick()
259
+ // Ensure this is the targeted element
260
+ if (this.$el.id !== this.id) return
261
+ return this.inputElements.filter((el) => el.type == 'input').length
262
+ }
263
+ }
264
+ }
265
+ </script>
266
+ <style lang="scss">
267
+ .texteatrou {
268
+ display: inline;
269
+ position: relative;
270
+
271
+ .v-input {
272
+ display: inline-block;
273
+ }
274
+ }
275
+
276
+ .texteatrou > input {
277
+ display: inline;
278
+ width: auto;
279
+ }
280
+
281
+ fieldset {
282
+ border: inherit;
283
+ }
284
+
285
+ .texteatrou {
286
+ position: relative;
287
+
288
+ .v-input {
289
+ width: 240px;
290
+ height: 29px;
291
+ position: relative;
292
+
293
+ .v-input__details {
294
+ display: none !important;
295
+ }
296
+
297
+ .v-input__control {
298
+ height: 29px;
299
+ width: 240px;
300
+
301
+ .v-field__field {
302
+ min-height: 29px;
303
+ height: 29px;
304
+
305
+ .v-field__input {
306
+ padding-top: 2px;
307
+ padding-bottom: 2px;
308
+ padding-right: 30px;
309
+ height: 29px;
310
+ min-height: 29px;
311
+ }
312
+ }
313
+ }
314
+ }
315
+ }
316
+ </style>