fcad-core-dragon 2.0.0-beta.1 → 2.0.0-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 (78) hide show
  1. package/{.eslintrc.js → .eslintrc.cjs} +13 -18
  2. package/bk.scss +117 -0
  3. package/package.json +23 -39
  4. package/src/$locales/en.json +30 -16
  5. package/src/$locales/fr.json +29 -16
  6. package/src/components/AppBase.vue +740 -305
  7. package/src/components/AppBaseButton.vue +33 -5
  8. package/src/components/AppBaseErrorDisplay.vue +43 -35
  9. package/src/components/AppBaseModule.vue +447 -623
  10. package/src/components/AppBasePage.vue +37 -25
  11. package/src/components/AppCompAudio.vue +266 -0
  12. package/src/components/AppCompBranchButtons.vue +52 -63
  13. package/src/components/AppCompButtonProgress.vue +1 -16
  14. package/src/components/AppCompCarousel.vue +43 -39
  15. package/src/components/AppCompInputCheckBox.vue +9 -3
  16. package/src/components/AppCompInputDropdown.vue +2 -4
  17. package/src/components/AppCompInputRadio.vue +8 -15
  18. package/src/components/AppCompInputTextTable.vue +15 -12
  19. package/src/components/AppCompInputTextToFillDropdown.vue +16 -14
  20. package/src/components/AppCompInputTextToFillText.vue +2 -2
  21. package/src/components/AppCompJauge.vue +13 -1
  22. package/src/components/AppCompMenu.vue +203 -10
  23. package/src/components/AppCompMenuItem.vue +20 -3
  24. package/src/components/AppCompNavigation.vue +351 -355
  25. package/src/components/AppCompNoteCall.vue +62 -47
  26. package/src/components/AppCompNoteCredit.vue +182 -79
  27. package/src/components/AppCompPlayBar.vue +975 -1023
  28. package/src/components/AppCompPlayBarProgress.vue +73 -0
  29. package/src/components/AppCompPopUp.vue +175 -114
  30. package/src/components/AppCompQuiz.vue +67 -81
  31. package/src/components/AppCompQuizRecall.vue +32 -5
  32. package/src/components/AppCompSVG.vue +66 -40
  33. package/src/components/AppCompSettingsMenu.vue +6 -8
  34. package/src/components/AppCompTableOfContent.vue +166 -45
  35. package/src/components/AppCompVideoPlayer.vue +154 -110
  36. package/src/components/BaseModule.vue +21 -17
  37. package/src/main.js +124 -88
  38. package/src/mixins/$mediaMixins.js +827 -0
  39. package/src/mixins/$pageMixins.js +65 -109
  40. package/src/mixins/$quizMixins.js +12 -26
  41. package/src/mixins/timerMixin.js +8 -9
  42. package/src/module/store.js +187 -68
  43. package/src/module/xapi/ADL.js +90 -53
  44. package/src/module/xapi/Crypto/Hasher.js +8 -8
  45. package/src/module/xapi/Crypto/WordArray.js +6 -6
  46. package/src/module/xapi/Crypto/algorithms/BufferedBlockAlgorithm.js +4 -4
  47. package/src/module/xapi/Crypto/algorithms/C_algo.js +14 -18
  48. package/src/module/xapi/Crypto/algorithms/HMAC.js +1 -1
  49. package/src/module/xapi/Crypto/algorithms/SHA1.js +1 -1
  50. package/src/module/xapi/Crypto/encoders/Base.js +7 -7
  51. package/src/module/xapi/Crypto/encoders/Base64.js +3 -3
  52. package/src/module/xapi/Crypto/encoders/Hex.js +2 -2
  53. package/src/module/xapi/Crypto/encoders/Latin1.js +3 -3
  54. package/src/module/xapi/Crypto/encoders/Utf8.js +3 -3
  55. package/src/module/xapi/Statement/index.js +1 -1
  56. package/src/module/xapi/launch.js +10 -10
  57. package/src/module/xapi/utils.js +17 -17
  58. package/src/module/xapi/wrapper.js +123 -50
  59. package/src/module/xapi/xapiStatement.js +29 -29
  60. package/src/plugins/helper.js +8 -9
  61. package/src/plugins/i18n.js +23 -10
  62. package/src/plugins/scorm.js +14 -14
  63. package/src/router/index.js +3 -4
  64. package/src/router/routes.js +10 -30
  65. package/src/shared/generalfuncs.js +31 -24
  66. package/src/shared/validators.js +730 -20
  67. package/.prettierrc.js +0 -5
  68. package/babel.config.js +0 -3
  69. package/src/components/AppBaseDragChoice.vue +0 -91
  70. package/src/components/AppBaseDropZone.vue +0 -112
  71. package/src/components/AppCompBif.vue +0 -120
  72. package/src/components/AppCompDragAndDrop.vue +0 -339
  73. package/src/components/AppCompInputAssociation.vue +0 -332
  74. package/src/components/AppCompMediaPlayer.vue +0 -397
  75. package/src/plugins/timeManager.js +0 -77
  76. package/src/routes_bckp.js +0 -313
  77. package/src/routes_static.js +0 -344
  78. package/vue.config.js +0 -83
