fcad-core-dragon 2.0.0-beta.5 → 2.0.0-beta.6

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 (71) hide show
  1. package/.editorconfig +33 -33
  2. package/.eslintignore +29 -29
  3. package/.eslintrc.cjs +81 -81
  4. package/CHANGELOG +392 -377
  5. package/README.md +71 -71
  6. package/bk.scss +117 -117
  7. package/package.json +61 -61
  8. package/src/$locales/en.json +23 -25
  9. package/src/$locales/fr.json +22 -23
  10. package/src/assets/data/onboardingMessages.json +47 -47
  11. package/src/components/AppBase.vue +166 -99
  12. package/src/components/AppBaseButton.vue +2 -0
  13. package/src/components/AppBaseErrorDisplay.vue +438 -438
  14. package/src/components/AppBaseFlipCard.vue +84 -84
  15. package/src/components/AppBaseModule.vue +164 -106
  16. package/src/components/AppBasePage.vue +14 -4
  17. package/src/components/AppBasePopover.vue +41 -41
  18. package/src/components/AppCompAudio.vue +20 -48
  19. package/src/components/AppCompBranchButtons.vue +7 -53
  20. package/src/components/{AppCompTranscript.vue → AppCompContainer.vue} +8 -1
  21. package/src/components/AppCompInputRadioNext.vue +152 -152
  22. package/src/components/AppCompInputTextToFillNext.vue +171 -171
  23. package/src/components/AppCompJauge.vue +74 -74
  24. package/src/components/AppCompMenu.vue +429 -428
  25. package/src/components/AppCompMenuItem.vue +228 -228
  26. package/src/components/AppCompNavigation.vue +2 -2
  27. package/src/components/AppCompPlayBarNext.vue +5 -0
  28. package/src/components/AppCompPlayBarProgress.vue +82 -82
  29. package/src/components/AppCompSVGNext.vue +2 -3
  30. package/src/components/AppCompSettingsMenu.vue +172 -172
  31. package/src/components/AppCompVideoPlayer.vue +17 -15
  32. package/src/composables/useQuiz.js +206 -206
  33. package/src/externalComps/ModuleView.vue +22 -22
  34. package/src/externalComps/SummaryView.vue +91 -91
  35. package/src/main.js +34 -29
  36. package/src/mixins/$mediaMixins.js +819 -819
  37. package/src/mixins/timerMixin.js +155 -155
  38. package/src/module/stores/appStore.js +1 -1
  39. package/src/module/xapi/ADL.js +144 -4
  40. package/src/module/xapi/Crypto/Hasher.js +241 -241
  41. package/src/module/xapi/Crypto/WordArray.js +278 -278
  42. package/src/module/xapi/Crypto/algorithms/BufferedBlockAlgorithm.js +103 -103
  43. package/src/module/xapi/Crypto/algorithms/C_algo.js +315 -315
  44. package/src/module/xapi/Crypto/algorithms/HMAC.js +9 -9
  45. package/src/module/xapi/Crypto/algorithms/SHA1.js +9 -9
  46. package/src/module/xapi/Crypto/encoders/Base.js +105 -105
  47. package/src/module/xapi/Crypto/encoders/Base64.js +99 -99
  48. package/src/module/xapi/Crypto/encoders/Hex.js +61 -61
  49. package/src/module/xapi/Crypto/encoders/Latin1.js +61 -61
  50. package/src/module/xapi/Crypto/encoders/Utf8.js +45 -45
  51. package/src/module/xapi/Statement/agent.js +55 -55
  52. package/src/module/xapi/Statement/index.js +259 -259
  53. package/src/module/xapi/Statement/statement.js +253 -253
  54. package/src/module/xapi/utils.js +167 -167
  55. package/src/module/xapi/verbs.js +294 -294
  56. package/src/module/xapi/wrapper copy.js +1963 -0
  57. package/src/module/xapi/wrapper.js +121 -188
  58. package/src/module/xapi/xapiStatement.js +444 -444
  59. package/src/plugins/bus.js +8 -8
  60. package/src/plugins/gsap.js +14 -14
  61. package/src/plugins/helper.js +0 -1
  62. package/src/plugins/i18n.js +44 -44
  63. package/src/plugins/save.js +37 -37
  64. package/src/plugins/scorm.js +287 -287
  65. package/src/plugins/xapi.js +11 -11
  66. package/src/public/index.html +33 -33
  67. package/src/router/index.js +2 -1
  68. package/src/router/routes.js +312 -312
  69. package/src/shared/generalfuncs.js +210 -210
  70. package/src/shared/validators.js +2 -0
  71. package/src/components/AppCompPlayBar.vue +0 -1217
