fcad-core-dragon 2.0.1 → 2.0.2-beta.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 (90) hide show
  1. package/.editorconfig +33 -33
  2. package/.eslintignore +29 -29
  3. package/.eslintrc.cjs +81 -81
  4. package/CHANGELOG +17 -1
  5. package/bk.scss +117 -117
  6. package/package.json +1 -1
  7. package/src/$locales/en.json +18 -4
  8. package/src/$locales/fr.json +17 -3
  9. package/src/assets/data/onboardingMessages.json +47 -47
  10. package/src/components/AppBase.vue +36 -341
  11. package/src/components/AppBaseErrorDisplay.vue +438 -438
  12. package/src/components/AppBaseFlipCard.vue +84 -84
  13. package/src/components/AppBaseModule.vue +16 -21
  14. package/src/components/AppBasePage.vue +45 -14
  15. package/src/components/AppBasePopover.vue +41 -41
  16. package/src/components/AppBaseSkeleton.vue +45 -0
  17. package/src/components/AppCompAudio.vue +12 -3
  18. package/src/components/AppCompButtonProgress.vue +13 -2
  19. package/src/components/AppCompCarousel.vue +12 -4
  20. package/src/components/AppCompInputCheckBoxNx.vue +324 -0
  21. package/src/components/AppCompInputDropdownNx.vue +295 -0
  22. package/src/components/AppCompInputRadioNx.vue +264 -0
  23. package/src/components/AppCompInputTextNx.vue +148 -0
  24. package/src/components/AppCompInputTextTableNx.vue +198 -0
  25. package/src/components/AppCompInputTextToFillDropdownNx.vue +291 -0
  26. package/src/components/AppCompInputTextToFillNx.vue +277 -0
  27. package/src/components/AppCompJauge.vue +11 -4
  28. package/src/components/AppCompMenu.vue +7 -14
  29. package/src/components/AppCompMenuItem.vue +7 -5
  30. package/src/components/AppCompNavigation.vue +21 -21
  31. package/src/components/AppCompNoteCall.vue +1 -0
  32. package/src/components/AppCompNoteCredit.vue +2 -1
  33. package/src/components/AppCompPlayBarNext.vue +94 -41
  34. package/src/components/AppCompPlayBarProgress.vue +82 -82
  35. package/src/components/AppCompPopUpNext.vue +6 -6
  36. package/src/components/AppCompQuiz.vue +500 -0
  37. package/src/components/AppCompQuizRecall.vue +113 -66
  38. package/src/components/AppCompSettingsMenu.vue +172 -172
  39. package/src/components/AppCompTableOfContent.vue +39 -10
  40. package/src/components/AppCompVideoPlayer.vue +1 -1
  41. package/src/components/AppCompViewDisplay.vue +6 -6
  42. package/src/composables/useQuiz.js +62 -179
  43. package/src/directives/nvdaFix.js +53 -0
  44. package/src/externalComps/ModuleView.vue +22 -22
  45. package/src/externalComps/SummaryView.vue +91 -91
  46. package/src/main.js +227 -30
  47. package/src/mixins/$mediaMixins.js +1 -11
  48. package/src/module/stores/appStore.js +29 -11
  49. package/src/module/xapi/Crypto/Hasher.js +241 -241
  50. package/src/module/xapi/Crypto/WordArray.js +278 -278
  51. package/src/module/xapi/Crypto/algorithms/BufferedBlockAlgorithm.js +103 -103
  52. package/src/module/xapi/Crypto/algorithms/C_algo.js +315 -315
  53. package/src/module/xapi/Crypto/algorithms/HMAC.js +9 -9
  54. package/src/module/xapi/Crypto/algorithms/SHA1.js +9 -9
  55. package/src/module/xapi/Crypto/encoders/Base.js +105 -105
  56. package/src/module/xapi/Crypto/encoders/Base64.js +99 -99
  57. package/src/module/xapi/Crypto/encoders/Hex.js +61 -61
  58. package/src/module/xapi/Crypto/encoders/Latin1.js +61 -61
  59. package/src/module/xapi/Crypto/encoders/Utf8.js +45 -45
  60. package/src/module/xapi/Crypto/index.js +53 -53
  61. package/src/module/xapi/Statement/activity.js +47 -47
  62. package/src/module/xapi/Statement/agent.js +55 -55
  63. package/src/module/xapi/Statement/group.js +26 -26
  64. package/src/module/xapi/Statement/index.js +259 -259
  65. package/src/module/xapi/Statement/statement.js +253 -253
  66. package/src/module/xapi/Statement/statementRef.js +23 -23
  67. package/src/module/xapi/Statement/substatement.js +22 -22
  68. package/src/module/xapi/Statement/verb.js +36 -36
  69. package/src/module/xapi/activitytypes.js +17 -17
  70. package/src/module/xapi/utils.js +167 -167
  71. package/src/module/xapi/verbs.js +294 -294
  72. package/src/module/xapi/xapiStatement.js +444 -444
  73. package/src/plugins/bus.js +8 -8
  74. package/src/plugins/gsap.js +14 -14
  75. package/src/plugins/i18n.js +44 -44
  76. package/src/plugins/idb.js +1 -1
  77. package/src/plugins/save.js +37 -37
  78. package/src/plugins/scorm.js +287 -287
  79. package/src/plugins/xapi.js +11 -11
  80. package/src/public/index.html +33 -33
  81. package/src/shared/generalfuncs.js +134 -0
  82. package/src/shared/validators.js +308 -234
  83. package/src/components/AppCompInputCheckBoxNext.vue +0 -205
  84. package/src/components/AppCompInputDropdownNext.vue +0 -201
  85. package/src/components/AppCompInputRadioNext.vue +0 -158
  86. package/src/components/AppCompInputTextNext.vue +0 -124
  87. package/src/components/AppCompInputTextTableNext.vue +0 -142
  88. package/src/components/AppCompInputTextToFillDropdownNext.vue +0 -238
  89. package/src/components/AppCompInputTextToFillNext.vue +0 -171
  90. package/src/components/AppCompQuizNext.vue +0 -2908