@@ -6,10 +6,15 @@
6
6
  */
7
7
  const validatefileContent = (fName, fData, requiredArgs = {}) => {
8
8
  let err = null
9
- if (process.env.NODE_ENV === 'development') {
9
+ if (import.meta.env.DEV) {
10
10
  switch (fName) {
11
11
  case 'menuSettings': {
12
- const { keys4Activity, keys4Anchors } = requiredArgs
12
+ const {
13
+ keys4Lesson,
14
+ keys4ActivityMando,
15
+ keys4ActivityOpt,
16
+ keys4Anchors
17
+ } = requiredArgs
13
18
 
14
19
  //*validate that data is an {Object}. if Not send error message
15
20
  if (fData.constructor !== Object)
@@ -17,27 +22,44 @@ const validatefileContent = (fName, fData, requiredArgs = {}) => {
17
22
 
18
23
  if (Object.entries(fData).length > 0) {
19
24
  const content = Object.entries(fData)
20
-
21
- for (let el of content) {
22
- // validate that the content of each entry is an object
23
- if (el[1].constructor !== Object || !Object.keys(el[1]).length) {
24
- err = `💥 invalid data provided for key 👉 ${el[0]} 👈 in ➡ menu.setting.js \n 🚩Must be of type {Object}`
25
- break
25
+ if (content.length != keys4Lesson.length) {
26
+ err = `!!!! 💥 Missing activity in➡ menu.setting.js \n 🚩Must declare all activity in menu.setting.js`
27
+ break
28
+ } else {
29
+ for (let [index, el] of content.entries()) {
30
+ //validate that the content of each entry is valide
31
+ if (el[0] !== keys4Lesson[index]) {
32
+ err = `!!!! 💥 invalid data provided for key 👉 ${el[0]} 👈 in ➡ menu.setting.js \n 🚩 All activity must be listed and you must have a lesson title`
33
+ break
34
+ }
26
35
  }
27
36
  }
37
+
28
38
  // Validate that each entry has the required key
29
39
  if (!err) {
40
+ // remove key lessonTitle
41
+ content.shift()
30
42
  for (let el of content) {
31
43
  const entry = el[1]
32
- for (let k of keys4Activity) {
33
- if (!entry[k]) {
34
- err = `💥 Missing 👉 ${k} 👈 in ${el[0]} in ➡ menu.setting.js \n 🚩Allowed indexes are: 👉 ${keys4Activity}`
44
+ const tabEntrykey = Object.keys(entry)
45
+
46
+ //Validate that entry has optional key
47
+ if (!tabEntrykey.includes(keys4ActivityOpt[0])) {
48
+ if (!tabEntrykey.includes(keys4ActivityOpt[1])) {
49
+ err = `💥 Missing 👉 ${keys4ActivityOpt[0]} or ${keys4ActivityOpt[1]} 👈 in ${el[0]} in ➡ menu.setting.js \n 🚩One of thess two keys are mandatory : 👉 ${keys4ActivityOpt}`
50
+ break
51
+ }
52
+ }
53
+
54
+ //Validate that entry has mandatory key
55
+ for (let m of keys4ActivityMando) {
56
+ if (!tabEntrykey.includes(m)) {
57
+ err = `💥 Missing 👉 ${m} 👈 in ${el[0]} in ➡ menu.setting.js \n 🚩All this key are mandatory : 👉 ${keys4ActivityMando}`
35
58
  break
36
59
  } else {
37
- //validate that each entry as correct value type
38
- switch (k) {
60
+ switch (m) {
39
61
  case 'anchors':
40
- if (entry[k].constructor !== Array)
62
+ if (entry[m].constructor !== Array)
41
63
  err = `💥 Invalid anchors declaration for 👉 ${el[0]} 👈 in ➡ menu.setting.j \n 🚩Must be of type {Array}`
42
64
  else {
43
65
  const anchors = entry.anchors
@@ -64,14 +86,12 @@ const validatefileContent = (fName, fData, requiredArgs = {}) => {
64
86
 
65
87
  break
66
88
  default:
67
- if (entry[k].constructor !== String)
68
- err = `Invalid 👉 ${k} 👈 declaration for ➡ ${el[0]} in ➡ menu.setting.js \n 🚩 Must be of type {String}`
89
+ if (entry[m].constructor !== String)
90
+ err = `Invalid 👉 ${m} 👈 declaration for ➡ ${el[0]} in ➡ menu.setting.js \n 🚩 Must be of type {String}`
69
91
  break
70
92
  }
71
93
  }
72
94
  }
73
-
74
- if (err) break
75
95
  }
76
96
  }
77
97
  }
@@ -88,7 +108,334 @@ const validatefileContent = (fName, fData, requiredArgs = {}) => {
88
108
  **/
89
109
  const validateVideoData = (data) => {
90
110
  const errorList = []
91
- if (process.env.NODE_ENV === 'development') {
111
+ if (import.meta.env.DEV) {
112
+ let errStringInConsole = null
113
+ let errString = null
114
+ const expectedKeys = [
115
+ 'id',
116
+ 'mSources',
117
+ 'mSubtitles',
118
+ 'mPoster',
119
+ 'mTranscript'
120
+ ]
121
+
122
+ if (!data || data.constructor !== Object || Object.keys(data).length < 1) {
123
+ errStringInConsole = `\n 💥 Invalid declaration for video element`
124
+ console.warn(
125
+ `%c WARNING!>>> VIDEO: ${errStringInConsole}`,
126
+ 'background: orange; color: white; display: block; border-radius:5px; margin:5px;'
127
+ )
128
+ errString = `Declaration invalide pour Objet video.`
129
+ errorList.push(errString)
130
+ }
131
+
132
+ if (!data['mSources']) {
133
+ errStringInConsole = ` Missing 👉 mSources 👈 declaration for video element`
134
+
135
+ errString = `l'Attribut 👉 mSources 👈 pour l'Objet video n'est pas defini. `
136
+ console.warn(
137
+ `%c WARNING!>>> ${errStringInConsole}`,
138
+ 'background: orange; color: white; display: block; border-radius:5px; margin:5px;'
139
+ )
140
+ errorList.push(errString)
141
+ }
142
+
143
+ //Start validation of keys in data
144
+ if (!errString) {
145
+ expectedKeys.forEach((k) => {
146
+ if (!data[k] && k !== 'mSources') return
147
+
148
+ switch (k) {
149
+ case 'mSources':
150
+ if (
151
+ data['mSources'].constructor !== Array ||
152
+ data['mSources'].length < 1
153
+ ) {
154
+ errStringInConsole =
155
+ '\n 💥 Invalid type declaration for mSources.\n 🚩 Must be of type Array'
156
+
157
+ errString = `l'Attribut 👉 mSources 👈 pour le media doit être de type Array`
158
+
159
+ errorList.push(errString)
160
+ console.warn(
161
+ `%c WARNING!>>> ${errStringInConsole}`,
162
+ 'background: orange; color: white; display: block; border-radius:5px; margin:5px;'
163
+ )
164
+ }
165
+ break
166
+
167
+ case 'mSubtitles':
168
+ {
169
+ //Validate required keys in Subtitle definition
170
+ let expectedKeys = ['label', 'src', 'srclang']
171
+ //we only accept one subtitle and must be defined as an Object with 3 keys
172
+ if (
173
+ data['mSubtitles'].constructor !== Array ||
174
+ !data['mSubtitles'].length
175
+ ) {
176
+ errStringInConsole = `\n 💥 Invalid type declaration for mSubtitles.\n 🚩 Must be of type Array with at list one Object defined with: ${expectedKeys}`
177
+
178
+ errString = `l'Attribut 👉 mSubtitles 👈 doit être de type Array avec au moins un Objet: {${expectedKeys}} `
179
+
180
+ console.warn(
181
+ `%c WARNING!>>> ${errStringInConsole}`,
182
+ 'background: orange; color: white; display: block; border-radius:5px; margin:5px;'
183
+ )
184
+
185
+ return errorList.push(errString)
186
+ }
187
+ //Validate definition for each Subtitle Object
188
+ for (const obj of data['mSubtitles']) {
189
+ const objIndex = data['mSubtitles'].indexOf(obj)
190
+ expectedKeys.forEach((expected) => {
191
+ if (!obj[expected]) {
192
+ errStringInConsole = `\n 💥 Missing key 👉 ${expected} 👈 for mSubtitles No.${
193
+ objIndex + 1
194
+ }.\n 🚩 required keys are: ${expectedKeys} `
195
+
196
+ errString = `l'Attribut 👉 ${expected} 👈 pour le sous-titre No.${
197
+ objIndex + 1
198
+ } n'est pas défini`
199
+
200
+ console.warn(
201
+ `%c WARNING!>>> ${errStringInConsole}`,
202
+ 'background: orange; color: white; display: block; border-radius:5px; margin:5px;'
203
+ )
204
+ return errorList.push(errString)
205
+ }
206
+
207
+ // Only none empty String type Accepted
208
+ if (
209
+ obj[expected].constructor === String &&
210
+ obj[expected].trim().length
211
+ )
212
+ return
213
+
214
+ errStringInConsole = `\n 💥 Invalid type declaration for 👉${expected}👈 in mSubtitles No.${
215
+ objIndex + 1
216
+ }.\n 🚩 Must be none-empty String `
217
+
218
+ errString = `l'Attribut 👉${expected}👈 du sous-titre No.${
219
+ objIndex + 1
220
+ } doit être de type String et ne peut pas être vide. `
221
+
222
+ console.warn(
223
+ `%c WARNING!>>> ${errStringInConsole}`,
224
+ 'background: orange; color: white; display: block; border-radius:5px; margin:5px;'
225
+ )
226
+
227
+ errorList.push(errString)
228
+ })
229
+ }
230
+ }
231
+ break
232
+ case 'mPoster':
233
+ //Only type String allowed and must not be empty
234
+ if (
235
+ data['mPoster'] &&
236
+ data['mPoster'].constructor == String &&
237
+ data['mPoster'].trim().length
238
+ )
239
+ return
240
+
241
+ errStringInConsole = `\n 💥 Invalid type declaration for 👉 mPoster 👈.\n 🚩 Must be none-empty String `
242
+
243
+ errString = `l'Attribut 👉 mPoster 👈 doit être de type String et ne peut pas être vide. `
244
+
245
+ errorList.push(errString)
246
+ console.warn(
247
+ `%c WARNING!>>> VIDEO: ${errStringInConsole}`,
248
+ 'background: orange; color: white; display: block; border-radius:5px; margin:5px;'
249
+ )
250
+
251
+ break
252
+ case 'mTranscript':
253
+ //Only type String allowed and must not be empty
254
+ if (
255
+ data['mTranscript'] &&
256
+ data['mTranscript'].constructor == String &&
257
+ data['mTranscript'].trim().length
258
+ )
259
+ return
260
+
261
+ errStringInConsole = `\n 💥 Invalid type declaration for 👉 mTranscript 👈 .\n 🚩 Must be none-empty String `
262
+
263
+ errString = `l'Attribut 👉 mTranscript 👈 doit être de type String et ne peut pas être vide. `
264
+
265
+ console.warn(
266
+ `%c WARNING!>>> VIDEO: ${errStringInConsole}`,
267
+ 'background: orange; color: white; display: block; border-radius:5px; margin:5px;'
268
+ )
269
+ errorList.push(errString)
270
+
271
+ break
272
+ }
273
+ })
274
+ }
275
+ }
276
+ return errorList
277
+ }
278
+
279
+ /**
280
+ * @description Validator for the content of audio props
281
+ * @param {Object} data- Object definition to validate
282
+ **/
283
+ const validateAudioData = (data) => {
284
+ const errorList = []
285
+ let currentProperties = Object.getOwnPropertyNames(data)
286
+ if (import.meta.env.DEV) {
287
+ //errorList.push('test')
288
+
289
+ const requiredProperties = ['id', 'mTitle', 'mSources', 'mTranscript']
290
+
291
+ const optionalProperties = ['mPoster', 'mAlt']
292
+
293
+ const allProperties = [
294
+ ...requiredProperties,
295
+ ...optionalProperties,
296
+ ...['__ob__']
297
+ ]
298
+
299
+ let errStringInConsole = null
300
+ let errString = null
301
+
302
+ //** Validate if data exist and is an object**/
303
+ if (!data || data.constructor !== Object || Object.keys(data).length < 1) {
304
+ errStringInConsole = `\n 💥 Invalid declaration for audio element`
305
+ console.warn(
306
+ `%c WARNING!>>> AUDIO: ${errStringInConsole}`,
307
+ 'background: orange; color: white; display: block; border-radius:5px; margin:5px;'
308
+ )
309
+ errString = `Déclaration invalide pour Objet audData. Ce doit être un objet non vide.`
310
+ errorList.push(errString)
311
+ return errorList
312
+ }
313
+ //** Validate if all the properties are right**/
314
+ let wrongProperties = checkerWrong(allProperties, currentProperties)
315
+ if (wrongProperties.length > 0) {
316
+ console.warn(
317
+ `%c WARNING!>>> AppCompAudio : audData property ${wrongProperties} invalid. Required properties: ${requiredProperties} . Optional properties: ${optionalProperties}`,
318
+ 'background: orange; color: white; display: block; margin:5px;'
319
+ )
320
+ errString = `Propriété invalide pour audData: ${wrongProperties}. Les propriétés requises sont: ${requiredProperties} et les propriétés facultatives sont: ${optionalProperties}`
321
+ errorList.push(errString)
322
+ return errorList
323
+ }
324
+
325
+ //** Validate if all the required properties are in the data */
326
+ let missingRequired = checkerMissing(requiredProperties, currentProperties)
327
+ if (missingRequired.length > 0) {
328
+ console.warn(
329
+ `%c WARNING!>>> AppCompAudio : audData missing required ${missingRequired} property. Required properties: ${requiredProperties} . Optional properties: ${optionalProperties}`,
330
+ 'background: orange; color: white; display: block; margin:5px;'
331
+ )
332
+ errString = `Propriété requise manquante pour audData: ${missingRequired}. Les propriétés requises sont: ${requiredProperties} et les propriétés facultatives sont: ${optionalProperties}`
333
+ errorList.push(errString)
334
+ return errorList
335
+ }
336
+ /***Validate data values */
337
+ if (errorList.length == 0) {
338
+ let invalidString = []
339
+ let invalidArray = []
340
+ let invalidProperties = []
341
+ currentProperties.forEach((p) => {
342
+ switch (p) {
343
+ case 'mTitle':
344
+ case 'mTranscript':
345
+ case 'mPoster':
346
+ case 'mAlt':
347
+ if (data[p] && data[p].constructor == String) {
348
+ data[p].trim().length == 0 ? invalidString.push(p) : ''
349
+ } else {
350
+ invalidString.push(p)
351
+ }
352
+ break
353
+ case 'mSources': {
354
+ if (data[p] && data[p].constructor == Array) {
355
+ data[p].length == 0 ? invalidArray.push(p) : ''
356
+ } else {
357
+ invalidArray.push(p)
358
+ }
359
+ if (invalidArray.length === 0) {
360
+ //Valider les attributs de mSources
361
+ for (let i in data[p]) {
362
+ let object = data[p][i]
363
+ if ('src' in object && 'type' in object) {
364
+ if (
365
+ object['src'].constructor != String &&
366
+ object['type'].constructor != String
367
+ ) {
368
+ invalidProperties.push(p)
369
+ } else {
370
+ object['src'].trim().length == 0
371
+ ? invalidString.push(p)
372
+ : ''
373
+ object['type'].trim().length == 0
374
+ ? invalidString.push(p)
375
+ : ''
376
+ }
377
+ } else {
378
+ invalidProperties.push(p)
379
+ }
380
+ }
381
+ }
382
+ break
383
+ }
384
+ }
385
+ })
386
+ //Display error for each type
387
+ //String
388
+ let sL = invalidString.length
389
+ if (sL > 0) {
390
+ errStringInConsole = `\n 💥 Invalid value type for 👉${invalidString}👈 \n 🚩 Must be none-empty String `
391
+
392
+ errString = `${sL > 1 ? 'Les ' : "L'"}attribut${
393
+ sL > 1 ? 's ' : ''
394
+ } 👉${invalidString}👈 doi${
395
+ sL > 1 ? 'ven' : ''
396
+ }t être de type String et ne peu${sL > 1 ? 'ven' : ''}t pas être vide. `
397
+
398
+ console.warn(
399
+ `%c WARNING!>>> ${errStringInConsole}`,
400
+ 'background: orange; color: white; display: block; border-radius:5px; margin:5px;'
401
+ )
402
+ errorList.push(errString)
403
+ }
404
+ //Array
405
+ let aL = invalidArray.length
406
+ if (aL > 0) {
407
+ errStringInConsole = `\n 💥 Invalid value type for 👉${invalidArray}👈 \n 🚩 Must be none-empty Array`
408
+
409
+ errString = `${aL > 1 ? 'Les ' : "L'"}attribut${
410
+ aL > 1 ? 's ' : ''
411
+ } 👉${invalidArray}👈 doi${
412
+ sL > 1 ? 'ven' : ''
413
+ }t être de type Array et ne peu${aL > 1 ? 'ven' : ''}t pas être vide. `
414
+
415
+ console.warn(
416
+ `%c WARNING!>>> ${errStringInConsole}`,
417
+ 'background: orange; color: white; display: block; border-radius:5px; margin:5px;'
418
+ )
419
+ errorList.push(errString)
420
+ }
421
+ let pL = invalidProperties.length
422
+ if (pL > 0) {
423
+ errStringInConsole = `\n 💥 Invalid value type for 👉src and/or type👈 in mSources \n 🚩 They are required and must be none-empty strings`
424
+
425
+ errString = `${pL > 1 ? 'Les ' : "L'"}attribut${
426
+ pL > 1 ? 's ' : ''
427
+ } 👉src and/or type👈 de mSources doi${
428
+ sL > 1 ? 'ven' : ''
429
+ }t être de type String et ne peu${pL > 1 ? 'ven' : ''}t pas être vide. `
430
+
431
+ console.warn(
432
+ `%c WARNING!>>> ${errStringInConsole}`,
433
+ 'background: orange; color: white; display: block; border-radius:5px; margin:5px;'
434
+ )
435
+ errorList.push(errString)
436
+ }
437
+ }
438
+ /*if (import.meta.env.DEV) {
92
439
  let errStringInConsole = null
93
440
  let errString = null
94
441
  const expectedKeys = ['mSources', 'mSubtitles', 'mPoster', 'mTranscript']
@@ -242,8 +589,371 @@ const validateVideoData = (data) => {
242
589
  }
243
590
  })
244
591
  }
592
+ }*/
245
593
  }
246
594
  return errorList
247
595
  }
596
+ //Get all the invalids properties from the object
597
+ /*Add element from target array that are NOT in arr to the wrongArray*/
598
+ const checkerWrong = (arr, target) => {
599
+ let wrongArray = []
600
+ target.every((v) => {
601
+ if (arr.includes(v)) {
602
+ return true
603
+ } else {
604
+ wrongArray.push(v)
605
+ return true
606
+ }
607
+ })
608
+ return wrongArray
609
+ }
610
+ //Get all the required properties that are missing from the object
611
+ /*Add element from the arr that are NOT in target arr to the missingArray*/
612
+ const checkerMissing = (arr, target) => {
613
+ let missingArray = []
614
+ arr.every((v) => {
615
+ if (target.includes(v)) {
616
+ return true
617
+ } else {
618
+ missingArray.push(v)
619
+ return true
620
+ }
621
+ })
622
+ return missingArray
623
+ }
624
+
625
+ const ERR_TYPE = {
626
+ err0: `\n 💥 Missing \x1B[1m$attr$ \x1B[0mfor $comp$. \x1B[1m$attr$ \x1B[0m should be provided with following attributes: \x1B[1m{$data$}`,
627
+ err1: `\n 💥 Invalid declaration for \x1B[1m$wrd$ \x1B[0m object`,
628
+ 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`,
629
+ err3: `\n 💥 Missing required argument 👉\x1B[1m$key$\x1B[0m👈 in \x1B[1m$el$\x1B[0m. Required arguments are: \x1B[1m$args$`,
630
+ err4: `\n 💥 Missing required argument 👉\x1B[1m$key$\x1B[0m👈 in \x1B[1m$el$\x1B[0m. Required arguments are: \x1B[1m$args$`
631
+ }
632
+
633
+ const ERR_TYPE_MSG = {
634
+ 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>`,
635
+ err1: `\n Déclaration invalide pour <b>$wrd$</b>. Assurez-vous que l'application a du data.`,
636
+ 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`,
637
+ err3: `\n L'attribut 👉<b>$key$</b>👈 est manquant dans <b>$el$</b>. Les attributs requis sont: <b>$args$</b>`
638
+ }
639
+
640
+ /**
641
+ * @description Validator for the content of app data.
642
+ * App data is used as setting for the application
643
+ * @param {Object} data - the Object definition to validate
644
+ * @param {Boolean} silent - if Validator should diplay error in console
645
+ *
646
+ **/
647
+
648
+ const validateAppContent = (data, silent = false) => {
649
+ let errorInConsole = []
650
+ let errorList = []
651
+
652
+ const requiredArgs = [
653
+ 'lang',
654
+ 'specification',
655
+ 'id',
656
+ 'crs_id',
657
+ 'idb_id',
658
+ 'no_menu',
659
+ 'is_single_activity',
660
+ 'auto_next_activity'
661
+ ]
662
+
663
+ //Validate not empty data
664
+ if (Object.keys(data).length == 0) {
665
+ const reg = /(\$comp\$)|(\$data\$)|(\$attr\$)/g
666
+
667
+ errorInConsole.push(
668
+ ERR_TYPE.err0.replace(reg, (e) => {
669
+ if (e == '$comp$') return 'app-base'
670
+ if (e == '$data$') return requiredArgs.toString().replaceAll(',', ', ')
671
+ if (e == '$attr$') return 'app-config'
672
+ })
673
+ )
674
+
675
+ errorList.push(
676
+ ERR_TYPE_MSG.err0.replace(reg, (e) => {
677
+ if (e == '$comp$') return 'app-base'
678
+ if (e == '$data$') return requiredArgs.toString().replaceAll(',', ', ')
679
+ if (e == '$attr$') return 'app-config'
680
+ })
681
+ )
682
+
683
+ console.warn(errorInConsole[0])
684
+
685
+ return errorList
686
+ }
687
+
688
+ let stringType = ['lang', 'specification', 'id', 'crs_id', 'idb_id']
689
+ let boolType = [
690
+ 'no_menu',
691
+ 'is_single_activity',
692
+ 'auto_next_activity',
693
+ 'remote'
694
+ ]
695
+ let objectType = ['actor', 'linkedResource']
696
+ let optionalArgs = ['remote', 'actor', 'linkedResource']
697
+
698
+ const { errorInConsole: errCons, errorList: errList } = validateObjType(
699
+ data,
700
+ {
701
+ stringType,
702
+ boolType,
703
+ objectType
704
+ },
705
+ optionalArgs,
706
+ 'App.vue'
707
+ )
708
+
709
+ errorList = [...errorList, ...errList]
710
+ errorInConsole = [...errorInConsole, ...errCons]
711
+
712
+ //===========Optional Keys should be of correct type when declared =================//
713
+ // Has actor defined
714
+ if (data['actor']) {
715
+ let { errorInConsole: err1, errorList: err2 } = validateObjType(
716
+ data['actor'],
717
+ {
718
+ stringType: ['name', 'mbox']
719
+ },
720
+ 'actor'
721
+ )
722
+
723
+ errorList = [...errorList, ...err2]
724
+ errorInConsole = [...errorInConsole, ...err1]
725
+ }
726
+ // Has LinkedResource defined
727
+ if (data['linkedResource']) {
728
+ let { errorInConsole: err1, errorList: err2 } = validateObjType(
729
+ data['linkedResource'],
730
+ {
731
+ stringType: ['url', 'id']
732
+ },
733
+ 'linkedResource'
734
+ )
735
+
736
+ errorList = [...errorList, ...err2]
737
+ errorInConsole = [...errorInConsole, ...err1]
738
+ }
739
+ // Has endpointConfig defined
740
+ if (data['endpointConfig']) {
741
+ let { errorInConsole: err1, errorList: err2 } = validateObjType(
742
+ data['endpointConfig'],
743
+ {
744
+ stringType: ['auth', 'endpoint']
745
+ },
746
+ 'endpointConfig'
747
+ )
748
+ errorList = [...errorList, ...err2]
749
+ errorInConsole = [...errorInConsole, ...err1]
750
+ }
751
+ //================== END Optional Keys ====================//
752
+
753
+ //Should display error to console
754
+ if (errorList.length && !silent) {
755
+ let txt = '⚠️ You have the following Errors:'
756
+ console.group(`%c ${txt}`, 'background:#ffc13a7d')
757
+ errorInConsole.forEach((err) => console.warn(err))
758
+ console.groupEnd()
759
+ }
760
+
761
+ return errorList
762
+ }
763
+
764
+ /**
765
+ * @description - Method to validate that given object attributes hold expected types
766
+ * @param {Object} Obj - object to validate
767
+ * @param {Object} Args - List of expected type groups - each type group must be an array of attributes with the same type
768
+ * @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
769
+ * @param {Array} err - list off errors to be added to
770
+ * @return {Object} list of errors - {errorInConsole, errorList} : errorlist can be used to display messages on template and
771
+ * errorInConsole to display messages in browser console
772
+ * @exemple - Given $user= {name:'toto', username:'totoEscargot', id:'id001', age:23, books:['one', 'two', 'three'] }
773
+ * Use validator on $user: validateObjType($user, {stringType:['name', 'username' , 'id'], numbType:['age'], arrayType:['books']})
774
+ * Will fail if any listed attribute not in $user or have wrong value. Error messages will be in console
775
+ *
776
+ */
777
+
778
+ const validateObjType = (
779
+ Obj,
780
+ Args = {
781
+ boolType: null,
782
+ arrayType: null,
783
+ stringType: null,
784
+ objectType: null,
785
+ numbType: null
786
+ },
787
+ notRequiredArgs = null,
788
+ compName = 'component',
789
+ err = null
790
+ ) => {
791
+ let errorInConsole = err && err.errorInConsole ? err.errorInConsole : []
792
+ let errorList = err && err.errorList ? err.errorLIst : []
793
+ let optionalArgs =
794
+ notRequiredArgs && notRequiredArgs.length ? notRequiredArgs : []
795
+ //=====Expected Arguments validation =================//
796
+ //Should have an object argument
797
+ if (!Obj) throw new Error(`No valid arguments provided`)
798
+
799
+ //validate Args Keys type
800
+ for (const _type in Args) {
801
+ // Should be a required type
802
+ if (
803
+ ![
804
+ 'boolType',
805
+ 'arrayType',
806
+ 'stringType',
807
+ 'objectType',
808
+ 'numbType'
809
+ ].includes(_type)
810
+ )
811
+ throw new Error(`Unknown types declaration : ${_type}`)
812
+
813
+ if (Args[_type] && Args[_type].length) {
814
+ for (let el of Args[_type]) {
815
+ //Check that each given element is a string
816
+ if (el.constructor !== String)
817
+ throw new Error(
818
+ `Invalid type detected in ${JSON.stringify(
819
+ Args[_type]
820
+ )}. Item ${Args[_type].indexOf(el) + 1} should be a String`
821
+ )
822
+
823
+ let reg = /(\$el\$)|(\$type\$)|(\$attr\$)/g
824
+
825
+ let isOptionalArg = optionalArgs.includes(el) ? true : false
826
+
827
+ switch (true) {
828
+ // Check That each given element exist in data if not optional
829
+ case Obj[el] === undefined && !isOptionalArg: {
830
+ reg = /(\$key\$)|(\$el\$)|(\$args\$)/g
831
+ const reg2 = /\[|\]|/g
832
+
833
+ errorInConsole.push(
834
+ ERR_TYPE.err3.replace(reg, (e) => {
835
+ if (e == '$key$') return el
836
+ if (e == '$el$') return compName
837
+ if (e == '$args$') return JSON.stringify(Args[_type])
838
+ })
839
+ )
840
+
841
+ errorList.push(
842
+ ERR_TYPE_MSG.err3.replace(reg, (e) => {
843
+ if (e == '$key$') return el
844
+ if (e == '$el$') return compName || 'Composant'
845
+ if (e == '$args$')
846
+ return JSON.stringify(Args[_type]).replaceAll(reg2, '')
847
+ })
848
+ )
849
+ break
850
+ }
851
+ //Should have Correct Types $attr$ $el$ $type$
852
+ case _type == 'boolType' &&
853
+ Obj[el] !== undefined &&
854
+ Obj[el].constructor !== Boolean:
855
+ errorInConsole.push(
856
+ ERR_TYPE.err2.replace(reg, (e) => {
857
+ if (e == '$attr$') return compName || 'Composant'
858
+ if (e == '$el$') return el
859
+ if (e == '$type$') return 'Boolean'
860
+ })
861
+ )
862
+ errorList.push(
863
+ ERR_TYPE_MSG.err2.replace(reg, (e) => {
864
+ if (e == '$attr$') return compName || 'Composant'
865
+ if (e == '$el$') return el
866
+ if (e == '$type$') return 'Boolean'
867
+ })
868
+ )
869
+ break
870
+
871
+ case _type == 'stringType' &&
872
+ Obj[el] !== undefined &&
873
+ (Obj[el].constructor !== String || !Obj[el].trim().length):
874
+ errorInConsole.push(
875
+ ERR_TYPE.err2.replace(reg, (e) => {
876
+ if (e == '$attr$') return compName || 'Composant'
877
+ if (e == '$el$') return el
878
+ if (e == '$type$') return 'String'
879
+ })
880
+ )
881
+ errorList.push(
882
+ ERR_TYPE_MSG.err2.replace(reg, (e) => {
883
+ if (e == '$attr$') return compName || 'Composant'
884
+ if (e == '$el$') return el
885
+ if (e == '$type$') return 'String'
886
+ })
887
+ )
888
+ break
889
+
890
+ case _type == 'arrayType' &&
891
+ Obj[el] !== undefined &&
892
+ (Obj[el].constructor !== Array || !Obj[el].length):
893
+ errorInConsole.push(
894
+ ERR_TYPE.err2.replace(reg, (e) => {
895
+ if (e == '$attr$') return compName || 'Composant'
896
+ if (e == '$el$') return el
897
+ if (e == '$type$') return 'Array'
898
+ })
899
+ )
900
+ errorList.push(
901
+ ERR_TYPE_MSG.err2.replace(reg, (e) => {
902
+ if (e == '$attr$') return compName || 'Composant'
903
+ if (e == '$el$') return el
904
+ if (e == '$type$') return 'Array'
905
+ })
906
+ )
907
+ break
908
+
909
+ case _type == 'numberType' &&
910
+ Obj[el] !== undefined &&
911
+ Obj[el].constructor !== Number:
912
+ errorInConsole.push(
913
+ ERR_TYPE.err2.replace(reg, (e) => {
914
+ if (e == '$attr$') return compName || 'Composant'
915
+ if (e == '$el$') return el
916
+ if (e == '$type$') return 'Number'
917
+ })
918
+ )
919
+ errorList.push(
920
+ ERR_TYPE_MSG.err2.replace(reg, (e) => {
921
+ if (e == '$attr$') return compName || 'Composant'
922
+ if (e == '$el$') return el
923
+ if (e == '$type$') return 'Number'
924
+ })
925
+ )
926
+ break
927
+
928
+ case _type == 'objectType' &&
929
+ Obj[el] !== undefined &&
930
+ Obj[el].constructor !== Object:
931
+ errorInConsole.push(
932
+ ERR_TYPE.err2.replace(reg, (e) => {
933
+ if (e == '$attr$') return compName || 'Composant'
934
+ if (e == '$el$') return el
935
+ if (e == '$type$') return 'Object'
936
+ })
937
+ )
938
+ errorList.push(
939
+ ERR_TYPE_MSG.err2.replace(reg, (e) => {
940
+ if (e == '$attr$') return compName || 'Composant'
941
+ if (e == '$el$') return el
942
+ if (e == '$type$') return 'Object'
943
+ })
944
+ )
945
+ break
946
+ }
947
+ }
948
+ }
949
+ }
950
+
951
+ return { errorInConsole, errorList }
952
+ }
248
953
 
249
- export { validateVideoData, validatefileContent }
954
+ export {
955
+ validateVideoData,
956
+ validateAudioData,
957
+ validatefileContent,
958
+ validateAppContent
959
+ }