@@ -34,7 +34,7 @@
34
34
  <audio
35
35
  :id="id"
36
36
  ref="m-audio"
37
- @loadedmetadata="updateMediaData($event)"
37
+ @loadedmetadata="updateMediaDataAudio($event.target)"
38
38
  >
39
39
  <source
40
40
  v-for="(aSource, index) in mSources"
@@ -128,75 +128,47 @@ export default {
128
128
 
129
129
  methods: {
130
130
  ...mapActions(useAppStore, ['updateCurrentMediaElements']),
131
+ /**
132
+ * @description search the DOM for medias with duplicated ID declaration in the page
133
+ * @return return Array of all DOM MediaElement with same id
134
+ */
135
+ checkDuplicatedID() {
136
+ const mediaList = document.querySelectorAll('.__media-container')
137
+ const duplicate = Array.from(mediaList).filter((media) =>
138
+ media.id.includes(this.id)
139
+ )
140
+ return duplicate
141
+ },
131
142
  /**
132
143
  * @description update the information for the mediaElement in the store
133
144
  * @param {htmlElement} e
134
145
  * @fires update-page to AppBaseModule.vue
135
146
  */
136
- updateMediaData(e) {
147
+ updateMediaDataAudio(e) {
137
148
  //dispatch loading status of for this component
138
- this.$bus.$emit('set-comp-status', 'AppCompMediaPlayer', 'loading')
149
+ this.$bus.$emit('set-comp-status', 'AppCompAudioPlayer', 'loading')
139
150
  this.$bus.$emit('update-media-duration')
140
151
 
141
- //Should Check that the the media Element is unique im Media Liste
142
- const { mElements } = this.getCurrentPage
143
-
144
- const hasEntry = mElements.findLastIndex(
145
- (media) => media.id === e.target.id
146
- )
147
-
148
- if (hasEntry !== -1) {
149
- // Should report Error to Console and Component template about this media
150
- const errmsg = `Cet élément a le même ID q'un autre media. Vous ne devez pas avoir de médias avec le même ID dans une page.`
152
+ if (this.checkDuplicatedID().length > 1) {
153
+ const errmsg = `Cet élément a le même ID <b>${this.id}</b>q'un autre media. Vous ne devez pas avoir de médias avec le même ID dans une page.`
151
154
 
152
155
  console.warn(
153
- `%c WARNING!>>> You cannot use the same ID in your media elements for your page.`,
156
+ `%c WARNING!>>> You cannot use the same ID (${this.id}) in your media elements for your page.`,
154
157
  'background: orange; color: white; display: block; border-radius:5px; margin:5px;'
155
158
  )
156
159
 
157
- this.$bus.$emit('set-comp-status', 'AppCompMediaPlayer', 'ready')
160
+ this.$bus.$emit('set-comp-status', 'AppCompAudioPlayer', 'ready')
158
161
  return this.hasErr.push(errmsg)
159
162
  }
160
163
 
161
- this.updateCurrentMediaElements(e.target).then(() => {
164
+ this.updateCurrentMediaElements(e).then(() => {
162
165
  this.isSet = true
163
- this.$bus.$emit('set-comp-status', 'AppCompMediaPlayer', 'ready')
166
+ this.$bus.$emit('set-comp-status', 'AppCompAudioPlayer', 'ready')
164
167
  })
165
168
  },
166
169
  errorHandling(e) {
167
170
  this.hasSourceLoadingError = true
168
- },
169
- // ===================================TEST TRANSCRIP================================================
170
- /**
171
- * @description Fetching method for transcript
172
- * @summary Fetch a transcript from HTML file to display. File URL is defined in the media data
173
- * and return its content for display
174
- * @return {String} HTML string
175
- */
176
- async fetchTranscript() {
177
- try {
178
- //const tFile = 'exemple_transcript2.html'
179
- const { mTranscript } = this.mediaToPlay
180
- const tFile = mTranscript
181
- if (!tFile) throw new Error('Missing transcript File!')
182
-
183
- // validate file types. Only .html are allowed
184
- if (!tFile.endsWith('.html'))
185
- throw new Error(
186
- 'Invalid valid transcript file. \n Expecting .html file'
187
- )
188
-
189
- const fileUrl = !tFile.includes('/') ? `./${tFile}` : tFile //allow passing file in Public folder
190
- // const fileUrl = new URL(tFile, import.meta.url))
191
- const res = await axios.get(fileUrl, { responseType: 'blob' })
192
- const content = await res.data.text()
193
-
194
- return content
195
- } catch (err) {
196
- console.warn("YOU'VE GOT AN ERROR!\n", err)
197
- }
198
171
  }
199
- // ===================================TEST TRANSCRIP================================================
200
172
  }
201
173
  }
202
174
  </script>
@@ -68,10 +68,8 @@ Si la composante est appelée sans prop, les boutons par défaut seront génér
68
68
  <v-card class="mx-auto" max-width="15rem">
69
69
  <v-img :src="branch.imgFile" :alt="`${branch.imgAlt}`" cover />
70
70
 
71
- <v-card-title>{{ branch.title }}</v-card-title>
72
- <v-card-text>
73
- {{ branch.text }}
74
- </v-card-text>
71
+ <v-card-title v-html="branch.title"></v-card-title>
72
+ <v-card-text v-html="branch.text"></v-card-text>
75
73
 
76
74
  <app-comp-button-progress
77
75
  :set-target="sidebar"
@@ -136,35 +134,6 @@ export default {
136
134
  break
137
135
  }
138
136
  }
139
- //Start validation of required keys
140
- if (isValid) {
141
- const requiredKeys = ['imgFile', 'title', 'text', 'brchName']
142
-
143
- for (let el of dataArray) {
144
- //Validate that require key exist for each element in card
145
- for (let k of requiredKeys) {
146
- let index = dataArray.indexOf(el)
147
-
148
- if (!el[k]) {
149
- isValid = false
150
- errMsg = `\n 💥 Missing 👉 ${k} 👈 in object ${
151
- index + 1
152
- } in ➡ card \n 🚩Allowed indexes are: 👉 ${requiredKeys}`
153
- break
154
- } else {
155
- if (el[k].constructor !== String) {
156
- errMsg = `\n 💥 Invalid 👉 ${k} 👈 declaration in ➡ object ${
157
- index + 1
158
- } ➡ of card. \n 🚩 Must be of type {String}`
159
- isValid = false
160
- break
161
- }
162
- }
163
- if (!isValid) break
164
- }
165
- if (!isValid) break
166
- }
167
- }
168
137
  }
169
138
 
170
139
  if (errMsg) console.error(`🧱 app-comp-branch-buttons \n ${errMsg}`)
@@ -317,7 +286,11 @@ export default {
317
286
  btnTitle
318
287
  }
319
288
 
320
- if (typeof branchData.imgAlt === 'undefined' && import.meta.env.DEV) {
289
+ if (
290
+ typeof branchData.imgAlt === 'undefined' &&
291
+ branchData.imgFile === 'undefined' &&
292
+ import.meta.env.DEV
293
+ ) {
321
294
  branchData.imgAlt = ''
322
295
  console.warn(
323
296
  `Bouton d’embranchement: ALT image sans valeur définie pour ${branchData.id}`
@@ -407,27 +380,8 @@ export default {
407
380
  }
408
381
  //Start validation of required keys
409
382
  if (isValid) {
410
- const requiredKeys = ['imgFile', 'title', 'text', 'brchName']
411
-
412
383
  for (let el of this.cards) {
413
384
  let index = this.cards.indexOf(el)
414
- //Validate that require key exist for each element in card
415
- for (let k of requiredKeys) {
416
- if (!el[k]) {
417
- isValid = false
418
- errMsg = `l'Attribut 👉 ${k} 👈 pour la carte ${index + 1} n'as pas été défini`
419
- break
420
- } else {
421
- if (el[k].constructor !== String) {
422
- errMsg = `l'Attribut 👉 ${k} 👈 pour la carte ${
423
- index + 1
424
- } doit être de type {String}`
425
- isValid = false
426
- break
427
- }
428
- }
429
- if (!isValid) break
430
- }
431
385
 
432
386
  // Start validation of existing branch for this element
433
387
  let searchEl = this.branchs.find((b) =>
@@ -1,13 +1,20 @@
1
1
  <template>
2
- <div id="transcript-container" v-html="content"></div>
2
+ <div :id="id" v-html="content"></div>
3
3
  </template>
4
4
  <script>
5
5
  export default {
6
6
  props: {
7
+ id: {
8
+ type: String,
9
+ default: 'shadow-container'
10
+ },
7
11
  content: {
8
12
  type: String,
9
13
  default: `Hello Wolrd!`
10
14
  }
15
+ },
16
+ mounted() {
17
+ console.log('😶‍🌫️ ', this.$props.id)
11
18
  }
12
19
  }
13
20
  </script>
@@ -1,152 +1,152 @@
1
- <!-- About this Component--
2
- * Renders a RADIO BUTTON input to display choices of response for the Quiz component
3
- * Related Quiz to question: REPONSE_UNIQUE
4
- * Receives the a data object defined by user
5
- * Used by AppCompQuizNext
6
- * Uses useQuiz composable
7
- -->
8
-
9
- <template>
10
- <div class="input-box">
11
- <fieldset>
12
- <legend
13
- :id="`lgd_${inputDataId}`"
14
- class="sr-only"
15
- tabindex="-1"
16
- v-html="$t('quizState.answers')"
17
- />
18
-
19
- <template
20
- v-for="choixReponse in quizInputDataValue"
21
- :Key="`div_chx_${inputDataId}-${choixReponse.id}`"
22
- >
23
- <div class="box-radio" role="group">
24
- <label
25
- :key="`lbl_chx_${inputDataId}_${choixReponse.id}`"
26
- :for="`chx_${inputDataId}_${choixReponse.id}`"
27
- :class="classInput(choixReponse.id)"
28
- class="radio-label"
29
- >
30
- <input
31
- :id="`chx_${inputDataId}_${choixReponse.id}`"
32
- :key="`chx_${inputDataId}_${choixReponse.id}`"
33
- v-model="inputUniqueValue"
34
- :disabled="quizLimitActive"
35
- type="radio"
36
- :value="choixReponse.id"
37
- :name="`btn-radios-${inputDataId}`"
38
- class="radio-input"
39
- :aria-labelledby="`span_${inputDataId}_${choixReponse.id}`"
40
- />
41
-
42
- <span
43
- :id="`span_${inputDataId}_${choixReponse.id}`"
44
- aria-hidden="true"
45
- class="radio-contenu"
46
- v-html="choixReponse.value"
47
- />
48
- <span
49
- :id="`${inputDataId}_${choixReponse.id}-msg-erreur`"
50
- :key="`msg_chx_${inputDataId}_${choixReponse.id}`"
51
- class="sr-only"
52
- >
53
- {{ messageAccessibility(choixReponse.id) }}
54
- </span>
55
- </label>
56
- </div>
57
- </template>
58
- </fieldset>
59
- </div>
60
- </template>
61
- <script>
62
- import { useQuiz } from '../composables/useQuiz'
63
- import { toRefs } from 'vue'
64
- export default {
65
- name: 'AppCompInputRadioNext',
66
-
67
- props: {
68
- quizType: {
69
- type: String,
70
- default: ''
71
- },
72
- inputDataId: {
73
- type: String,
74
- default: ''
75
- },
76
-
77
- inputData: {
78
- type: Array,
79
- default: () => []
80
- },
81
- quizInputType: {
82
- type: String,
83
- default: ''
84
- },
85
- solution: {
86
- type: String,
87
- default: ''
88
- }, //may be null
89
- showSolution: {
90
- type: Boolean,
91
- default: false
92
- },
93
- shuffleAnswers: {
94
- type: Boolean,
95
- default: false
96
- },
97
- quizLimitActive: {
98
- type: Boolean,
99
- default: false
100
- }, //use to set if quiz should be active or not
101
-
102
- quizSubmit: {
103
- type: Boolean,
104
- default: false
105
- } //use to call a submit
106
- },
107
- emits: ['input-change'],
108
- setup(props) {
109
- const { shuffleArray, classInput, messageAccessibility } = useQuiz(
110
- toRefs(props)
111
- )
112
-
113
- return { shuffleArray, classInput, messageAccessibility }
114
- },
115
- data() {
116
- return {
117
- quizInputDataValue: [],
118
- inputUniqueValue: null //not using quizInputUnique because quizInputUnique is a prop
119
- }
120
- },
121
-
122
- computed: {},
123
-
124
- watch: {
125
- // /**
126
- // * @description to pass value to AppCompQuiz
127
- // * @fires input-change to AppCompQuiz.vue
128
- // */
129
- inputUniqueValue: {
130
- deep: true,
131
- handler(newValue) {
132
- this.$emit('input-change', newValue)
133
- }
134
- }
135
- },
136
-
137
- mounted() {
138
- this.initQuiz()
139
- },
140
-
141
- methods: {
142
- initQuiz() {
143
- this.inputUniqueValue = this.quizInputType
144
- if (this.shuffleAnswers) {
145
- this.quizInputDataValue = this.shuffleArray(this.inputData)
146
- } else {
147
- this.quizInputDataValue = this.inputData
148
- }
149
- }
150
- }
151
- }
152
- </script>
1
+ <!-- About this Component--
2
+ * Renders a RADIO BUTTON input to display choices of response for the Quiz component
3
+ * Related Quiz to question: REPONSE_UNIQUE
4
+ * Receives the a data object defined by user
5
+ * Used by AppCompQuizNext
6
+ * Uses useQuiz composable
7
+ -->
8
+
9
+ <template>
10
+ <div class="input-box">
11
+ <fieldset>
12
+ <legend
13
+ :id="`lgd_${inputDataId}`"
14
+ class="sr-only"
15
+ tabindex="-1"
16
+ v-html="$t('quizState.answers')"
17
+ />
18
+
19
+ <template
20
+ v-for="choixReponse in quizInputDataValue"
21
+ :Key="`div_chx_${inputDataId}-${choixReponse.id}`"
22
+ >
23
+ <div class="box-radio" role="group">
24
+ <label
25
+ :key="`lbl_chx_${inputDataId}_${choixReponse.id}`"
26
+ :for="`chx_${inputDataId}_${choixReponse.id}`"
27
+ :class="classInput(choixReponse.id)"
28
+ class="radio-label"
29
+ >
30
+ <input
31
+ :id="`chx_${inputDataId}_${choixReponse.id}`"
32
+ :key="`chx_${inputDataId}_${choixReponse.id}`"
33
+ v-model="inputUniqueValue"
34
+ :disabled="quizLimitActive"
35
+ type="radio"
36
+ :value="choixReponse.id"
37
+ :name="`btn-radios-${inputDataId}`"
38
+ class="radio-input"
39
+ :aria-labelledby="`span_${inputDataId}_${choixReponse.id}`"
40
+ />
41
+
42
+ <span
43
+ :id="`span_${inputDataId}_${choixReponse.id}`"
44
+ aria-hidden="true"
45
+ class="radio-contenu"
46
+ v-html="choixReponse.value"
47
+ />
48
+ <span
49
+ :id="`${inputDataId}_${choixReponse.id}-msg-erreur`"
50
+ :key="`msg_chx_${inputDataId}_${choixReponse.id}`"
51
+ class="sr-only"
52
+ >
53
+ {{ messageAccessibility(choixReponse.id) }}
54
+ </span>
55
+ </label>
56
+ </div>
57
+ </template>
58
+ </fieldset>
59
+ </div>
60
+ </template>
61
+ <script>
62
+ import { useQuiz } from '../composables/useQuiz'
63
+ import { toRefs } from 'vue'
64
+ export default {
65
+ name: 'AppCompInputRadioNext',
66
+
67
+ props: {
68
+ quizType: {
69
+ type: String,
70
+ default: ''
71
+ },
72
+ inputDataId: {
73
+ type: String,
74
+ default: ''
75
+ },
76
+
77
+ inputData: {
78
+ type: Array,
79
+ default: () => []
80
+ },
81
+ quizInputType: {
82
+ type: String,
83
+ default: ''
84
+ },
85
+ solution: {
86
+ type: String,
87
+ default: ''
88
+ }, //may be null
89
+ showSolution: {
90
+ type: Boolean,
91
+ default: false
92
+ },
93
+ shuffleAnswers: {
94
+ type: Boolean,
95
+ default: false
96
+ },
97
+ quizLimitActive: {
98
+ type: Boolean,
99
+ default: false
100
+ }, //use to set if quiz should be active or not
101
+
102
+ quizSubmit: {
103
+ type: Boolean,
104
+ default: false
105
+ } //use to call a submit
106
+ },
107
+ emits: ['input-change'],
108
+ setup(props) {
109
+ const { shuffleArray, classInput, messageAccessibility } = useQuiz(
110
+ toRefs(props)
111
+ )
112
+
113
+ return { shuffleArray, classInput, messageAccessibility }
114
+ },
115
+ data() {
116
+ return {
117
+ quizInputDataValue: [],
118
+ inputUniqueValue: null //not using quizInputUnique because quizInputUnique is a prop
119
+ }
120
+ },
121
+
122
+ computed: {},
123
+
124
+ watch: {
125
+ // /**
126
+ // * @description to pass value to AppCompQuiz
127
+ // * @fires input-change to AppCompQuiz.vue
128
+ // */
129
+ inputUniqueValue: {
130
+ deep: true,
131
+ handler(newValue) {
132
+ this.$emit('input-change', newValue)
133
+ }
134
+ }
135
+ },
136
+
137
+ mounted() {
138
+ this.initQuiz()
139
+ },
140
+
141
+ methods: {
142
+ initQuiz() {
143
+ this.inputUniqueValue = this.quizInputType
144
+ if (this.shuffleAnswers) {
145
+ this.quizInputDataValue = this.shuffleArray(this.inputData)
146
+ } else {
147
+ this.quizInputDataValue = this.inputData
148
+ }
149
+ }
150
+ }
151
+ }
152
+ </script>