@@ -0,0 +1,291 @@
1
+ <!-- About this Component--
2
+ * Renders a Series of inputs to collect input for the Quiz component.
3
+ * Related Quiz to question: TEXTE_TROUE_SELECT
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="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
+ <div
24
+ v-if="textInput.type == 'select'"
25
+ class="cnt-input"
26
+ :class="`${retro[textInput.id.substr(textInput.id.length - 1)] ? retro[textInput.id.substr(textInput.id.length - 1)] : ''}`"
27
+ >
28
+ <v-select
29
+ :id="`${id}_${textInput.id}-champ`"
30
+ :model-value="inputsValue[textInput.index]"
31
+ item-title="text"
32
+ :open-text="`${$t('message.dropdown_list')}`"
33
+ :item-props="true"
34
+ :items="getItemOptions(textInput.index)"
35
+ :aria-describedby="`${id}_${textInput.id}-msg-erreur`"
36
+ :aria-labelledby="`${id}_${textInput.id}-label`"
37
+ @update:model-value="onSelectUpdate($event, textInput.index)"
38
+ />
39
+ <span
40
+ :id="`${id}_${textInput.id}-msg-erreur`"
41
+ :key="`msg_chx_${id}_${textInput.id}`"
42
+ class="sr-only"
43
+ >
44
+ {{ messageAccessibility[textInput.index] }}
45
+ </span>
46
+ </div>
47
+ </div>
48
+ </fieldset>
49
+ </div>
50
+ </template>
51
+ <script>
52
+ import { useQuiz } from '../composables/useQuiz'
53
+ export default {
54
+ name: 'AppCompInputTextToFillDropdownNext',
55
+ /* PROPS USED FOR PARENT TO COMMUNICATE DATA TO CHILD */
56
+ props: {
57
+ modelValue: {
58
+ type: Array,
59
+ default: () => []
60
+ },
61
+ inputData: {
62
+ type: Array,
63
+ default: () => []
64
+ },
65
+ textBase: {
66
+ type: String,
67
+ default: ''
68
+ },
69
+ solution: {
70
+ type: Array,
71
+ default: () => []
72
+ },
73
+
74
+ id: {
75
+ type: String,
76
+ default: ''
77
+ }
78
+ },
79
+ emits: ['update:modelValue', 'enable-submit'],
80
+ setup(props) {
81
+ const { retroType, addRetroStyle, resetRetroStyle } = useQuiz()
82
+
83
+ return { retroType, addRetroStyle, resetRetroStyle }
84
+ },
85
+ data() {
86
+ return {
87
+ inputElements: [],
88
+ result: [],
89
+ retro: [],
90
+ messageAccessibility: [],
91
+ inputCount: null
92
+ }
93
+ },
94
+ computed: {
95
+ fieldsetLabel() {
96
+ return `${this.$t('quizState.textToFillDropdownFieldset1')} ${this.inputCount} ${this.$t('quizState.textToFillDropdownFieldset2')}`
97
+ },
98
+ /* INTERNAL REACTIVE VALUE THAT BIND WITH MODELVALUE PROPS */
99
+ inputsValue: {
100
+ get() {
101
+ return this.modelValue
102
+ },
103
+ set(newValue) {
104
+ this.resetRetroStyle([this.retro, this.messageAccessibility])
105
+ this.$emit('update:modelValue', [...newValue])
106
+ }
107
+ },
108
+ /**
109
+ * internal reactive value that map the options to add SELECTED attribute on each option
110
+ * and Add entrie for the default selected Elements
111
+ * this attribute value can be changed when user select the option
112
+ */
113
+ mappedOptions() {
114
+ return this.inputData.map((op) => {
115
+ const key = Object.keys(op)[0]
116
+ const values = Object.values(op)[0]
117
+
118
+ const newValues = [
119
+ {
120
+ value: null,
121
+ disabled: true,
122
+ selected: true,
123
+ text: this.$t('message.first_option_dropdown')
124
+ },
125
+ ...values.map((el) => ({
126
+ value: el,
127
+ text: el,
128
+ selected: false
129
+ }))
130
+ ]
131
+
132
+ return {
133
+ [key]: newValues
134
+ }
135
+ })
136
+ }
137
+ },
138
+ watch: {
139
+ /**
140
+ * @description watcher to track the inputs content
141
+ * remove an element from the inputs array (modelValue) when it is empty
142
+ */
143
+ inputsValue: {
144
+ handler() {
145
+ const filledCount = this.modelValue.filter(
146
+ (val) => val !== null && val !== undefined
147
+ )
148
+
149
+ this.$emit('enable-submit', filledCount.length == this.inputData.length)
150
+ },
151
+ deep: true,
152
+ immediate: true
153
+ }
154
+ },
155
+
156
+ mounted() {},
157
+ created() {
158
+ this.createTextWithInput(this.textBase)
159
+ },
160
+
161
+ methods: {
162
+ /**
163
+ * @description create the object to generate the text and selects options
164
+ * for each fillable input. The created object is assigned to inputElements
165
+ * @param {String} str the text with holes to fill
166
+ */
167
+ createTextWithInput(str) {
168
+ const regex = /\$%\S*%\$/g // regex pattern to match exp: $%number%$
169
+
170
+ let splittedText = str.split(regex)
171
+ let listInput = []
172
+
173
+ for (let i = 0; i < splittedText.length - 1; i++) {
174
+ listInput.push({
175
+ id: `text-${i}`,
176
+ type: 'text',
177
+ content: splittedText[i]
178
+ })
179
+
180
+ if (i < splittedText.length - 1)
181
+ listInput.push({ id: `select-${i}`, type: 'select', index: i })
182
+ }
183
+ let lI = listInput.findLast((element) => element.type == 'select')
184
+ this.inputCount = lI.index + 1
185
+
186
+ this.inputElements = listInput
187
+ },
188
+ /**
189
+ * @description Method to force update of this.inputsValue.
190
+ * this force the old value and new value of the input to be tracked by VUE.
191
+ * @param newValue, the new value of the input
192
+ * @param index index of the selected element
193
+ */
194
+
195
+ onSelectUpdate(newValue, index) {
196
+ if (this.$el && this.$el.id !== this.id) return //prevent event from firing on other input
197
+ this.resetRetroStyle([this.retro, this.messageAccessibility])
198
+ const updated = [...this.inputsValue] //create new array from inputsValue
199
+ updated[index] = newValue
200
+ this.inputsValue = updated //trigger vue reactivity for inputsValue
201
+ },
202
+
203
+ /**
204
+ * @description Method to retrive the options of each selectable input in the mappedOption Object
205
+ * @param {Number } index - number representing the index of the item in the array of inputElements
206
+ * @Return a collection of item representing the options for a the selectables
207
+ */
208
+ getItemOptions(index) {
209
+ return Object.values(this.mappedOptions[index])[0]
210
+ },
211
+ /**
212
+ * @description Component validation method to validate the user input against the solution
213
+ * can handle logic of Css style to apply (correct/wrong Answer) and return the result
214
+ * @return {Object} result
215
+ */
216
+ validateAnswer() {
217
+ let mappedResults
218
+
219
+ if (this.solution != null) {
220
+ mappedResults = this.inputsValue.map((a, i) => {
221
+ const s = Object.values(this.solution[i])[0]
222
+ return { selected: a, correct: s == a }
223
+ })
224
+ } else {
225
+ mappedResults = this.inputsValue.map((a) => {
226
+ return { selected: a, correct: false }
227
+ })
228
+ }
229
+
230
+ //Set the valition style
231
+ let { classRetro, mesA11y } = this.addRetroStyle(
232
+ this.solution,
233
+ mappedResults,
234
+ this.inputsValue.length
235
+ )
236
+ this.retro = classRetro
237
+ this.messageAccessibility = mesA11y
238
+ //Retrive the user response from validation
239
+ this.result = mappedResults.filter((a) => a.selected)
240
+
241
+ let retro = this.retroType(this.solution, this.result)
242
+
243
+ let cAns
244
+ if (this.solution != null) cAns = this.computeResult(this.result)
245
+ else cAns = false
246
+ //Return this to parent
247
+ return {
248
+ userAnswer: this.result,
249
+ correctAnswer: cAns,
250
+ retroType: retro
251
+ }
252
+ },
253
+
254
+ /**
255
+ * @description - compute the correct elements in user response
256
+ * compare with the solution and return wether user succeeded or failed
257
+ * @param {Object} result - user responses
258
+ * @retuns boolean expressing the fail/success result
259
+ */
260
+ computeResult(result) {
261
+ const res = result.filter((el) => el.correct)
262
+ return res.length == this.solution.length
263
+ }
264
+ }
265
+ }
266
+ </script>
267
+ <style lang="scss" scoped>
268
+ select {
269
+ &.custom-select {
270
+ background-image: inherit;
271
+
272
+ &:focus {
273
+ border-color: inherit;
274
+ box-shadow: inherit;
275
+ }
276
+ }
277
+ }
278
+
279
+ /***** style dev *****/
280
+ .texteatrou {
281
+ display: inline;
282
+ }
283
+ .texteatrou > select {
284
+ display: inline;
285
+ width: auto;
286
+ }
287
+
288
+ .cnt-input {
289
+ position: relative;
290
+ }
291
+ </style>
@@ -0,0 +1,277 @@
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" scoped>
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
+ </style>
@@ -7,7 +7,7 @@
7
7
  :max="maxValue"
