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,1018 +1,1018 @@
1
- // Errors message to display in the console
2
- const ERR_TYPE = {
3
- err0: `\n 💥 Missing \x1B[1m$attr$ \x1B[0mfor $comp$. \x1B[1m$attr$ \x1B[0m should be provided with following attributes: \x1B[1m{$data$}`,
4
- err1: `\n 💥 Invalid declaration for \x1B[1m$wrd$ \x1B[0m object`,
5
- err2: `\n 💥 Invalid type declaration for 👉\x1B[1m$attr$ \x1B[0m👈 in \x1B[1m$el$\x1B[0m. Expected is \x1B[3m$type$ \x1B[0mtype with some value`,
6
- err3: `\n 💥 Missing required argument 👉\x1B[1m$key$\x1B[0m👈 in \x1B[1m$el$\x1B[0m. Required arguments are: \x1B[1m$args$`,
7
- err4: `\n 💥 Missing required argument 👉\x1B[1m$key$\x1B[0m👈 in \x1B[1m$el$\x1B[0m. Required arguments are: \x1B[1m$args$`
8
- }
9
-
10
- // Errors message to display in Appplication UI
11
- const ERR_TYPE_MSG = {
12
- err0: `\n Données manquantes pour <span style='text-transform: uppercase;'>$comp$</span>. Assurez-vous que le composant reçoit l'attribut <b>$attr$</b> avec des données pour: <b>$data$</b>`,
13
- err1: `\n Déclaration invalide pour <b>$wrd$</b>. Assurez-vous que l'application a du data.`,
14
- err2: `\n Vous avez une declaration invalide dans <b>$attr$</b>. 👉<b>$el$</b>👈 n'accepte que le type <i>$type$</i> et ne peut pas être vide`,
15
- err3: `\n L'attribut 👉<b>$key$</b>👈 est manquant dans <b>$el$</b>. Les attributs requis sont: <b>$args$</b>`
16
- }
17
-
18
- //Get all the invalids properties from the object
19
- /*Add element from target array that are NOT in arr to the wrongArray*/
20
- const checkerWrong = (arr, target) => {
21
- let wrongArray = []
22
- target.every((v) => {
23
- if (arr.includes(v)) {
24
- return true
25
- } else {
26
- wrongArray.push(v)
27
- return true
28
- }
29
- })
30
- return wrongArray
31
- }
32
- //Get all the required properties that are missing from the object
33
- /*Add element from the arr that are NOT in target arr to the missingArray*/
34
- const checkerMissing = (arr, target) => {
35
- let missingArray = []
36
- arr.every((v) => {
37
- if (target.includes(v)) {
38
- return true
39
- } else {
40
- missingArray.push(v)
41
- return true
42
- }
43
- })
44
- return missingArray
45
- }
46
-
47
- /**
48
- * @description - Method to validate that given object attributes hold expected types
49
- * @param {Object} Obj - object to validate
50
- * @param {Object} Args - List of expected type groups - each type group must be an array of attributes with the same type
51
- * @param {Array} notRequiredArgs - list of field that should be considered as optional in the object. Will not give error if not * provided but will be validated if they are present with wrong type or empty
52
- * @param {Array} compName - Name of the component- will be display in error message
53
- * @param {Array} err - list off errors to be added to
54
- * @return {Object} list of errors - {errorInConsole, errorList} : errorlist can be used to display messages on template and
55
- * errorInConsole to display messages in browser console
56
- * @exemple - Given $user= {name:'toto', username:'totoEscargot', id:'id001', age:23, books:['one', 'two', 'three'] }
57
- * Use validator on $user: validateObjType($user, {stringType:['name', 'username' , 'id'], numbType:['age'], arrayType:['books']})
58
- * Will fail if any listed attribute not in $user or have wrong value. Error messages will be in console
59
- *
60
- */
61
-
62
- const validateObjType = (
63
- Obj,
64
- Args = {
65
- boolType: null,
66
- arrayType: null,
67
- stringType: null,
68
- objectType: null,
69
- numbType: null
70
- },
71
- notRequiredArgs = null,
72
- compName = 'component',
73
- err = null
74
- ) => {
75
- let errorInConsole = err && err.errorInConsole ? err.errorInConsole : []
76
- let errorList = err && err.errorList ? err.errorLIst : []
77
- let optionalArgs =
78
- notRequiredArgs && notRequiredArgs.length ? notRequiredArgs : []
79
- //=====Expected Arguments validation =================//
80
- //Should have an object argument
81
- if (!Obj) throw new Error(`No valid arguments provided`)
82
-
83
- //List required attributes
84
- const required = []
85
-
86
- for (const _type in Args) {
87
- // Should be a required type
88
- if (
89
- ![
90
- 'boolType',
91
- 'arrayType',
92
- 'stringType',
93
- 'objectType',
94
- 'numberType'
95
- ].includes(_type)
96
- )
97
- throw new Error(`Unknown types declaration : ${_type}`)
98
-
99
- if (Args[_type] && Args[_type].length) {
100
- for (let el of Args[_type]) {
101
- //Check that each given element is a string
102
- if (el.constructor !== String)
103
- throw new Error(
104
- `Invalid type detected in ${JSON.stringify(
105
- Args[_type]
106
- )}. Item ${Args[_type].indexOf(el) + 1} should be a String`
107
- )
108
-
109
- if (!optionalArgs.includes(el)) required.push(el)
110
- }
111
- }
112
- }
113
-
114
- //validate Args Keys type
115
- for (const _type in Args) {
116
- for (let el of Args[_type]) {
117
- let reg = /(\$el\$)|(\$type\$)|(\$attr\$)/g
118
-
119
- switch (true) {
120
- // Check That each given element exist in data if not optional
121
- case Obj[el] === undefined && required.includes(el): {
122
- reg = /(\$key\$)|(\$el\$)|(\$args\$)/g
123
- const reg2 = /\[|\]|/g
124
-
125
- errorInConsole.push(
126
- ERR_TYPE.err3.replace(reg, (e) => {
127
- if (e == '$key$') return el
128
- if (e == '$el$') return compName
129
- if (e == '$args$') return JSON.stringify(required)
130
- })
131
- )
132
-
133
- errorList.push(
134
- ERR_TYPE_MSG.err3.replace(reg, (e) => {
135
- if (e == '$key$') return el
136
- if (e == '$el$') return compName || 'Composant'
137
- if (e == '$args$')
138
- return JSON.stringify(required).replaceAll(reg2, '')
139
- })
140
- )
141
- break
142
- }
143
- //Should have Correct Types $attr$ $el$ $type$
144
- case _type == 'boolType' &&
145
- Obj[el] !== undefined &&
146
- Obj[el].constructor !== Boolean:
147
- errorInConsole.push(
148
- ERR_TYPE.err2.replace(reg, (e) => {
149
- if (e == '$attr$') return compName || 'Composant'
150
- if (e == '$el$') return el
151
- if (e == '$type$') return 'Boolean'
152
- })
153
- )
154
- errorList.push(
155
- ERR_TYPE_MSG.err2.replace(reg, (e) => {
156
- if (e == '$attr$') return compName || 'Composant'
157
- if (e == '$el$') return el
158
- if (e == '$type$') return 'Boolean'
159
- })
160
- )
161
- break
162
-
163
- case _type == 'stringType' &&
164
- Obj[el] !== undefined &&
165
- (Obj[el].constructor !== String || !Obj[el].trim().length):
166
- errorInConsole.push(
167
- ERR_TYPE.err2.replace(reg, (e) => {
168
- if (e == '$attr$') return compName || 'Composant'
169
- if (e == '$el$') return el
170
- if (e == '$type$') return 'String'
171
- })
172
- )
173
- errorList.push(
174
- ERR_TYPE_MSG.err2.replace(reg, (e) => {
175
- if (e == '$attr$') return compName || 'Composant'
176
- if (e == '$el$') return el
177
- if (e == '$type$') return 'String'
178
- })
179
- )
180
- break
181
-
182
- case _type == 'arrayType' &&
183
- Obj[el] !== null &&
184
- Obj[el] !== undefined &&
185
- (Obj[el].constructor !== Array || !Obj[el].length):
186
- errorInConsole.push(
187
- ERR_TYPE.err2.replace(reg, (e) => {
188
- if (e == '$attr$') return compName || 'Composant'
189
- if (e == '$el$') return el
190
- if (e == '$type$') return 'Array'
191
- })
192
- )
193
- errorList.push(
194
- ERR_TYPE_MSG.err2.replace(reg, (e) => {
195
- if (e == '$attr$') return compName || 'Composant'
196
- if (e == '$el$') return el
197
- if (e == '$type$') return 'Array'
198
- })
199
- )
200
- break
201
-
202
- case _type == 'numberType' &&
203
- Obj[el] !== undefined &&
204
- Obj[el].constructor !== Number:
205
- errorInConsole.push(
206
- ERR_TYPE.err2.replace(reg, (e) => {
207
- if (e == '$attr$') return compName || 'Composant'
208
- if (e == '$el$') return el
209
- if (e == '$type$') return 'Number'
210
- })
211
- )
212
- errorList.push(
213
- ERR_TYPE_MSG.err2.replace(reg, (e) => {
214
- if (e == '$attr$') return compName || 'Composant'
215
- if (e == '$el$') return el
216
- if (e == '$type$') return 'Number'
217
- })
218
- )
219
- break
220
-
221
- case _type == 'objectType' &&
222
- Obj[el] !== undefined &&
223
- Obj[el].constructor !== Object:
224
- errorInConsole.push(
225
- ERR_TYPE.err2.replace(reg, (e) => {
226
- if (e == '$attr$') return compName || 'Composant'
227
- if (e == '$el$') return el
228
- if (e == '$type$') return 'Object'
229
- })
230
- )
231
- errorList.push(
232
- ERR_TYPE_MSG.err2.replace(reg, (e) => {
233
- if (e == '$attr$') return compName || 'Composant'
234
- if (e == '$el$') return el
235
- if (e == '$type$') return 'Object'
236
- })
237
- )
238
- break
239
- }
240
- }
241
- }
242
-
243
- return { errorInConsole, errorList }
244
- }
245
-
246
- /**
247
- * @description Validator for the content of menu setting file
248
- * @param {String} fName- name of the file for use case
249
- * @param {Object} fData: file's data to validate
250
- * @param {Object} [requiredArgs] list of arguments to include consider in validation ()
251
- */
252
- const validatefileContent = (fName, fData, requiredArgs = {}) => {
253
- let err = null
254
- if (import.meta.env.DEV) {
255
- switch (fName) {
256
- case 'menuSettings': {
257
- const {
258
- keys4Lesson,
259
- keys4ActivityMandatory,
260
- keys4ActivityOpt,
261
- keys4Anchors
262
- } = requiredArgs
263
-
264
- //*validate that data is an {Object}. if Not send error message
265
- if (fData.constructor !== Object)
266
- err = '💥Invalid file provided for menu settings'
267
- if (Object.keys(fData).length > 0) {
268
- const content = Object.keys(fData)
269
- //Check if lessonTitle exists
270
- if (typeof fData.lessonTitle === 'undefined') {
271
- err = `!!!! 💥 Missing 👉 lessonTitle 👈 variable in ➡ menu.setting.js \n 🚩 This variable is mandatory.`
272
- break
273
- }
274
- //Check if lessonNumber exists
275
- if (typeof fData.lessonNumber === 'undefined') {
276
- err = `!!!! 💥 Missing 👉 lessonNumber 👈 variable in ➡ menu.setting.js \n 🚩 This variable is mandatory.`
277
- break
278
- }
279
- if (content.length != keys4Lesson.length) {
280
- err = `!!!! 💥 Missing activity in➡ menu.setting.js \n 🚩Must declare all activity in menu.setting.js`
281
- break
282
- } else {
283
- for (let el of content) {
284
- //validate that the content of each entry is valide
285
- if (!keys4Lesson.includes(el)) {
286
- err = `!!!! 💥 invalid data provided for key 👉 ${el} 👈 in ➡ menu.setting.js \n 🚩 All activity must be listed and you must have a lesson title`
287
- break
288
- }
289
- }
290
- }
291
-
292
- // Validate that each entry has the required key
293
- if (!err) {
294
- const reg = /^A[0-9]{2}$/ // target only activities
295
- const contentActivities = content.filter((data) => data.match(reg)) //Get only the activities
296
-
297
- for (let el of contentActivities) {
298
- const entry = fData[el]
299
-
300
- const tabEntrykey = Object.keys(entry)
301
- //Validate that entry has optional key
302
- if (
303
- !tabEntrykey.includes(keys4ActivityOpt[0]) ||
304
- !tabEntrykey.includes(keys4ActivityOpt[1])
305
- ) {
306
- err = `💥 Missing 👉 ${keys4ActivityOpt[0]} or ${keys4ActivityOpt[1]} 👈 in ${el} in ➡ menu.setting.js \n 🚩One of thess two keys are mandatory : 👉 ${keys4ActivityOpt}`
307
- break
308
- }
309
-
310
- //Validate that entry has mandatory key
311
- for (let m of keys4ActivityMandatory) {
312
- if (!tabEntrykey.includes(m)) {
313
- err = `💥 Missing 👉 ${m} 👈 in ${el} in ➡ menu.setting.js \n 🚩All this key are mandatory : 👉 ${keys4ActivityMandatory}`
314
- break
315
- } else {
316
- switch (m) {
317
- case 'anchors':
318
- if (entry[m].constructor !== Array)
319
- err = `💥 Invalid anchors declaration for 👉 ${el} 👈 in ➡ menu.setting.j \n 🚩Must be of type {Array}`
320
- else {
321
- const anchors = entry.anchors
322
-
323
- for (let a of anchors) {
324
- //trow error if numbers of keys are not the same as required
325
- const a_numb = anchors.indexOf(a) + 1
326
- if (Object.keys(a).length !== keys4Anchors.length) {
327
- err = `💥 Invalid declaration in 👉anchor ${a_numb}👈 for ➡ ${el} in ➡ menu.setting.js \n 🚩 Allowed indexes are: 👉 ${keys4Anchors}`
328
- break
329
- }
330
- // Validated that required keys condition and type is met
331
- for (let k of keys4Anchors) {
332
- if (!a[k]) {
333
- err = `💥 Missing 👉 ${k} 👈 for anchor ${a_numb} ➡ ${el} ➡ menu.setting.js \n 🚩 Allowed indexes are: 👉 ${keys4Anchors}`
334
- } else if (a[k].constructor !== String) {
335
- err = `💥 Invalid 👉 ${k} 👈 declaration for anchor ${a_numb} ➡ ${el} ➡ menu.setting.js \n 🚩 Must be of type {String}`
336
- }
337
- if (err) break
338
- }
339
- if (err) break
340
- }
341
- }
342
-
343
- break
344
- default:
345
- if (entry[m].constructor !== String)
346
- err = `Invalid 👉 ${m} 👈 declaration for ➡ ${el} in ➡ menu.setting.js \n 🚩 Must be of type {String}`
347
- break
348
- }
349
- }
350
- }
351
- }
352
- }
353
- }
354
- break
355
- }
356
- }
357
- }
358
- return err
359
- }
360
-
361
- /**
362
- * @description Validator for the content of menu setting file
363
- * @param {Object} data- Object definition to validate
364
- **/
365
- const validateVideoData = (data) => {
366
- const errorList = []
367
- if (import.meta.env.DEV) {
368
- let errStringInConsole = null
369
- let errString = null
370
- const expectedKeys = [
371
- 'id',
372
- 'mSources',
373
- 'mSubtitles',
374
- 'mPoster',
375
- 'mTranscript'
376
- ]
377
-
378
- if (!data || data.constructor !== Object || Object.keys(data).length < 1) {
379
- errStringInConsole = `\n 💥 Invalid declaration for video element`
380
- console.warn(
381
- `%c WARNING!>>> VIDEO: ${errStringInConsole}`,
382
- 'background: orange; color: white; display: block; border-radius:5px; margin:5px;'
383
- )
384
- errString = `Declaration invalide pour Objet video.`
385
- errorList.push(errString)
386
- }
387
- //Must have mSources
388
- if (!data['mSources']) {
389
- errStringInConsole = ` Missing 👉 mSources 👈 declaration for video element`
390
-
391
- errString = `l'Attribut <b>mSources</b> pour l'Objet video n'est pas defini. `
392
- console.warn(
393
- `%c WARNING!>>> ${errStringInConsole}`,
394
- 'background: orange; color: white; display: block; border-radius:5px; margin:5px;'
395
- )
396
- errorList.push(errString)
397
- }
398
- //Must have id
399
- if (!data['id']) {
400
- errStringInConsole = ` Missing 👉 id 👈 declaration for video element`
401
-
402
- errString = `l'Attribut <b>id</b> pour l'objet video n'est pas defini. `
403
- console.warn(
404
- `%c WARNING!>>> ${errStringInConsole}`,
405
- 'background: orange; color: white; display: block; border-radius:5px; margin:5px;'
406
- )
407
- errorList.push(errString)
408
- }
409
- //Start validation of keys in data
410
- if (!errString) {
411
- expectedKeys.forEach((k) => {
412
- if (!data[k] && k !== 'mSources') return
413
-
414
- switch (k) {
415
- case 'id':
416
- if (data['id'].constructor !== String || data['id'].length < 1) {
417
- errStringInConsole =
418
- '\n 💥 Invalid type declaration for id.\n 🚩 Must be of type Array'
419
-
420
- errString = `l'Attribut <b>id</b> pour le media doit être de type <i>String</i>`
421
-
422
- errorList.push(errString)
423
- console.warn(
424
- `%c WARNING!>>> ${errStringInConsole}`,
425
- 'background: orange; color: white; display: block; border-radius:5px; margin:5px;'
426
- )
427
- }
428
- break
429
- case 'mSources':
430
- if (
431
- data['mSources'].constructor !== Array ||
432
- data['mSources'].length < 1
433
- ) {
434
- errStringInConsole =
435
- '\n 💥 Invalid type declaration for mSources.\n 🚩 Must be of type Array'
436
-
437
- errString = `l'Attribut 👉 mSources 👈 pour le media doit être de type Array`
438
-
439
- errorList.push(errString)
440
- console.warn(
441
- `%c WARNING!>>> ${errStringInConsole}`,
442
- 'background: orange; color: white; display: block; border-radius:5px; margin:5px;'
443
- )
444
- }
445
- break
446
-
447
- case 'mSubtitles':
448
- {
449
- //Validate required keys in Subtitle definition
450
- let expectedKeys = ['label', 'src', 'srclang']
451
- //we only accept one subtitle and must be defined as an Object with 3 keys
452
- if (
453
- data['mSubtitles'].constructor !== Array ||
454
- !data['mSubtitles'].length
455
- ) {
456
- errStringInConsole = `\n 💥 Invalid type declaration for mSubtitles.\n 🚩 Must be of type Array with at list one Object defined with: ${expectedKeys}`
457
-
458
- errString = `l'Attribut 👉 mSubtitles 👈 doit être de type Array avec au moins un Objet: {${expectedKeys}} `
459
-
460
- console.warn(
461
- `%c WARNING!>>> ${errStringInConsole}`,
462
- 'background: orange; color: white; display: block; border-radius:5px; margin:5px;'
463
- )
464
-
465
- return errorList.push(errString)
466
- }
467
- //Validate definition for each Subtitle Object
468
- for (const obj of data['mSubtitles']) {
469
- const objIndex = data['mSubtitles'].indexOf(obj)
470
- expectedKeys.forEach((expected) => {
471
- if (!obj[expected]) {
472
- errStringInConsole = `\n 💥 Missing key 👉 ${expected} 👈 for mSubtitles No.${
473
- objIndex + 1
474
- }.\n 🚩 required keys are: ${expectedKeys} `
475
-
476
- errString = `l'Attribut 👉 ${expected} 👈 pour le sous-titre No.${
477
- objIndex + 1
478
- } n'est pas défini`
479
-
480
- console.warn(
481
- `%c WARNING!>>> ${errStringInConsole}`,
482
- 'background: orange; color: white; display: block; border-radius:5px; margin:5px;'
483
- )
484
- return errorList.push(errString)
485
- }
486
-
487
- // Only none empty String type Accepted
488
- if (
489
- obj[expected].constructor === String &&
490
- obj[expected].trim().length
491
- )
492
- return
493
-
494
- errStringInConsole = `\n 💥 Invalid type declaration for 👉${expected}👈 in mSubtitles No.${
495
- objIndex + 1
496
- }.\n 🚩 Must be none-empty String `
497
-
498
- errString = `l'Attribut 👉${expected}👈 du sous-titre No.${
499
- objIndex + 1
500
- } doit être de type String et ne peut pas être vide. `
501
-
502
- console.warn(
503
- `%c WARNING!>>> ${errStringInConsole}`,
504
- 'background: orange; color: white; display: block; border-radius:5px; margin:5px;'
505
- )
506
-
507
- errorList.push(errString)
508
- })
509
- }
510
- }
511
- break
512
- case 'mPoster':
513
- //Only type String allowed and must not be empty
514
- if (
515
- data['mPoster'] &&
516
- data['mPoster'].constructor == String &&
517
- data['mPoster'].trim().length
518
- )
519
- return
520
-
521
- errStringInConsole = `\n 💥 Invalid type declaration for 👉 mPoster 👈.\n 🚩 Must be none-empty String `
522
-
523
- errString = `l'Attribut 👉 mPoster 👈 doit être de type String et ne peut pas être vide. `
524
-
525
- errorList.push(errString)
526
- console.warn(
527
- `%c WARNING!>>> VIDEO: ${errStringInConsole}`,
528
- 'background: orange; color: white; display: block; border-radius:5px; margin:5px;'
529
- )
530
-
531
- break
532
- case 'mTranscript':
533
- //Only type String allowed and must not be empty
534
- if (
535
- data['mTranscript'] &&
536
- data['mTranscript'].constructor == String &&
537
- data['mTranscript'].trim().length
538
- )
539
- return
540
-
541
- errStringInConsole = `\n 💥 Invalid type declaration for 👉 mTranscript 👈 .\n 🚩 Must be none-empty String `
542
-
543
- errString = `l'Attribut 👉 mTranscript 👈 doit être de type String et ne peut pas être vide. `
544
-
545
- console.warn(
546
- `%c WARNING!>>> VIDEO: ${errStringInConsole}`,
547
- 'background: orange; color: white; display: block; border-radius:5px; margin:5px;'
548
- )
549
- errorList.push(errString)
550
-
551
- break
552
- }
553
- })
554
- }
555
- }
556
- return errorList
557
- }
558
-
559
- /**
560
- * @description Validator for the content of audio props
561
- * @param {Object} data- Object definition to validate
562
- **/
563
- const validateAudioData = (data) => {
564
- const errorList = []
565
- let currentProperties = Object.getOwnPropertyNames(data)
566
- if (process.env.NODE_ENV === 'development') {
567
- //errorList.push('test')
568
-
569
- const requiredProperties = ['id', 'mTitle', 'mSources', 'mTranscript']
570
-
571
- const optionalProperties = ['mPoster', 'mAlt']
572
-
573
- const allProperties = [
574
- ...requiredProperties,
575
- ...optionalProperties,
576
- ...['__ob__']
577
- ]
578
-
579
- let errStringInConsole = null
580
- let errString = null
581
-
582
- //** Validate if data exist and is an object**/
583
- if (!data || data.constructor !== Object || Object.keys(data).length < 1) {
584
- errStringInConsole = `\n 💥 Invalid declaration for audio element`
585
- console.warn(
586
- `%c WARNING!>>> AUDIO: ${errStringInConsole}`,
587
- 'background: orange; color: white; display: block; border-radius:5px; margin:5px;'
588
- )
589
- errString = `Déclaration invalide pour Objet audData. Ce doit être un objet non vide.`
590
- errorList.push(errString)
591
- return errorList
592
- }
593
- //** Validate if all the properties are right**/
594
- let wrongProperties = checkerWrong(allProperties, currentProperties)
595
-
596
- if (wrongProperties.length > 0) {
597
- console.warn(
598
- `%c WARNING!>>> AppCompAudio : audData property ${wrongProperties} invalid. Required properties: ${requiredProperties} . Optional properties: ${optionalProperties}`,
599
- 'background: orange; color: white; display: block; margin:5px;'
600
- )
601
- errString = `Propriété invalide pour audData: ${wrongProperties}. Les propriétés requises sont: ${requiredProperties} et les propriétés facultatives sont: ${optionalProperties}`
602
- errorList.push(errString)
603
- return errorList
604
- }
605
-
606
- //** Validate if all the required properties are in the data */
607
- let missingRequired = checkerMissing(requiredProperties, currentProperties)
608
-
609
- if (missingRequired.length > 0) {
610
- console.warn(
611
- `%c WARNING!>>> AppCompAudio : audData missing required ${missingRequired} property. Required properties: ${requiredProperties} . Optional properties: ${optionalProperties}`,
612
- 'background: orange; color: white; display: block; margin:5px;'
613
- )
614
- errString = `Propriété requise manquante pour audData: <b>${missingRequired}</b>. Les propriétés requises sont: <i>${requiredProperties}</i> et les propriétés facultatives sont: <i>${optionalProperties}</i>`
615
- errorList.push(errString)
616
- return errorList
617
- }
618
- /***Validate data values */
619
- if (errorList.length == 0) {
620
- let invalidString = []
621
- let invalidArray = []
622
- let invalidProperties = []
623
- currentProperties.forEach((p) => {
624
- switch (p) {
625
- case 'mTitle':
626
- case 'mTranscript':
627
- case 'mPoster':
628
- case 'mAlt':
629
- if (data[p] && data[p].constructor == String) {
630
- data[p].trim().length == 0 ? invalidString.push(p) : ''
631
- } else {
632
- invalidString.push(p)
633
- }
634
- break
635
- case 'mSources': {
636
- if (data[p] && data[p].constructor == Array) {
637
- data[p].length == 0 ? invalidArray.push(p) : ''
638
- } else {
639
- invalidArray.push(p)
640
- }
641
- if (invalidArray.length === 0) {
642
- //Valider les attributs de mSources
643
- for (let i in data[p]) {
644
- let object = data[p][i]
645
- if ('src' in object && 'type' in object) {
646
- if (
647
- object['src'].constructor != String &&
648
- object['type'].constructor != String
649
- ) {
650
- invalidProperties.push(p)
651
- } else {
652
- object['src'].trim().length == 0
653
- ? invalidString.push(p)
654
- : ''
655
- object['type'].trim().length == 0
656
- ? invalidString.push(p)
657
- : ''
658
- }
659
- } else {
660
- invalidProperties.push(p)
661
- }
662
- }
663
- }
664
- break
665
- }
666
- }
667
- })
668
- //Display error for each type
669
- //String
670
- let sL = invalidString.length
671
- if (sL > 0) {
672
- errStringInConsole = `\n 💥 Invalid value type for 👉${invalidString}👈 \n 🚩 Must be none-empty String `
673
-
674
- errString = `${sL > 1 ? 'Les ' : "L'"}attribut${
675
- sL > 1 ? 's ' : ''
676
- } 👉${invalidString}👈 doi${
677
- sL > 1 ? 'ven' : ''
678
- }t être de type String et ne peu${sL > 1 ? 'ven' : ''}t pas être vide. `
679
-
680
- console.warn(
681
- `%c WARNING!>>> ${errStringInConsole}`,
682
- 'background: orange; color: white; display: block; border-radius:5px; margin:5px;'
683
- )
684
- errorList.push(errString)
685
- }
686
- //Array
687
- let aL = invalidArray.length
688
- if (aL > 0) {
689
- errStringInConsole = `\n 💥 Invalid value type for 👉${invalidArray}👈 \n 🚩 Must be none-empty Array`
690
-
691
- errString = `${aL > 1 ? 'Les ' : "L'"}attribut${
692
- aL > 1 ? 's ' : ''
693
- } 👉${invalidArray}👈 doi${
694
- sL > 1 ? 'ven' : ''
695
- }t être de type Array et ne peu${aL > 1 ? 'ven' : ''}t pas être vide. `
696
-
697
- console.warn(
698
- `%c WARNING!>>> ${errStringInConsole}`,
699
- 'background: orange; color: white; display: block; border-radius:5px; margin:5px;'
700
- )
701
- errorList.push(errString)
702
- }
703
- let pL = invalidProperties.length
704
- if (pL > 0) {
705
- errStringInConsole = `\n 💥 Invalid value type for 👉src and/or type👈 in mSources \n 🚩 They are required and must be none-empty strings`
706
-
707
- errString = `${pL > 1 ? 'Les ' : "L'"}attribut${
708
- pL > 1 ? 's ' : ''
709
- } 👉src and/or type👈 de mSources doi${
710
- sL > 1 ? 'ven' : ''
711
- }t être de type String et ne peu${pL > 1 ? 'ven' : ''}t pas être vide. `
712
-
713
- console.warn(
714
- `%c WARNING!>>> ${errStringInConsole}`,
715
- 'background: orange; color: white; display: block; border-radius:5px; margin:5px;'
716
- )
717
- errorList.push(errString)
718
- }
719
- }
720
- }
721
- return errorList
722
- }
723
-
724
- /**
725
- * @description Validator for the content of app data.
726
- * App data is used as setting for the application
727
- * @param {Object} data - the Object definition to validate
728
- * @param {Boolean} silent - if Validator should diplay error in console
729
- *
730
- **/
731
-
732
- const validateAppContent = (data, silent = false) => {
733
- let errorInConsole = []
734
- let errorList = []
735
-
736
- const requiredArgs = [
737
- 'lang',
738
- 'specification',
739
- 'id',
740
- 'crs_id',
741
- 'idb_id',
742
- 'no_menu',
743
- 'is_single_activity',
744
- 'auto_next_activity'
745
- ]
746
-
747
- //Validate not empty data
748
- if (Object.keys(data).length == 0) {
749
- const reg = /(\$comp\$)|(\$data\$)|(\$attr\$)/g
750
-
751
- errorInConsole.push(
752
- ERR_TYPE.err0.replace(reg, (e) => {
753
- if (e == '$comp$') return 'app-base'
754
- if (e == '$data$') return requiredArgs.toString().replaceAll(',', ', ')
755
- if (e == '$attr$') return 'app-config'
756
- })
757
- )
758
-
759
- errorList.push(
760
- ERR_TYPE_MSG.err0.replace(reg, (e) => {
761
- if (e == '$comp$') return 'app-base'
762
- if (e == '$data$') return requiredArgs.toString().replaceAll(',', ', ')
763
- if (e == '$attr$') return 'app-config'
764
- })
765
- )
766
-
767
- console.warn(errorInConsole[0])
768
-
769
- return errorList
770
- }
771
-
772
- let stringType = ['lang', 'specification', 'id', 'crs_id', 'idb_id']
773
- let boolType = [
774
- 'no_menu',
775
- 'is_single_activity',
776
- 'auto_next_activity',
777
- 'remote'
778
- ]
779
- let objectType = ['actor', 'linkedResource']
780
- let optionalArgs = ['remote', 'actor', 'linkedResource']
781
-
782
- const { errorInConsole: errCons, errorList: errList } = validateObjType(
783
- data,
784
- {
785
- stringType,
786
- boolType,
787
- objectType
788
- },
789
- optionalArgs,
790
- 'App.vue'
791
- )
792
-
793
- errorList = [...errorList, ...errList]
794
- errorInConsole = [...errorInConsole, ...errCons]
795
-
796
- //===========Optional Keys should be of correct type when declared =================//
797
- // Has actor defined
798
- if (data['actor']) {
799
- let { errorInConsole: err1, errorList: err2 } = validateObjType(
800
- data['actor'],
801
- {
802
- stringType: ['name', 'mbox']
803
- },
804
- 'actor'
805
- )
806
-
807
- errorList = [...errorList, ...err2]
808
- errorInConsole = [...errorInConsole, ...err1]
809
- }
810
- // Has LinkedResource defined
811
- if (data['linkedResource']) {
812
- let { errorInConsole: err1, errorList: err2 } = validateObjType(
813
- data['linkedResource'],
814
- {
815
- stringType: ['url', 'id']
816
- },
817
- 'linkedResource'
818
- )
819
-
820
- errorList = [...errorList, ...err2]
821
- errorInConsole = [...errorInConsole, ...err1]
822
- }
823
- // Has endpointConfig defined
824
- if (data['endpointConfig']) {
825
- let { errorInConsole: err1, errorList: err2 } = validateObjType(
826
- data['endpointConfig'],
827
- {
828
- stringType: ['auth', 'endpoint']
829
- },
830
- 'endpointConfig'
831
- )
832
- errorList = [...errorList, ...err2]
833
- errorInConsole = [...errorInConsole, ...err1]
834
- }
835
- //================== END Optional Keys ====================//
836
-
837
- //Should display error to console
838
- if (errorList.length && !silent) {
839
- let txt = '⚠️ You have the following Errors:'
840
- console.group(`%c ${txt}`, 'background:#ffc13a7d')
841
- errorInConsole.forEach((err) => console.warn(err))
842
- console.groupEnd()
843
- }
844
-
845
- return errorList
846
- }
847
-
848
- /**
849
- * @description - Method validate the definition of SVG data.
850
- * @param {Array || Object } SVGData - the data defining the SVG to render
851
- * @return true - if valid
852
- * */
853
-
854
- const validateSvgDefinition = (SVGData) => {
855
- //Should be Array of Object
856
- if (SVGData.constructor !== Array && SVGData.constructor !== Object)
857
- throw new Error('Unsupported Type for SVG data')
858
- let Errors = []
859
- let SVGDef = SVGData.constructor == Object ? new Array(SVGData) : SVGData
860
- //Should validate the entries for each SVG definition as the required entries
861
-
862
- for (const s_def of SVGDef) {
863
- let i = SVGDef.indexOf(s_def)
864
- let stringType = ['id', 'viewBox']
865
- let arrayType = ['paths']
866
- let { errorInConsole: errCons } = validateObjType(
867
- s_def,
868
- {
869
- stringType,
870
- arrayType
871
- },
872
- 'viewBox',
873
- `SVG ${i + 1}`
874
- )
875
- Errors.push(...errCons)
876
- if (errCons.length) {
877
- errCons.forEach((err) => console.warn(err))
878
- break
879
- }
880
-
881
- //Should validate that each element in the path attributes is an object of type string and has the id attribute
882
-
883
- for (const _path of s_def.paths) {
884
- let index = s_def.paths.indexOf(_path)
885
- if (_path.constructor !== Object)
886
- throw Error(
887
- `Unexpected definition for path ${index + 1} in SVG ${i + 1}. Expecting Object but received ${typeof _path}`
888
- )
889
-
890
- let stringType = ['d']
891
-
892
- let { errorInConsole: errCons } = validateObjType(
893
- _path,
894
- {
895
- stringType
896
- },
897
- null,
898
- `SVG path ${index + 1}`
899
- )
900
- Errors.push(...errCons)
901
- if (errCons.length) {
902
- errCons.forEach((err) => console.warn(err))
903
- break
904
- }
905
-
906
- //validate each entries in path
907
- for (const _key in _path) {
908
- if (_key == 'd') continue //skip
909
- //all keys in path should be of type String and not empty
910
- let stringType = [_key]
911
-
912
- let { errorInConsole: errCons } = validateObjType(
913
- _path,
914
- {
915
- stringType
916
- },
917
- null,
918
- `SVG path ${index + 1}`
919
- )
920
- Errors.push(...errCons)
921
- if (errCons.length) {
922
- errCons.forEach((err) => console.log(err))
923
- break
924
- }
925
- }
926
- }
927
- }
928
-
929
- if (Errors.length) throw new Error('Error SVG')
930
- return true
931
- }
932
-
933
- /**
934
- * @description - Method validate the definition data forthe quiz.
935
- * @param {Object} data - the data defining the SVG to render
936
- * @return true - if valid
937
- * */
938
- const validateQuizData = (data) => {
939
- let errors
940
- let stringType = ['ennonce', 'id', 'type_question', 'texte_base']
941
- let arrayType = ['choix_reponse', 'solution']
942
- let objectType = ['retroaction']
943
- let numberType = ['valeur_point', 'max_tentative']
944
- let optionalArgs = ['valeur_point', 'max_tentative', 'texte_base']
945
-
946
- errors = validateObjType(
947
- data,
948
- { stringType, arrayType, objectType, numberType },
949
- optionalArgs,
950
- 'quizData'
951
- )
952
-
953
- let hasError = errors.errorInConsole.length || errors.errorList.length
954
-
955
- if (hasError) return errors
956
-
957
- //validate Containt for retroaction
958
-
959
-
960
- // if(data.solution !=null){
961
- // console.log('ici')
962
- // }else{
963
- // console.log('la')
964
- // }
965
-
966
- switch (true) {
967
- case data.retroaction != null:
968
- objectType = ['retro_positive', 'retro_negative', 'retro_neutre']
969
-
970
-
971
- errors = validateObjType(
972
- data.retroaction,
973
- { objectType },
974
- null,
975
- 'quizData retraoction'
976
- )
977
-
978
- hasError = errors.errorInConsole.length || errors.errorList.length
979
-
980
- //console.log(hasError)
981
- if (hasError) return errors
982
-
983
- // Validate containt of retroaction attributes
984
- stringType = ['title', 'hypertext']
985
-
986
-
987
- for (const key of Object.keys(data.retroaction)) {
988
-
989
- if(key == "retro_neutre") continue //skip
990
-
991
-
992
-
993
- errors = validateObjType(
994
- data.retroaction[key],
995
- { stringType },
996
- null,
997
- key
998
- )
999
-
1000
- hasError = errors.errorInConsole.length || errors.errorList.length
1001
-
1002
- if (hasError) return errors
1003
- }
1004
-
1005
- break
1006
- }
1007
- return errors
1008
- }
1009
-
1010
- export {
1011
- validateObjType,
1012
- validateVideoData,
1013
- validateAudioData,
1014
- validatefileContent,
1015
- validateAppContent,
1016
- validateSvgDefinition,
1017
- validateQuizData
1018
- }
1
+ // Errors message to display in the console
2
+ const ERR_TYPE = {
3
+ err0: `\n 💥 Missing \x1B[1m$attr$ \x1B[0mfor $comp$. \x1B[1m$attr$ \x1B[0m should be provided with following attributes: \x1B[1m{$data$}`,
4
+ err1: `\n 💥 Invalid declaration for \x1B[1m$wrd$ \x1B[0m object`,
5
+ err2: `\n 💥 Invalid type declaration for 👉\x1B[1m$attr$ \x1B[0m👈 in \x1B[1m$el$\x1B[0m. Expected is \x1B[3m$type$ \x1B[0mtype with some value`,
6
+ err3: `\n 💥 Missing required argument 👉\x1B[1m$key$\x1B[0m👈 in \x1B[1m$el$\x1B[0m. Required arguments are: \x1B[1m$args$`,
7
+ err4: `\n 💥 Missing required argument 👉\x1B[1m$key$\x1B[0m👈 in \x1B[1m$el$\x1B[0m. Required arguments are: \x1B[1m$args$`
8
+ }
9
+
10
+ // Errors message to display in Appplication UI
11
+ const ERR_TYPE_MSG = {
12
+ err0: `\n Données manquantes pour <span style='text-transform: uppercase;'>$comp$</span>. Assurez-vous que le composant reçoit l'attribut <b>$attr$</b> avec des données pour: <b>$data$</b>`,
13
+ err1: `\n Déclaration invalide pour <b>$wrd$</b>. Assurez-vous que l'application a du data.`,
14
+ err2: `\n Vous avez une declaration invalide dans <b>$attr$</b>. 👉<b>$el$</b>👈 n'accepte que le type <i>$type$</i> et ne peut pas être vide`,
15
+ err3: `\n L'attribut 👉<b>$key$</b>👈 est manquant dans <b>$el$</b>. Les attributs requis sont: <b>$args$</b>`
16
+ }
17
+
18
+ //Get all the invalids properties from the object
19
+ /*Add element from target array that are NOT in arr to the wrongArray*/
20
+ const checkerWrong = (arr, target) => {
21
+ let wrongArray = []
22
+ target.every((v) => {
23
+ if (arr.includes(v)) {
24
+ return true
25
+ } else {
26
+ wrongArray.push(v)
27
+ return true
28
+ }
29
+ })
30
+ return wrongArray
31
+ }
32
+ //Get all the required properties that are missing from the object
33
+ /*Add element from the arr that are NOT in target arr to the missingArray*/
34
+ const checkerMissing = (arr, target) => {
35
+ let missingArray = []
36
+ arr.every((v) => {
37
+ if (target.includes(v)) {
38
+ return true
39
+ } else {
40
+ missingArray.push(v)
41
+ return true
42
+ }
43
+ })
44
+ return missingArray
45
+ }
46
+
47
+ /**
48
+ * @description - Method to validate that given object attributes hold expected types
49
+ * @param {Object} Obj - object to validate
50
+ * @param {Object} Args - List of expected type groups - each type group must be an array of attributes with the same type
51
+ * @param {Array} notRequiredArgs - list of field that should be considered as optional in the object. Will not give error if not * provided but will be validated if they are present with wrong type or empty
52
+ * @param {Array} compName - Name of the component- will be display in error message
53
+ * @param {Array} err - list off errors to be added to
54
+ * @return {Object} list of errors - {errorInConsole, errorList} : errorlist can be used to display messages on template and
55
+ * errorInConsole to display messages in browser console
56
+ * @exemple - Given $user= {name:'toto', username:'totoEscargot', id:'id001', age:23, books:['one', 'two', 'three'] }
57
+ * Use validator on $user: validateObjType($user, {stringType:['name', 'username' , 'id'], numbType:['age'], arrayType:['books']})
58
+ * Will fail if any listed attribute not in $user or have wrong value. Error messages will be in console
59
+ *
60
+ */
61
+
62
+ const validateObjType = (
63
+ Obj,
64
+ Args = {
65
+ boolType: null,
66
+ arrayType: null,
67
+ stringType: null,
68
+ objectType: null,
69
+ numbType: null
70
+ },
71
+ notRequiredArgs = null,
72
+ compName = 'component',
73
+ err = null
74
+ ) => {
75
+ let errorInConsole = err && err.errorInConsole ? err.errorInConsole : []
76
+ let errorList = err && err.errorList ? err.errorLIst : []
77
+ let optionalArgs =
78
+ notRequiredArgs && notRequiredArgs.length ? notRequiredArgs : []
79
+ //=====Expected Arguments validation =================//
80
+ //Should have an object argument
81
+ if (!Obj) throw new Error(`No valid arguments provided`)
82
+
83
+ //List required attributes
84
+ const required = []
85
+
86
+ for (const _type in Args) {
87
+ // Should be a required type
88
+ if (
89
+ ![
90
+ 'boolType',
91
+ 'arrayType',
92
+ 'stringType',
93
+ 'objectType',
94
+ 'numberType'
95
+ ].includes(_type)
96
+ )
97
+ throw new Error(`Unknown types declaration : ${_type}`)
98
+
99
+ if (Args[_type] && Args[_type].length) {
100
+ for (let el of Args[_type]) {
101
+ //Check that each given element is a string
102
+ if (el.constructor !== String)
103
+ throw new Error(
104
+ `Invalid type detected in ${JSON.stringify(
105
+ Args[_type]
106
+ )}. Item ${Args[_type].indexOf(el) + 1} should be a String`
107
+ )
108
+
109
+ if (!optionalArgs.includes(el)) required.push(el)
110
+ }
111
+ }
112
+ }
113
+
114
+ //validate Args Keys type
115
+ for (const _type in Args) {
116
+ for (let el of Args[_type]) {
117
+ let reg = /(\$el\$)|(\$type\$)|(\$attr\$)/g
118
+
119
+ switch (true) {
120
+ // Check That each given element exist in data if not optional
121
+ case Obj[el] === undefined && required.includes(el): {
122
+ reg = /(\$key\$)|(\$el\$)|(\$args\$)/g
123
+ const reg2 = /\[|\]|/g
124
+
125
+ errorInConsole.push(
126
+ ERR_TYPE.err3.replace(reg, (e) => {
127
+ if (e == '$key$') return el
128
+ if (e == '$el$') return compName
129
+ if (e == '$args$') return JSON.stringify(required)
130
+ })
131
+ )
132
+
133
+ errorList.push(
134
+ ERR_TYPE_MSG.err3.replace(reg, (e) => {
135
+ if (e == '$key$') return el
136
+ if (e == '$el$') return compName || 'Composant'
137
+ if (e == '$args$')
138
+ return JSON.stringify(required).replaceAll(reg2, '')
139
+ })
140
+ )
141
+ break
142
+ }
143
+ //Should have Correct Types $attr$ $el$ $type$
144
+ case _type == 'boolType' &&
145
+ Obj[el] !== undefined &&
146
+ Obj[el].constructor !== Boolean:
147
+ errorInConsole.push(
148
+ ERR_TYPE.err2.replace(reg, (e) => {
149
+ if (e == '$attr$') return compName || 'Composant'
150
+ if (e == '$el$') return el
151
+ if (e == '$type$') return 'Boolean'
152
+ })
153
+ )
154
+ errorList.push(
155
+ ERR_TYPE_MSG.err2.replace(reg, (e) => {
156
+ if (e == '$attr$') return compName || 'Composant'
157
+ if (e == '$el$') return el
158
+ if (e == '$type$') return 'Boolean'
159
+ })
160
+ )
161
+ break
162
+
163
+ case _type == 'stringType' &&
164
+ Obj[el] !== undefined &&
165
+ (Obj[el].constructor !== String || !Obj[el].trim().length):
166
+ errorInConsole.push(
167
+ ERR_TYPE.err2.replace(reg, (e) => {
168
+ if (e == '$attr$') return compName || 'Composant'
169
+ if (e == '$el$') return el
170
+ if (e == '$type$') return 'String'
171
+ })
172
+ )
173
+ errorList.push(
174
+ ERR_TYPE_MSG.err2.replace(reg, (e) => {
175
+ if (e == '$attr$') return compName || 'Composant'
176
+ if (e == '$el$') return el
177
+ if (e == '$type$') return 'String'
178
+ })
179
+ )
180
+ break
181
+
182
+ case _type == 'arrayType' &&
183
+ Obj[el] !== null &&
184
+ Obj[el] !== undefined &&
185
+ (Obj[el].constructor !== Array || !Obj[el].length):
186
+ errorInConsole.push(
187
+ ERR_TYPE.err2.replace(reg, (e) => {
188
+ if (e == '$attr$') return compName || 'Composant'
189
+ if (e == '$el$') return el
190
+ if (e == '$type$') return 'Array'
191
+ })
192
+ )
193
+ errorList.push(
194
+ ERR_TYPE_MSG.err2.replace(reg, (e) => {
195
+ if (e == '$attr$') return compName || 'Composant'
196
+ if (e == '$el$') return el
197
+ if (e == '$type$') return 'Array'
198
+ })
199
+ )
200
+ break
201
+
202
+ case _type == 'numberType' &&
203
+ Obj[el] !== undefined &&
204
+ Obj[el].constructor !== Number:
205
+ errorInConsole.push(
206
+ ERR_TYPE.err2.replace(reg, (e) => {
207
+ if (e == '$attr$') return compName || 'Composant'
208
+ if (e == '$el$') return el
209
+ if (e == '$type$') return 'Number'
210
+ })
211
+ )
212
+ errorList.push(
213
+ ERR_TYPE_MSG.err2.replace(reg, (e) => {
214
+ if (e == '$attr$') return compName || 'Composant'
215
+ if (e == '$el$') return el
216
+ if (e == '$type$') return 'Number'
217
+ })
218
+ )
219
+ break
220
+
221
+ case _type == 'objectType' &&
222
+ Obj[el] !== undefined &&
223
+ Obj[el].constructor !== Object:
224
+ errorInConsole.push(
225
+ ERR_TYPE.err2.replace(reg, (e) => {
226
+ if (e == '$attr$') return compName || 'Composant'
227
+ if (e == '$el$') return el
228
+ if (e == '$type$') return 'Object'
229
+ })
230
+ )
231
+ errorList.push(
232
+ ERR_TYPE_MSG.err2.replace(reg, (e) => {
233
+ if (e == '$attr$') return compName || 'Composant'
234
+ if (e == '$el$') return el
235
+ if (e == '$type$') return 'Object'
236
+ })
237
+ )
238
+ break
239
+ }
240
+ }
241
+ }
242
+
243
+ return { errorInConsole, errorList }
244
+ }
245
+
246
+ /**
247
+ * @description Validator for the content of menu setting file
248
+ * @param {String} fName- name of the file for use case
249
+ * @param {Object} fData: file's data to validate
250
+ * @param {Object} [requiredArgs] list of arguments to include consider in validation ()
251
+ */
252
+ const validatefileContent = (fName, fData, requiredArgs = {}) => {
253
+ let err = null
254
+ if (import.meta.env.DEV) {
255
+ switch (fName) {
256
+ case 'menuSettings': {
257
+ const {
258
+ keys4Lesson,
259
+ keys4ActivityMandatory,
260
+ keys4ActivityOpt,
261
+ keys4Anchors
262
+ } = requiredArgs
263
+
264
+ //*validate that data is an {Object}. if Not send error message
265
+ if (fData.constructor !== Object)
266
+ err = '💥Invalid file provided for menu settings'
267
+ if (Object.keys(fData).length > 0) {
268
+ const content = Object.keys(fData)
269
+ //Check if lessonTitle exists
270
+ if (typeof fData.lessonTitle === 'undefined') {
271
+ err = `!!!! 💥 Missing 👉 lessonTitle 👈 variable in ➡ menu.setting.js \n 🚩 This variable is mandatory.`
272
+ break
273
+ }
274
+ //Check if lessonNumber exists
275
+ if (typeof fData.lessonNumber === 'undefined') {
276
+ err = `!!!! 💥 Missing 👉 lessonNumber 👈 variable in ➡ menu.setting.js \n 🚩 This variable is mandatory.`
277
+ break
278
+ }
279
+ if (content.length != keys4Lesson.length) {
280
+ err = `!!!! 💥 Missing activity in➡ menu.setting.js \n 🚩Must declare all activity in menu.setting.js`
281
+ break
282
+ } else {
283
+ for (let el of content) {
284
+ //validate that the content of each entry is valide
285
+ if (!keys4Lesson.includes(el)) {
286
+ err = `!!!! 💥 invalid data provided for key 👉 ${el} 👈 in ➡ menu.setting.js \n 🚩 All activity must be listed and you must have a lesson title`
287
+ break
288
+ }
289
+ }
290
+ }
291
+
292
+ // Validate that each entry has the required key
293
+ if (!err) {
294
+ const reg = /^A[0-9]{2}$/ // target only activities
295
+ const contentActivities = content.filter((data) => data.match(reg)) //Get only the activities
296
+
297
+ for (let el of contentActivities) {
298
+ const entry = fData[el]
299
+
300
+ const tabEntrykey = Object.keys(entry)
301
+ //Validate that entry has optional key
302
+ if (
303
+ !tabEntrykey.includes(keys4ActivityOpt[0]) ||
304
+ !tabEntrykey.includes(keys4ActivityOpt[1])
305
+ ) {
306
+ err = `💥 Missing 👉 ${keys4ActivityOpt[0]} or ${keys4ActivityOpt[1]} 👈 in ${el} in ➡ menu.setting.js \n 🚩One of thess two keys are mandatory : 👉 ${keys4ActivityOpt}`
307
+ break
308
+ }
309
+
310
+ //Validate that entry has mandatory key
311
+ for (let m of keys4ActivityMandatory) {
312
+ if (!tabEntrykey.includes(m)) {
313
+ err = `💥 Missing 👉 ${m} 👈 in ${el} in ➡ menu.setting.js \n 🚩All this key are mandatory : 👉 ${keys4ActivityMandatory}`
314
+ break
315
+ } else {
316
+ switch (m) {
317
+ case 'anchors':
318
+ if (entry[m].constructor !== Array)
319
+ err = `💥 Invalid anchors declaration for 👉 ${el} 👈 in ➡ menu.setting.j \n 🚩Must be of type {Array}`
320
+ else {
321
+ const anchors = entry.anchors
322
+
323
+ for (let a of anchors) {
324
+ //trow error if numbers of keys are not the same as required
325
+ const a_numb = anchors.indexOf(a) + 1
326
+ if (Object.keys(a).length !== keys4Anchors.length) {
327
+ err = `💥 Invalid declaration in 👉anchor ${a_numb}👈 for ➡ ${el} in ➡ menu.setting.js \n 🚩 Allowed indexes are: 👉 ${keys4Anchors}`
328
+ break
329
+ }
330
+ // Validated that required keys condition and type is met
331
+ for (let k of keys4Anchors) {
332
+ if (!a[k]) {
333
+ err = `💥 Missing 👉 ${k} 👈 for anchor ${a_numb} ➡ ${el} ➡ menu.setting.js \n 🚩 Allowed indexes are: 👉 ${keys4Anchors}`
334
+ } else if (a[k].constructor !== String) {
335
+ err = `💥 Invalid 👉 ${k} 👈 declaration for anchor ${a_numb} ➡ ${el} ➡ menu.setting.js \n 🚩 Must be of type {String}`
336
+ }
337
+ if (err) break
338
+ }
339
+ if (err) break
340
+ }
341
+ }
342
+
343
+ break
344
+ default:
345
+ if (entry[m].constructor !== String)
346
+ err = `Invalid 👉 ${m} 👈 declaration for ➡ ${el} in ➡ menu.setting.js \n 🚩 Must be of type {String}`
347
+ break
348
+ }
349
+ }
350
+ }
351
+ }
352
+ }
353
+ }
354
+ break
355
+ }
356
+ }
357
+ }
358
+ return err
359
+ }
360
+
361
+ /**
362
+ * @description Validator for the content of menu setting file
363
+ * @param {Object} data- Object definition to validate
364
+ **/
365
+ const validateVideoData = (data) => {
366
+ const errorList = []
367
+ if (import.meta.env.DEV) {
368
+ let errStringInConsole = null
369
+ let errString = null
370
+ const expectedKeys = [
371
+ 'id',
372
+ 'mSources',
373
+ 'mSubtitles',
374
+ 'mPoster',
375
+ 'mTranscript'
376
+ ]
377
+
378
+ if (!data || data.constructor !== Object || Object.keys(data).length < 1) {
379
+ errStringInConsole = `\n 💥 Invalid declaration for video element`
380
+ console.warn(
381
+ `%c WARNING!>>> VIDEO: ${errStringInConsole}`,
382
+ 'background: orange; color: white; display: block; border-radius:5px; margin:5px;'
383
+ )
384
+ errString = `Declaration invalide pour Objet video.`
385
+ errorList.push(errString)
386
+ }
387
+ //Must have mSources
388
+ if (!data['mSources']) {
389
+ errStringInConsole = ` Missing 👉 mSources 👈 declaration for video element`
390
+
391
+ errString = `l'Attribut <b>mSources</b> pour l'Objet video n'est pas defini. `
392
+ console.warn(
393
+ `%c WARNING!>>> ${errStringInConsole}`,
394
+ 'background: orange; color: white; display: block; border-radius:5px; margin:5px;'
395
+ )
396
+ errorList.push(errString)
397
+ }
398
+ //Must have id
399
+ if (!data['id']) {
400
+ errStringInConsole = ` Missing 👉 id 👈 declaration for video element`
401
+
402
+ errString = `l'Attribut <b>id</b> pour l'objet video n'est pas defini. `
403
+ console.warn(
404
+ `%c WARNING!>>> ${errStringInConsole}`,
405
+ 'background: orange; color: white; display: block; border-radius:5px; margin:5px;'
406
+ )
407
+ errorList.push(errString)
408
+ }
409
+ //Start validation of keys in data
410
+ if (!errString) {
411
+ expectedKeys.forEach((k) => {
412
+ if (!data[k] && k !== 'mSources') return
413
+
414
+ switch (k) {
415
+ case 'id':
416
+ if (data['id'].constructor !== String || data['id'].length < 1) {
417
+ errStringInConsole =
418
+ '\n 💥 Invalid type declaration for id.\n 🚩 Must be of type Array'
419
+
420
+ errString = `l'Attribut <b>id</b> pour le media doit être de type <i>String</i>`
421
+
422
+ errorList.push(errString)
423
+ console.warn(
424
+ `%c WARNING!>>> ${errStringInConsole}`,
425
+ 'background: orange; color: white; display: block; border-radius:5px; margin:5px;'
426
+ )
427
+ }
428
+ break
429
+ case 'mSources':
430
+ if (
431
+ data['mSources'].constructor !== Array ||
432
+ data['mSources'].length < 1
433
+ ) {
434
+ errStringInConsole =
435
+ '\n 💥 Invalid type declaration for mSources.\n 🚩 Must be of type Array'
436
+
437
+ errString = `l'Attribut 👉 mSources 👈 pour le media doit être de type Array`
438
+
439
+ errorList.push(errString)
440
+ console.warn(
441
+ `%c WARNING!>>> ${errStringInConsole}`,
442
+ 'background: orange; color: white; display: block; border-radius:5px; margin:5px;'
443
+ )
444
+ }
445
+ break
446
+
447
+ case 'mSubtitles':
448
+ {
449
+ //Validate required keys in Subtitle definition
450
+ let expectedKeys = ['label', 'src', 'srclang']
451
+ //we only accept one subtitle and must be defined as an Object with 3 keys
452
+ if (
453
+ data['mSubtitles'].constructor !== Array ||
454
+ !data['mSubtitles'].length
455
+ ) {
456
+ errStringInConsole = `\n 💥 Invalid type declaration for mSubtitles.\n 🚩 Must be of type Array with at list one Object defined with: ${expectedKeys}`
457
+
458
+ errString = `l'Attribut 👉 mSubtitles 👈 doit être de type Array avec au moins un Objet: {${expectedKeys}} `
459
+
460
+ console.warn(
461
+ `%c WARNING!>>> ${errStringInConsole}`,
462
+ 'background: orange; color: white; display: block; border-radius:5px; margin:5px;'
463
+ )
464
+
465
+ return errorList.push(errString)
466
+ }
467
+ //Validate definition for each Subtitle Object
468
+ for (const obj of data['mSubtitles']) {
469
+ const objIndex = data['mSubtitles'].indexOf(obj)
470
+ expectedKeys.forEach((expected) => {
471
+ if (!obj[expected]) {
472
+ errStringInConsole = `\n 💥 Missing key 👉 ${expected} 👈 for mSubtitles No.${
473
+ objIndex + 1
474
+ }.\n 🚩 required keys are: ${expectedKeys} `
475
+
476
+ errString = `l'Attribut 👉 ${expected} 👈 pour le sous-titre No.${
477
+ objIndex + 1
478
+ } n'est pas défini`
479
+
480
+ console.warn(
481
+ `%c WARNING!>>> ${errStringInConsole}`,
482
+ 'background: orange; color: white; display: block; border-radius:5px; margin:5px;'
483
+ )
484
+ return errorList.push(errString)
485
+ }
486
+
487
+ // Only none empty String type Accepted
488
+ if (
489
+ obj[expected].constructor === String &&
490
+ obj[expected].trim().length
491
+ )
492
+ return
493
+
494
+ errStringInConsole = `\n 💥 Invalid type declaration for 👉${expected}👈 in mSubtitles No.${
495
+ objIndex + 1
496
+ }.\n 🚩 Must be none-empty String `
497
+
498
+ errString = `l'Attribut 👉${expected}👈 du sous-titre No.${
499
+ objIndex + 1
500
+ } doit être de type String et ne peut pas être vide. `
501
+
502
+ console.warn(
503
+ `%c WARNING!>>> ${errStringInConsole}`,
504
+ 'background: orange; color: white; display: block; border-radius:5px; margin:5px;'
505
+ )
506
+
507
+ errorList.push(errString)
508
+ })
509
+ }
510
+ }
511
+ break
512
+ case 'mPoster':
513
+ //Only type String allowed and must not be empty
514
+ if (
515
+ data['mPoster'] &&
516
+ data['mPoster'].constructor == String &&
517
+ data['mPoster'].trim().length
518
+ )
519
+ return
520
+
521
+ errStringInConsole = `\n 💥 Invalid type declaration for 👉 mPoster 👈.\n 🚩 Must be none-empty String `
522
+
523
+ errString = `l'Attribut 👉 mPoster 👈 doit être de type String et ne peut pas être vide. `
524
+
525
+ errorList.push(errString)
526
+ console.warn(
527
+ `%c WARNING!>>> VIDEO: ${errStringInConsole}`,
528
+ 'background: orange; color: white; display: block; border-radius:5px; margin:5px;'
529
+ )
530
+
531
+ break
532
+ case 'mTranscript':
533
+ //Only type String allowed and must not be empty
534
+ if (
535
+ data['mTranscript'] &&
536
+ data['mTranscript'].constructor == String &&
537
+ data['mTranscript'].trim().length
538
+ )
539
+ return
540
+
541
+ errStringInConsole = `\n 💥 Invalid type declaration for 👉 mTranscript 👈 .\n 🚩 Must be none-empty String `
542
+
543
+ errString = `l'Attribut 👉 mTranscript 👈 doit être de type String et ne peut pas être vide. `
544
+
545
+ console.warn(
546
+ `%c WARNING!>>> VIDEO: ${errStringInConsole}`,
547
+ 'background: orange; color: white; display: block; border-radius:5px; margin:5px;'
548
+ )
549
+ errorList.push(errString)
550
+
551
+ break
552
+ }
553
+ })
554
+ }
555
+ }
556
+ return errorList
557
+ }
558
+
559
+ /**
560
+ * @description Validator for the content of audio props
561
+ * @param {Object} data- Object definition to validate
562
+ **/
563
+ const validateAudioData = (data) => {
564
+ const errorList = []
565
+ let currentProperties = Object.getOwnPropertyNames(data)
566
+ if (process.env.NODE_ENV === 'development') {
567
+ //errorList.push('test')
568
+
569
+ const requiredProperties = ['id', 'mTitle', 'mSources', 'mTranscript']
570
+
571
+ const optionalProperties = ['mPoster', 'mAlt']
572
+
573
+ const allProperties = [
574
+ ...requiredProperties,
575
+ ...optionalProperties,
576
+ ...['__ob__']
577
+ ]
578
+
579
+ let errStringInConsole = null
580
+ let errString = null
581
+
582
+ //** Validate if data exist and is an object**/
583
+ if (!data || data.constructor !== Object || Object.keys(data).length < 1) {
584
+ errStringInConsole = `\n 💥 Invalid declaration for audio element`
585
+ console.warn(
586
+ `%c WARNING!>>> AUDIO: ${errStringInConsole}`,
587
+ 'background: orange; color: white; display: block; border-radius:5px; margin:5px;'
588
+ )
589
+ errString = `Déclaration invalide pour Objet audData. Ce doit être un objet non vide.`
590
+ errorList.push(errString)
591
+ return errorList
592
+ }
593
+ //** Validate if all the properties are right**/
594
+ let wrongProperties = checkerWrong(allProperties, currentProperties)
595
+
596
+ if (wrongProperties.length > 0) {
597
+ console.warn(
598
+ `%c WARNING!>>> AppCompAudio : audData property ${wrongProperties} invalid. Required properties: ${requiredProperties} . Optional properties: ${optionalProperties}`,
599
+ 'background: orange; color: white; display: block; margin:5px;'
600
+ )
601
+ errString = `Propriété invalide pour audData: ${wrongProperties}. Les propriétés requises sont: ${requiredProperties} et les propriétés facultatives sont: ${optionalProperties}`
602
+ errorList.push(errString)
603
+ return errorList
604
+ }
605
+
606
+ //** Validate if all the required properties are in the data */
607
+ let missingRequired = checkerMissing(requiredProperties, currentProperties)
608
+
609
+ if (missingRequired.length > 0) {
610
+ console.warn(
611
+ `%c WARNING!>>> AppCompAudio : audData missing required ${missingRequired} property. Required properties: ${requiredProperties} . Optional properties: ${optionalProperties}`,
612
+ 'background: orange; color: white; display: block; margin:5px;'
613
+ )
614
+ errString = `Propriété requise manquante pour audData: <b>${missingRequired}</b>. Les propriétés requises sont: <i>${requiredProperties}</i> et les propriétés facultatives sont: <i>${optionalProperties}</i>`
615
+ errorList.push(errString)
616
+ return errorList
617
+ }
618
+ /***Validate data values */
619
+ if (errorList.length == 0) {
620
+ let invalidString = []
621
+ let invalidArray = []
622
+ let invalidProperties = []
623
+ currentProperties.forEach((p) => {
624
+ switch (p) {
625
+ case 'mTitle':
626
+ case 'mTranscript':
627
+ case 'mPoster':
628
+ case 'mAlt':
629
+ if (data[p] && data[p].constructor == String) {
630
+ data[p].trim().length == 0 ? invalidString.push(p) : ''
631
+ } else {
632
+ invalidString.push(p)
633
+ }
634
+ break
635
+ case 'mSources': {
636
+ if (data[p] && data[p].constructor == Array) {
637
+ data[p].length == 0 ? invalidArray.push(p) : ''
638
+ } else {
639
+ invalidArray.push(p)
640
+ }
641
+ if (invalidArray.length === 0) {
642
+ //Valider les attributs de mSources
643
+ for (let i in data[p]) {
644
+ let object = data[p][i]
645
+ if ('src' in object && 'type' in object) {
646
+ if (
647
+ object['src'].constructor != String &&
648
+ object['type'].constructor != String
649
+ ) {
650
+ invalidProperties.push(p)
651
+ } else {
652
+ object['src'].trim().length == 0
653
+ ? invalidString.push(p)
654
+ : ''
655
+ object['type'].trim().length == 0
656
+ ? invalidString.push(p)
657
+ : ''
658
+ }
659
+ } else {
660
+ invalidProperties.push(p)
661
+ }
662
+ }
663
+ }
664
+ break
665
+ }
666
+ }
667
+ })
668
+ //Display error for each type
669
+ //String
670
+ let sL = invalidString.length
671
+ if (sL > 0) {
672
+ errStringInConsole = `\n 💥 Invalid value type for 👉${invalidString}👈 \n 🚩 Must be none-empty String `
673
+
674
+ errString = `${sL > 1 ? 'Les ' : "L'"}attribut${
675
+ sL > 1 ? 's ' : ''
676
+ } 👉${invalidString}👈 doi${
677
+ sL > 1 ? 'ven' : ''
678
+ }t être de type String et ne peu${sL > 1 ? 'ven' : ''}t pas être vide. `
679
+
680
+ console.warn(
681
+ `%c WARNING!>>> ${errStringInConsole}`,
682
+ 'background: orange; color: white; display: block; border-radius:5px; margin:5px;'
683
+ )
684
+ errorList.push(errString)
685
+ }
686
+ //Array
687
+ let aL = invalidArray.length
688
+ if (aL > 0) {
689
+ errStringInConsole = `\n 💥 Invalid value type for 👉${invalidArray}👈 \n 🚩 Must be none-empty Array`
690
+
691
+ errString = `${aL > 1 ? 'Les ' : "L'"}attribut${
692
+ aL > 1 ? 's ' : ''
693
+ } 👉${invalidArray}👈 doi${
694
+ sL > 1 ? 'ven' : ''
695
+ }t être de type Array et ne peu${aL > 1 ? 'ven' : ''}t pas être vide. `
696
+
697
+ console.warn(
698
+ `%c WARNING!>>> ${errStringInConsole}`,
699
+ 'background: orange; color: white; display: block; border-radius:5px; margin:5px;'
700
+ )
701
+ errorList.push(errString)
702
+ }
703
+ let pL = invalidProperties.length
704
+ if (pL > 0) {
705
+ errStringInConsole = `\n 💥 Invalid value type for 👉src and/or type👈 in mSources \n 🚩 They are required and must be none-empty strings`
706
+
707
+ errString = `${pL > 1 ? 'Les ' : "L'"}attribut${
708
+ pL > 1 ? 's ' : ''
709
+ } 👉src and/or type👈 de mSources doi${
710
+ sL > 1 ? 'ven' : ''
711
+ }t être de type String et ne peu${pL > 1 ? 'ven' : ''}t pas être vide. `
712
+
713
+ console.warn(
714
+ `%c WARNING!>>> ${errStringInConsole}`,
715
+ 'background: orange; color: white; display: block; border-radius:5px; margin:5px;'
716
+ )
717
+ errorList.push(errString)
718
+ }
719
+ }
720
+ }
721
+ return errorList
722
+ }
723
+
724
+ /**
725
+ * @description Validator for the content of app data.
726
+ * App data is used as setting for the application
727
+ * @param {Object} data - the Object definition to validate
728
+ * @param {Boolean} silent - if Validator should diplay error in console
729
+ *
730
+ **/
731
+
732
+ const validateAppContent = (data, silent = false) => {
733
+ let errorInConsole = []
734
+ let errorList = []
735
+
736
+ const requiredArgs = [
737
+ 'lang',
738
+ 'specification',
739
+ 'id',
740
+ 'crs_id',
741
+ 'idb_id',
742
+ 'no_menu',
743
+ 'is_single_activity',
744
+ 'auto_next_activity'
745
+ ]
746
+
747
+ //Validate not empty data
748
+ if (Object.keys(data).length == 0) {
749
+ const reg = /(\$comp\$)|(\$data\$)|(\$attr\$)/g
750
+
751
+ errorInConsole.push(
752
+ ERR_TYPE.err0.replace(reg, (e) => {
753
+ if (e == '$comp$') return 'app-base'
754
+ if (e == '$data$') return requiredArgs.toString().replaceAll(',', ', ')
755
+ if (e == '$attr$') return 'app-config'
756
+ })
757
+ )
758
+
759
+ errorList.push(
760
+ ERR_TYPE_MSG.err0.replace(reg, (e) => {
761
+ if (e == '$comp$') return 'app-base'
762
+ if (e == '$data$') return requiredArgs.toString().replaceAll(',', ', ')
763
+ if (e == '$attr$') return 'app-config'
764
+ })
765
+ )
766
+
767
+ console.warn(errorInConsole[0])
768
+
769
+ return errorList
770
+ }
771
+
772
+ let stringType = ['lang', 'specification', 'id', 'crs_id', 'idb_id']
773
+ let boolType = [
774
+ 'no_menu',
775
+ 'is_single_activity',
776
+ 'auto_next_activity',
777
+ 'remote'
778
+ ]
779
+ let objectType = ['actor', 'linkedResource']
780
+ let optionalArgs = ['remote', 'actor', 'linkedResource']
781
+
782
+ const { errorInConsole: errCons, errorList: errList } = validateObjType(
783
+ data,
784
+ {
785
+ stringType,
786
+ boolType,
787
+ objectType
788
+ },
789
+ optionalArgs,
790
+ 'App.vue'
791
+ )
792
+
793
+ errorList = [...errorList, ...errList]
794
+ errorInConsole = [...errorInConsole, ...errCons]
795
+
796
+ //===========Optional Keys should be of correct type when declared =================//
797
+ // Has actor defined
798
+ if (data['actor']) {
799
+ let { errorInConsole: err1, errorList: err2 } = validateObjType(
800
+ data['actor'],
801
+ {
802
+ stringType: ['name', 'mbox']
803
+ },
804
+ 'actor'
805
+ )
806
+
807
+ errorList = [...errorList, ...err2]
808
+ errorInConsole = [...errorInConsole, ...err1]
809
+ }
810
+ // Has LinkedResource defined
811
+ if (data['linkedResource']) {
812
+ let { errorInConsole: err1, errorList: err2 } = validateObjType(
813
+ data['linkedResource'],
814
+ {
815
+ stringType: ['url', 'id']
816
+ },
817
+ 'linkedResource'
818
+ )
819
+
820
+ errorList = [...errorList, ...err2]
821
+ errorInConsole = [...errorInConsole, ...err1]
822
+ }
823
+ // Has endpointConfig defined
824
+ if (data['endpointConfig']) {
825
+ let { errorInConsole: err1, errorList: err2 } = validateObjType(
826
+ data['endpointConfig'],
827
+ {
828
+ stringType: ['auth', 'endpoint']
829
+ },
830
+ 'endpointConfig'
831
+ )
832
+ errorList = [...errorList, ...err2]
833
+ errorInConsole = [...errorInConsole, ...err1]
834
+ }
835
+ //================== END Optional Keys ====================//
836
+
837
+ //Should display error to console
838
+ if (errorList.length && !silent) {
839
+ let txt = '⚠️ You have the following Errors:'
840
+ console.group(`%c ${txt}`, 'background:#ffc13a7d')
841
+ errorInConsole.forEach((err) => console.warn(err))
842
+ console.groupEnd()
843
+ }
844
+
845
+ return errorList
846
+ }
847
+
848
+ /**
849
+ * @description - Method validate the definition of SVG data.
850
+ * @param {Array || Object } SVGData - the data defining the SVG to render
851
+ * @return true - if valid
852
+ * */
853
+
854
+ const validateSvgDefinition = (SVGData) => {
855
+ //Should be Array of Object
856
+ if (SVGData.constructor !== Array && SVGData.constructor !== Object)
857
+ throw new Error('Unsupported Type for SVG data')
858
+ let Errors = []
859
+ let SVGDef = SVGData.constructor == Object ? new Array(SVGData) : SVGData
860
+ //Should validate the entries for each SVG definition as the required entries
861
+
862
+ for (const s_def of SVGDef) {
863
+ let i = SVGDef.indexOf(s_def)
864
+ let stringType = ['id', 'viewBox']
865
+ let arrayType = ['paths']
866
+ let { errorInConsole: errCons } = validateObjType(
867
+ s_def,
868
+ {
869
+ stringType,
870
+ arrayType
871
+ },
872
+ 'viewBox',
873
+ `SVG ${i + 1}`
874
+ )
875
+ Errors.push(...errCons)
876
+ if (errCons.length) {
877
+ errCons.forEach((err) => console.warn(err))
878
+ break
879
+ }
880
+
881
+ //Should validate that each element in the path attributes is an object of type string and has the id attribute
882
+
883
+ for (const _path of s_def.paths) {
884
+ let index = s_def.paths.indexOf(_path)
885
+ if (_path.constructor !== Object)
886
+ throw Error(
887
+ `Unexpected definition for path ${index + 1} in SVG ${i + 1}. Expecting Object but received ${typeof _path}`
888
+ )
889
+
890
+ let stringType = ['d']
891
+
892
+ let { errorInConsole: errCons } = validateObjType(
893
+ _path,
894
+ {
895
+ stringType
896
+ },
897
+ null,
898
+ `SVG path ${index + 1}`
899
+ )
900
+ Errors.push(...errCons)
901
+ if (errCons.length) {
902
+ errCons.forEach((err) => console.warn(err))
903
+ break
904
+ }
905
+
906
+ //validate each entries in path
907
+ for (const _key in _path) {
908
+ if (_key == 'd') continue //skip
909
+ //all keys in path should be of type String and not empty
910
+ let stringType = [_key]
911
+
912
+ let { errorInConsole: errCons } = validateObjType(
913
+ _path,
914
+ {
915
+ stringType
916
+ },
917
+ null,
918
+ `SVG path ${index + 1}`
919
+ )
920
+ Errors.push(...errCons)
921
+ if (errCons.length) {
922
+ errCons.forEach((err) => console.log(err))
923
+ break
924
+ }
925
+ }
926
+ }
927
+ }
928
+
929
+ if (Errors.length) throw new Error('Error SVG')
930
+ return true
931
+ }
932
+
933
+ /**
934
+ * @description - Method validate the definition data forthe quiz.
935
+ * @param {Object} data - the data defining the SVG to render
936
+ * @return true - if valid
937
+ * */
938
+ const validateQuizData = (data) => {
939
+ let errors
940
+ let stringType = ['ennonce', 'id', 'type_question', 'texte_base']
941
+ let arrayType = ['choix_reponse', 'solution']
942
+ let objectType = ['retroaction']
943
+ let numberType = ['valeur_point', 'max_tentative']
944
+ let optionalArgs = ['valeur_point', 'max_tentative', 'texte_base']
945
+
946
+ errors = validateObjType(
947
+ data,
948
+ { stringType, arrayType, objectType, numberType },
949
+ optionalArgs,
950
+ 'quizData'
951
+ )
952
+
953
+ let hasError = errors.errorInConsole.length || errors.errorList.length
954
+
955
+ if (hasError) return errors
956
+
957
+ //validate Containt for retroaction
958
+
959
+
960
+ // if(data.solution !=null){
961
+ // console.log('ici')
962
+ // }else{
963
+ // console.log('la')
964
+ // }
965
+
966
+ switch (true) {
967
+ case data.retroaction != null:
968
+ objectType = ['retro_positive', 'retro_negative', 'retro_neutre']
969
+
970
+
971
+ errors = validateObjType(
972
+ data.retroaction,
973
+ { objectType },
974
+ null,
975
+ 'quizData retraoction'
976
+ )
977
+
978
+ hasError = errors.errorInConsole.length || errors.errorList.length
979
+
980
+ //console.log(hasError)
981
+ if (hasError) return errors
982
+
983
+ // Validate containt of retroaction attributes
984
+ stringType = ['title', 'hypertext']
985
+
986
+
987
+ for (const key of Object.keys(data.retroaction)) {
988
+
989
+ if(key == "retro_neutre") continue //skip
990
+
991
+
992
+
993
+ errors = validateObjType(
994
+ data.retroaction[key],
995
+ { stringType },
996
+ null,
997
+ key
998
+ )
999
+
1000
+ hasError = errors.errorInConsole.length || errors.errorList.length
1001
+
1002
+ if (hasError) return errors
1003
+ }
1004
+
1005
+ break
1006
+ }
1007
+ return errors
1008
+ }
1009
+
1010
+ export {
1011
+ validateObjType,
1012
+ validateVideoData,
1013
+ validateAudioData,
1014
+ validatefileContent,
1015
+ validateAppContent,
1016
+ validateSvgDefinition,
1017
+ validateQuizData
1018
+ }