fcad-core-dragon 2.0.0-beta.0 → 2.0.0-beta.10

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 (161) hide show
  1. package/.editorconfig +6 -31
  2. package/.prettierrc +11 -0
  3. package/.vscode/extensions.json +8 -0
  4. package/.vscode/settings.json +16 -0
  5. package/CHANGELOG +153 -0
  6. package/README.md +28 -43
  7. package/documentation/.vitepress/config.js +114 -0
  8. package/documentation/api-examples.md +49 -0
  9. package/documentation/composants/app-base-button.md +58 -0
  10. package/documentation/composants/app-base-error-display.md +59 -0
  11. package/documentation/composants/app-base-popover.md +68 -0
  12. package/documentation/composants/app-comp-audio.md +75 -0
  13. package/documentation/composants/app-comp-branch-buttons.md +111 -0
  14. package/documentation/composants/app-comp-button-progress.md +53 -0
  15. package/documentation/composants/app-comp-carousel.md +53 -0
  16. package/documentation/composants/app-comp-container.md +53 -0
  17. package/documentation/composants/app-comp-input-checkbox-next.md +42 -0
  18. package/documentation/composants/app-comp-input-dropdown-next.md +34 -0
  19. package/documentation/composants/app-comp-input-radio-next.md +39 -0
  20. package/documentation/composants/app-comp-input-text-next.md +35 -0
  21. package/documentation/composants/app-comp-input-text-table-next.md +34 -0
  22. package/documentation/composants/app-comp-input-text-to-fill-dropdown-next.md +53 -0
  23. package/documentation/composants/app-comp-input-text-to-fill-next.md +31 -0
  24. package/documentation/composants/app-comp-jauge.md +31 -0
  25. package/documentation/composants/app-comp-menu-item.md +55 -0
  26. package/documentation/composants/app-comp-menu.md +29 -0
  27. package/documentation/composants/app-comp-navigation.md +41 -0
  28. package/documentation/composants/app-comp-note-call.md +53 -0
  29. package/documentation/composants/app-comp-note-credit.md +53 -0
  30. package/documentation/composants/app-comp-play-bar-next.md +53 -0
  31. package/documentation/composants/app-comp-pop-up-next.md +93 -0
  32. package/documentation/composants/app-comp-quiz-next.md +235 -0
  33. package/documentation/composants/app-comp-quiz-recall.md +53 -0
  34. package/documentation/composants/app-comp-svg-next.md +53 -0
  35. package/documentation/composants/app-comp-table-of-content.md +50 -0
  36. package/documentation/composants/app-comp-video-player.md +82 -0
  37. package/documentation/composants.md +46 -0
  38. package/documentation/composants_critiques/ModelPageComposant.md +53 -0
  39. package/documentation/composants_critiques/app-base-module.md +43 -0
  40. package/documentation/composants_critiques/app-base-page.md +48 -0
  41. package/documentation/composants_critiques/app-base.md +311 -0
  42. package/documentation/composants_critiques/main.md +15 -0
  43. package/documentation/demarrage.md +50 -0
  44. package/documentation/deploiement.md +58 -0
  45. package/documentation/index.md +33 -0
  46. package/documentation/markdown-examples.md +85 -0
  47. package/documentation/public/npm_version.png +0 -0
  48. package/documentation/public/vite.svg +15 -0
  49. package/documentation/public/vuejs.svg +2 -0
  50. package/documentation/public/vuetify.svg +6 -0
  51. package/eslint.config.js +60 -0
  52. package/package.json +43 -49
  53. package/src/$locales/en.json +94 -92
  54. package/src/$locales/fr.json +77 -113
  55. package/src/assets/data/onboardingMessages.json +1 -1
  56. package/src/components/AppBase.vue +971 -437
  57. package/src/components/AppBaseButton.test.js +21 -0
  58. package/src/components/AppBaseButton.vue +42 -10
  59. package/src/components/AppBaseErrorDisplay.vue +209 -162
  60. package/src/components/AppBaseFlipCard.vue +1 -0
  61. package/src/components/AppBaseModule.vue +1021 -976
  62. package/src/components/AppBasePage.vue +656 -128
  63. package/src/components/AppBasePopover.vue +41 -0
  64. package/src/components/AppBaseSkeleton.vue +66 -0
  65. package/src/components/AppCompAudio.vue +256 -0
  66. package/src/components/AppCompBranchButtons.vue +108 -181
  67. package/src/components/AppCompButtonProgress.vue +44 -70
  68. package/src/components/AppCompCarousel.vue +284 -233
  69. package/src/components/AppCompContainer.vue +29 -0
  70. package/src/components/AppCompInputCheckBoxNx.vue +323 -0
  71. package/src/components/AppCompInputDropdownNx.vue +299 -0
  72. package/src/components/AppCompInputRadioNx.vue +284 -0
  73. package/src/components/AppCompInputTextNx.vue +153 -0
  74. package/src/components/AppCompInputTextTableNx.vue +202 -0
  75. package/src/components/AppCompInputTextToFillDropdownNx.vue +340 -0
  76. package/src/components/AppCompInputTextToFillNx.vue +313 -0
  77. package/src/components/AppCompJauge.vue +36 -11
  78. package/src/components/AppCompMenu.vue +312 -92
  79. package/src/components/AppCompMenuItem.vue +129 -105
  80. package/src/components/AppCompNavigation.vue +972 -0
  81. package/src/components/AppCompNoteCall.vue +161 -0
  82. package/src/components/AppCompNoteCredit.vue +491 -0
  83. package/src/components/AppCompPlayBarNext.vue +2288 -0
  84. package/src/components/AppCompPopUpNext.vue +504 -0
  85. package/src/components/AppCompQuizNext.vue +510 -0
  86. package/src/components/AppCompQuizRecall.vue +350 -0
  87. package/src/components/AppCompSVGNext.vue +346 -0
  88. package/src/components/AppCompSettingsMenu.vue +18 -16
  89. package/src/components/AppCompTableOfContent.vue +340 -122
  90. package/src/components/AppCompVideoPlayer.vue +377 -0
  91. package/src/components/BaseModule.vue +24 -117
  92. package/src/components/tests__/AppBaseButton.spec.js +53 -0
  93. package/src/components/tests__/useTimer.spec.js +91 -0
  94. package/src/composables/useIdleDetector.js +56 -0
  95. package/src/composables/useQuiz.js +89 -0
  96. package/src/composables/useTimer.js +172 -0
  97. package/src/directives/nvdaFix.js +53 -0
  98. package/src/externalComps/ModuleView.vue +22 -0
  99. package/src/externalComps/SummaryView.vue +91 -0
  100. package/src/main.js +400 -142
  101. package/src/module/stores/appStore.js +947 -0
  102. package/src/module/xapi/ADL.js +241 -60
  103. package/src/module/xapi/Crypto/Hasher.js +8 -8
  104. package/src/module/xapi/Crypto/WordArray.js +6 -6
  105. package/src/module/xapi/Crypto/algorithms/BufferedBlockAlgorithm.js +4 -4
  106. package/src/module/xapi/Crypto/algorithms/C_algo.js +14 -18
  107. package/src/module/xapi/Crypto/algorithms/HMAC.js +1 -1
  108. package/src/module/xapi/Crypto/algorithms/SHA1.js +1 -1
  109. package/src/module/xapi/Crypto/encoders/Base.js +7 -7
  110. package/src/module/xapi/Crypto/encoders/Base64.js +3 -3
  111. package/src/module/xapi/Crypto/encoders/Hex.js +4 -3
  112. package/src/module/xapi/Crypto/encoders/Latin1.js +3 -3
  113. package/src/module/xapi/Crypto/encoders/Utf8.js +3 -3
  114. package/src/module/xapi/Statement/index.js +3 -3
  115. package/src/module/xapi/launch.js +10 -10
  116. package/src/module/xapi/utils.js +17 -17
  117. package/src/module/xapi/wrapper.js +223 -218
  118. package/src/module/xapi/xapiStatement.js +29 -29
  119. package/src/plugins/analytics.js +34 -0
  120. package/src/plugins/bus.js +7 -2
  121. package/src/plugins/gsap.js +9 -8
  122. package/src/plugins/helper.js +141 -43
  123. package/src/plugins/i18n.js +13 -18
  124. package/src/plugins/idb.js +46 -30
  125. package/src/plugins/save.js +1 -1
  126. package/src/plugins/scorm.js +15 -15
  127. package/src/plugins/xapi.js +2 -2
  128. package/src/public/index.html +23 -11
  129. package/src/router/index.js +57 -0
  130. package/src/router/routes.js +312 -0
  131. package/src/shared/generalfuncs.js +241 -10
  132. package/src/shared/validators.js +1018 -0
  133. package/vitest.config.js +19 -0
  134. package/.eslintignore +0 -29
  135. package/.eslintrc.js +0 -86
  136. package/.prettierrc.js +0 -5
  137. package/babel.config.js +0 -3
  138. package/src/components/AppBaseDragChoice.vue +0 -91
  139. package/src/components/AppBaseDropZone.vue +0 -112
  140. package/src/components/AppCompDragAndDrop.vue +0 -339
  141. package/src/components/AppCompInputAssociation.vue +0 -332
  142. package/src/components/AppCompInputCheckBox.vue +0 -227
  143. package/src/components/AppCompInputDropdown.vue +0 -184
  144. package/src/components/AppCompInputRadio.vue +0 -169
  145. package/src/components/AppCompInputTextBox.vue +0 -91
  146. package/src/components/AppCompInputTextTable.vue +0 -155
  147. package/src/components/AppCompInputTextToFillDropdown.vue +0 -255
  148. package/src/components/AppCompInputTextToFillText.vue +0 -164
  149. package/src/components/AppCompMediaPlayer.vue +0 -365
  150. package/src/components/AppCompNavigationFull.vue +0 -1791
  151. package/src/components/AppCompPlayBar.vue +0 -1540
  152. package/src/components/AppCompPopUp.vue +0 -523
  153. package/src/components/AppCompQuiz.vue +0 -2998
  154. package/src/components/AppCompToolTip.vue +0 -94
  155. package/src/mixins/$pageMixins.js +0 -381
  156. package/src/mixins/$quizMixins.js +0 -456
  157. package/src/mixins/timerMixin.js +0 -132
  158. package/src/module/store.js +0 -874
  159. package/src/plugins/timeManager.js +0 -77
  160. package/src/routes.js +0 -734
  161. package/vue.config.js +0 -83