8
8
  aria-hidden="true"
9
9
  ></v-progress-linear>
10
- <p class="prcnt">{{ getPourcent }} %</p>
10
+ <p class="prcnt">{{ getPourcent }}</p>
11
11
  </div>
12
12
  <div v-else>
13
13
  <div class="warning">
@@ -20,6 +20,8 @@
20
20
  </div>
21
21
  </template>
22
22
  <script>
23
+ import { mapState } from 'pinia'
24
+ import { useAppStore } from '../module/stores/appStore'
23
25
  export default {
24
26
  props: {
25
27
  // props Give value to show progress
@@ -39,11 +41,16 @@ export default {
39
41
  return {}
40
42
  },
41
43
  computed: {
44
+ ...mapState(useAppStore, ['getAppConfigs']),
42
45
  getPourcent() {
43
46
  // Calculate on a 100%
44
- let result = (this.value * 100) / this.maxValue
45
- if (result > 100) return 100
46
- else return Math.round(result)
47
+ let result = Math.round((this.value * 100) / this.maxValue)
48
+
49
+ if (result > 100) result = 100
50
+
51
+ return this.getAppConfigs.lang.toLowerCase() == 'en'
52
+ ? `${result}%`
53
+ : `${result} %`
47
54
  },
48
55
  error() {
49
56
  if (typeof this.value != 'number' || typeof this.maxValue != 'number') {
@@ -56,6 +56,7 @@
56
56
  <app-base-button
57
57
  :id="`btn-quiz`"
58
58
  class="btn lk-btn"
59
+ title="Réinitialiser la leçon"
59
60
  :is-disabled="resetStatus !== false"
60
61
  @click="askResetUserData"
61
62
  >
@@ -105,8 +106,8 @@ export default {
105
106
  'getModuleInfo',
106
107
  'getMenuSettings',
107
108
  'getAppDebugMode',
108
- 'getAllCompleted',
109
- 'getDataFromServer'
109
+ 'getAppConfigs',
110
+ 'getAllCompleted'
110
111
  ]),
111
112
  appDebugMode() {
112
113
  return this.getAppDebugMode
@@ -171,17 +172,7 @@ export default {
171
172
  }
172
173
  }, 2000)
173
174
  },
174
- // GoToLastRoute() {
175
- // let lastRoute
176
- // //Get all activity state (menu not included)
177
-
178
- // //No route history Should link to introduction route
179
- // if (!this.getRouteHistory.length) return 'introduction'
180
- // //last Route should be the last element in route history
181
- // lastRoute = this.getRouteHistory.toReversed()[0]
182
- // //create the route link and return it
183
- // return this.createdRoute(lastRoute)
184
- // },
175
+ //Go to the last route you were before the menu
185
176
  GoToLastRoute() {
186
177
  let lastRoute
187
178
  let path
@@ -294,7 +285,9 @@ export default {
294
285
  // Create pourcentage complete
295
286
  progress = Math.round((pageCmplt * 100) / page)
296
287
 
297
- return `${progress}%`
288
+ return this.getAppConfigs.lang.toLowerCase() == 'en'
289
+ ? `${progress}%`
290
+ : `${progress} %`
298
291
  },
299
292
  askResetUserData() {
300
293
  //show loader animation
@@ -35,12 +35,14 @@
35
35
  </div>
36
36
 
37
37
  <div class="cnt-time">
38
- <svg :aria-label="$t('label.timer')">
38
+ <svg
39
+ :aria-label="$t('label.timer')"
40
+ aria-hidden="true"
41
+ focusable="false"
42
+ >
39
43
  <use href="#clock-icon" />
40
44
  </svg>
41
- <p class="time">
42
- {{ activity.time || '00:00' }}
43
- </p>
45
+ <p class="time">{{ activity.time || '00:00' }}</p>
44
46
  </div>
45
47
  <div class="box-gauge">
46
48
  <app-comp-jauge
@@ -76,7 +78,7 @@ export default {
76
78
  * Apply different punctuation for colons. No space before a colon in english, one space before a colon in french
77
79
  */
78
80
  cardTitleSeparator() {
79
- return this.getAppConfigs.lang === 'en' ? ': ' : ' : '
81
+ return this.getAppConfigs.lang.toLowerCase() == 'en' ? ': ' : ' : '
80
82
  },
81
83
  activities() {
82
84
  // get the data for list of the page for this module from the store and