@@ -0,0 +1,323 @@
1
+ <!-- About this Component--
2
+ * Renders a checkboxe input type for the Quiz component
3
+ * Related Quiz to question: REPONSE_MULTIPLE
4
+ * Receives the a data object defined by user
5
+ * Used by AppCompQuiz
6
+ -->
7
+ <template>
8
+ <div :id="id" class="input-box">
9
+ <fieldset :aria-label="fieldsetLabel">
10
+ <template
11
+ v-for="(choixReponse, index) in inputData"
12
+ :Key="`div_chx_${id}_${choixReponse.id}`"
13
+ >
14
+ <div class="box-checkbox">
15
+ <label
16
+ :key="`lbl_chx_${id}-${choixReponse.id}`"
17
+ :for="`boxchx_${id}_${choixReponse.id}`"
18
+ class="checkbox-label"
19
+ :class="[
20
+ {
21
+ answerSlct: isSelected(choixReponse.value)
22
+ },
23
+ `${retro[index] || ''}`
24
+ ]"
25
+ >
26
+ <input
27
+ :id="`boxchx_${id}_${choixReponse.id}`"
28
+ :key="`boxchx_${id}_${id}-${choixReponse.id}`"
29
+ :checked="isSelected(choixReponse.value)"
30
+ type="checkbox"
31
+ :name="`btn-checkbox-${id}`"
32
+ :aria-labelledby="`span_${id}_${choixReponse.id}`"
33
+ :aria-describedby="`${id}_${choixReponse.id}-msg-erreur`"
34
+ @change="onSelectUpdate($event, choixReponse.value)"
35
+ />
36
+ <span
37
+ :id="`span_${id}_${choixReponse.id}`"
38
+ class="checkbox-contenu"
39
+ v-html="choixReponse.value"
40
+ ></span>
41
+ <span
42
+ :id="`${id}_${choixReponse.id}-msg-erreur`"
43
+ :key="`msg_chx_${id}_${choixReponse.id}`"
44
+ class="sr-only"
45
+ >
46
+ {{ messageAccessibility[index] }}
47
+ </span>
48
+ </label>
49
+ </div>
50
+ </template>
51
+ </fieldset>
52
+ </div>
53
+ </template>
54
+ <script>
55
+ import { useQuiz } from '../composables/useQuiz'
56
+ import { validateObjType } from '../shared/validators'
57
+ export default {
58
+ name: 'AppCompInputCheckBoxNx',
59
+ /* PROPS USED FOR PARENT TO COMMUNICATE DATA TO CHILD */
60
+ props: {
61
+ modelValue: {
62
+ type: Array,
63
+ default: () => []
64
+ },
65
+ inputData: {
66
+ type: Array,
67
+ default: () => []
68
+ },
69
+ solution: {
70
+ type: Array,
71
+ default: () => []
72
+ },
73
+ id: {
74
+ type: String,
75
+ default: ''
76
+ }
77
+ },
78
+ emits: ['update:modelValue', 'enable-submit'],
79
+ setup() {
80
+ const { retroType, addRetroStyle, resetRetroStyle } = useQuiz()
81
+
82
+ return { retroType, addRetroStyle, resetRetroStyle }
83
+ },
84
+ data() {
85
+ return {
86
+ quizInputDataValue: [],
87
+ result: null,
88
+ retro: [],
89
+ messageAccessibility: [],
90
+ selectedItems: []
91
+ }
92
+ },
93
+ computed: {
94
+ fieldsetLabel() {
95
+ return `${this.$t('quizState.checkboxFieldset')} ${this.inputData.length} ${this.$t('quizState.options')}`
96
+ },
97
+ /* INTERNAL REACTIVE VALUE THAT BIND WITH MODELVALUE PROPS */
98
+ inputsValue: {
99
+ get() {
100
+ return this.modelValue
101
+ },
102
+
103
+ set(newValue) {
104
+ if (
105
+ (this.$el && this.$el.id !== this.id) ||
106
+ newValue.constructor !== Array
107
+ )
108
+ return
109
+
110
+ this.$emit('update:modelValue', newValue)
111
+ }
112
+ },
113
+ /**
114
+ * internal reactive value that map the options to add SELECTED attribute on each option
115
+ * this attribute value can be changed when user select the option
116
+ */
117
+ mappedOptions() {
118
+ const options = this.inputData.map((op) => {
119
+ const selectedItem = this.modelValue.find((i) => i.id === op.id)
120
+ return {
121
+ ...op,
122
+ selected: selectedItem ? selectedItem.selected : false
123
+ }
124
+ })
125
+
126
+ return options
127
+ }
128
+ },
129
+ watch: {
130
+ inputsValue: {
131
+ handler(newVal) {
132
+ this.$emit('enable-submit', newVal.length > 0)
133
+ },
134
+ deep: true,
135
+ immediate: true
136
+ }
137
+ },
138
+ created() {
139
+ if (import.meta.env.DEV) {
140
+ let errors = this.validateInputData()
141
+
142
+ if (errors && errors.errorList.length)
143
+ return this.$bus.$emit('input-error', { e: this.id, errors })
144
+ }
145
+
146
+ this.quizInputDataValue = this.inputData
147
+ },
148
+ mounted() {},
149
+
150
+ methods: {
151
+ /**
152
+ * @description validate the raw data received by the component to render is view
153
+ * @returns {Object} errors - errorList: to display in view and errorConsole, to be displayed in console
154
+ */
155
+ validateInputData() {
156
+ let errors = null //array for errors dectected
157
+ let stringType = ['id', 'value']
158
+
159
+ if (!this.inputData.length) return errors
160
+ for (let i = 0; i < this.inputData.length; i++) {
161
+ errors = validateObjType(
162
+ this.inputData[i],
163
+ { stringType },
164
+ null,
165
+ `choix_reponse #${i + 1}`
166
+ )
167
+ const { errorList, errorInConsole } = errors
168
+
169
+ if (errorList.length || errorInConsole.length) return errors
170
+ }
171
+
172
+ return errors
173
+ },
174
+
175
+ /**
176
+ * @description inicate wether the element is checked or not.
177
+ * Element is selected if in the modelValue
178
+ * @param value value of tje element to be checked
179
+ */
180
+ isSelected(value) {
181
+ const existing = this.modelValue.includes(value)
182
+ return existing
183
+ },
184
+
185
+ /**
186
+ * @description Method to force update of this.inputsValue.
187
+ * this force the old value and new value of the input to be tracked by VUE.
188
+ * @param newValue, the new value of the input
189
+ * @param index index of the selected element
190
+ */
191
+ onSelectUpdate(event, value) {
192
+ if (this.$el && this.$el.id !== this.id) return //prevent event from firing on other input
193
+
194
+ const isChecked = event.target.checked
195
+ this.resetRetroStyle([this.retro, this.messageAccessibility])
196
+ let updatedValue = [...this.modelValue]
197
+
198
+ if (isChecked) {
199
+ const existing = updatedValue.includes(value)
200
+ if (!existing) updatedValue.push(value)
201
+ } else updatedValue = updatedValue.filter((v) => v !== value)
202
+
203
+ this.$emit('update:modelValue', updatedValue)
204
+ },
205
+ /**
206
+ * @description Component validation method to validate the user input against the solution
207
+ * can handle logic of Css style to apply (correct/wrong Answer) and return the result
208
+ * @return {Object} result
209
+ */
210
+ validateAnswer() {
211
+ // Validate the user answer
212
+ //Created a custom validated object for inputData
213
+ let mappedResults
214
+ if (this.solution != null) {
215
+ mappedResults = this.inputData.map(
216
+ (a) =>
217
+ (a = {
218
+ ...a,
219
+ correct: this.solution.includes(a.id)
220
+ })
221
+ )
222
+ } else {
223
+ mappedResults = this.inputData.map(
224
+ (a) =>
225
+ (a = {
226
+ ...a,
227
+ correct: null
228
+ })
229
+ )
230
+ }
231
+
232
+ let { classRetro, mesA11y } = this.addRetroStyle(
233
+ this.solution,
234
+ mappedResults,
235
+ this.inputData.length
236
+ )
237
+
238
+ this.retro = classRetro
239
+ this.messageAccessibility = mesA11y
240
+
241
+ //filer mapped to return a customized object of the user selection
242
+ this.result = mappedResults
243
+ .filter((a) => this.inputsValue.includes(a.value))
244
+ .map((a) => {
245
+ const { id, value, correct } = a
246
+ return { id, selected: value, correct }
247
+ })
248
+
249
+ let retro = this.retroType(this.solution, this.result)
250
+
251
+ let cAns
252
+ if (this.solution != null) cAns = this.computeResult(this.result)
253
+ else cAns = false
254
+
255
+ //Object to return validation to parent
256
+ return {
257
+ userAnswer: this.result,
258
+ correctAnswer: cAns,
259
+ retroType: retro
260
+ }
261
+ },
262
+ /**
263
+ * @description - compute the correct elements in user response
264
+ * compare with the solution and return wether user succeeded or failed
265
+ * @param {Object} result - user responses
266
+ * @retuns boolean
267
+ */
268
+ computeResult(result) {
269
+ const res = this.result.filter((el) => el.correct)
270
+
271
+ return (
272
+ res.length == this.solution.length &&
273
+ this.solution.length == this.result.length
274
+ )
275
+ }
276
+ }
277
+ }
278
+ </script>
279
+ <style lang="scss">
280
+ fieldset {
281
+ border: inherit;
282
+ }
283
+
284
+ .custom-control-input:focus ~ .custom-control-label::before {
285
+ border: inherit;
286
+ }
287
+
288
+ .custom-control-input:focus ~ .custom-control-label::before {
289
+ box-shadow: inherit;
290
+ -webkit-box-shadow: inherit;
291
+ }
292
+
293
+ fieldset {
294
+ border: inherit;
295
+ }
296
+
297
+ .custom-checkbox {
298
+ width: 100%;
299
+ height: 100%;
300
+ padding-left: 0;
301
+
302
+ input {
303
+ width: 100%;
304
+ height: 100%;
305
+ }
306
+
307
+ label {
308
+ width: 100%;
309
+ height: 100%;
310
+
311
+ &:after,
312
+ &:before {
313
+ border: inherit;
314
+ top: 0px;
315
+ left: 0px;
316
+ height: 0;
317
+ width: 0;
318
+ background-color: inherit;
319
+ border: inherit;
320
+ }
321
+ }
322
+ }
323
+ </style>
@@ -0,0 +1,299 @@
1
+ <!-- About this Component--
2
+ * Renders a SELECT input to display choices of response for the Quiz component
3
+ * Related Quiz to question: DROPDOWN
4
+ * Receives the a data object defined by user
5
+ * Used by AppCompQuiz
6
+ * Uses useQuiz composable
7
+ -->
8
+ <template>
9
+ <div v-if="inputData.length > 0" :id="id" class="input-box">
10
+ <fieldset :aria-label="fieldsetLabel">
11
+ <div
12
+ v-for="(singleDropdown, index) in inputData"
13
+ :key="singleDropdown.id"
14
+ class="dropdown-container"
15
+ :class="`dropdownlist-${singleDropdown.id}`"
16
+ >
17
+ <label
18
+ :id="`label_dropdown_${id}_${singleDropdown.id}`"
19
+ :for="`dropdown_${id}_${singleDropdown.id}`"
20
+ v-html="singleDropdown.ennonce"
21
+ ></label>
22
+
23
+ <div class="cnt-input" :class="`${retro[index] ? retro[index] : ''}`">
24
+ <v-select
25
+ :id="`dropdown_${id}_${singleDropdown.id}`"
26
+ :model-value="inputsValue[singleDropdown.id]"
27
+ item-title="text"
28
+ :item-props="true"
29
+ :items="getItemOptions(index)"
30
+ :open-text="`${$t('message.dropdown_list')}_${singleDropdown.ennonce}`"
31
+ :aria-describedby="`${id}_${singleDropdown.id}-msg-erreur`"
32
+ @update:model-value="onSelectUpdate($event, index)"
33
+ ></v-select>
34
+
35
+ <span
36
+ :id="`${id}_${singleDropdown.id}-msg-erreur`"
37
+ :key="`msg_chx_${id}_${singleDropdown.id}`"
38
+ class="sr-only"
39
+ >
40
+ {{ messageAccessibility[index] }}
41
+ </span>
42
+ </div>
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: 'AppCompInputDropdown',
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
+ solution: {
63
+ type: Array,
64
+ default: () => []
65
+ },
66
+ id: {
67
+ type: String,
68
+ default: ''
69
+ }
70
+ },
71
+ emits: ['update:modelValue', 'enable-submit'],
72
+ setup(props) {
73
+ const { retroType, addRetroStyle, resetRetroStyle } = useQuiz()
74
+
75
+ return { retroType, addRetroStyle, resetRetroStyle }
76
+ },
77
+ data() {
78
+ return {
79
+ retro: [],
80
+ messageAccessibility: [],
81
+ result: [],
82
+ oldValue: null
83
+ }
84
+ },
85
+ computed: {
86
+ fieldsetLabel() {
87
+ let label
88
+ if (this.inputData.length === 1) {
89
+ label = this.$t('quizState.dropdownFieldsetSingle')
90
+ } else {
91
+ label = `${this.$t('quizState.dropdownFieldsetMulti1')} ${this.inputData.length} ${this.$t('quizState.dropdownFieldsetMulti2')}`
92
+ }
93
+ return label
94
+ },
95
+ /* INTERNAL REACTIVE VALUE THAT BIND WITH MODELVALUE PROPS */
96
+ inputsValue: {
97
+ get() {
98
+ return this.modelValue
99
+ },
100
+ set(newValue) {
101
+ this.$emit('update:modelValue', [...newValue])
102
+ }
103
+ },
104
+ mappedOptions() {
105
+ if (this.inputData.length === 0) return []
106
+
107
+ return this.inputData.map((op) => {
108
+ const key = Object.keys(op)[0]
109
+ const values = Object.values(op)[2]
110
+
111
+ const newValues = [
112
+ {
113
+ value: null,
114
+ disabled: true,
115
+ selected: true,
116
+ text: this.$t('message.first_option_dropdown')
117
+ // text: 'choisir une option'
118
+ },
119
+ ...values.map((el) => ({
120
+ value: el,
121
+ text: el,
122
+ selected: false
123
+ }))
124
+ ]
125
+
126
+ return {
127
+ [key]: newValues
128
+ }
129
+ })
130
+ }
131
+ },
132
+ watch: {
133
+ inputsValue: {
134
+ handler() {
135
+ if (this.$el && this.$el.id !== this.id) return
136
+ const filled = this.modelValue.filter((val) => val && val.trim() !== '')
137
+
138
+ this.$emit('enable-submit', filled.length === this.inputData.length)
139
+ },
140
+ deep: true,
141
+ immediate: true
142
+ }
143
+ },
144
+ created() {
145
+ if (import.meta.env.DEV) {
146
+ let errors = this.validateInputData()
147
+ if (errors && errors.errorList.length) {
148
+ return this.$bus.$emit('input-error', { e: this.id, errors })
149
+ }
150
+ }
151
+ },
152
+ mounted() {},
153
+
154
+ methods: {
155
+ validateInputData() {
156
+ let errors = null
157
+ let stringType = ['id', 'ennonce']
158
+ let arrayType = ['option']
159
+ let e = null
160
+
161
+ if (!this.inputData.length) return errors
162
+ for (let i = 0; i < this.inputData.length; i++) {
163
+ e = validateObjType(
164
+ this.inputData[i],
165
+ { stringType, arrayType },
166
+ null,
167
+ `liste déroulante #${i + 1}`
168
+ )
169
+
170
+ if (e.errorInConsole.length && e.errorList.length) {
171
+ errors.errorInConsole.push(e.errorInConsole[0])
172
+ errors.errorList.push(e.errorList[0])
173
+ }
174
+ }
175
+
176
+ return errors
177
+ },
178
+ /**
179
+ * @description Method to retrive the options of each selectable input in the mappedOption Object
180
+ * @param {Number } index - number representing the index of the item in the array of inputElements
181
+ * @Return a collection of item representing the options for a the selectables
182
+ */
183
+ getItemOptions(index) {
184
+ return Object.values(this.mappedOptions[index])[0]
185
+ },
186
+ /**
187
+ * @description Method to force update of this.inputsValue.
188
+ * this force the old value and new value of the input to be tracked by VUE.
189
+ * @param newValue, the new value of the input
190
+ * @param index index of the selected element
191
+ */
192
+
193
+ onSelectUpdate(newValue, index) {
194
+ if (this.$el && this.$el.id !== this.id) return //prevent event from firing on other input
195
+ this.resetRetroStyle([this.retro, this.messageAccessibility])
196
+ const updated = [...this.inputsValue] //create new array from inputsValue
197
+ updated[index] = newValue
198
+ this.inputsValue = updated //trigger vue reactivity for inputsValue
199
+ },
200
+ /**
201
+ * @description Component validation method to validate the user input against the solution
202
+ * can handle logic of Css style to apply (correct/wrong Answer) and return the result
203
+ * @return {Object} result
204
+ */
205
+ validateAnswer() {
206
+ let mappedResults
207
+ if (this.solution != null) {
208
+ mappedResults = this.inputsValue.map((a, i) => {
209
+ const s = this.solution[i]
210
+ return { selected: a, correct: s == a }
211
+ })
212
+ } else {
213
+ mappedResults = this.inputsValue.map((a, i) => {
214
+ return { selected: a, correct: false }
215
+ })
216
+ }
217
+
218
+ let { classRetro, mesA11y } = this.addRetroStyle(
219
+ this.solution,
220
+ mappedResults,
221
+ this.inputData.length
222
+ )
223
+
224
+ this.retro = [...classRetro]
225
+ this.messageAccessibility = [...mesA11y]
226
+
227
+ this.retro = classRetro
228
+ this.messageAccessibility = mesA11y
229
+
230
+ this.result = mappedResults.filter((a) => a.selected)
231
+ let tr = this.retroType(this.solution, this.result)
232
+
233
+ let cAns
234
+ if (this.solution != null) cAns = this.computeResult(this.result)
235
+ else cAns = false
236
+
237
+ return {
238
+ userAnswer: this.result,
239
+ correctAnswer: cAns,
240
+ retroType: tr
241
+ }
242
+ },
243
+ computeResult(result) {
244
+ const res = result.filter((el) => el.correct)
245
+ return res.length == this.solution.length
246
+ }
247
+ }
248
+ }
249
+ </script>
250
+ <style lang="scss">
251
+ .dropdown-container {
252
+ position: relative;
253
+ }
254
+
255
+ fieldset {
256
+ border: inherit;
257
+ }
258
+
259
+ div.texteatrou {
260
+ display: inline !important;
261
+ .cnt-input {
262
+ display: inline;
263
+
264
+ .v-input {
265
+ display: inline-block !important;
266
+
267
+ .v-input__control,
268
+ .v-field {
269
+ width: 240px !important;
270
+ grid-area: inherit !important;
271
+
272
+ .v-field__field {
273
+ height: 25px !important;
274
+ padding: 0 !important;
275
+ min-height: inherit !important;
276
+
277
+ .v-field__input {
278
+ padding-top: 0 !important;
279
+ padding-bottom: 0 !important;
280
+ min-height: inherit !important;
281
+
282
+ .v-select__selection {
283
+ min-height: inherit !important;
284
+ }
285
+ }
286
+ }
287
+
288
+ .v-field__append-inner {
289
+ margin-right: 6px;
290
+ }
291
+ }
292
+
293
+ .v-input__details {
294
+ display: none;
295
+ }
296
+ }
297
+ }
298
+ }
299
+ </style>