fcad-core-dragon 2.0.0-beta.2 → 2.0.0-beta.3

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 (103) hide show
  1. package/.editorconfig +33 -33
  2. package/.eslintignore +29 -29
  3. package/.eslintrc.cjs +81 -81
  4. package/CHANGELOG +364 -364
  5. package/README.md +71 -71
  6. package/bk.scss +117 -117
  7. package/package.json +61 -47
  8. package/src/$locales/en.json +143 -193
  9. package/src/$locales/fr.json +105 -194
  10. package/src/assets/data/onboardingMessages.json +47 -47
  11. package/src/components/AppBase.vue +1054 -1049
  12. package/src/components/AppBaseButton.vue +87 -91
  13. package/src/components/AppBaseErrorDisplay.vue +438 -428
  14. package/src/components/AppBaseFlipCard.vue +84 -83
  15. package/src/components/AppBaseModule.vue +1673 -1666
  16. package/src/components/AppBasePage.vue +779 -324
  17. package/src/components/AppBasePopover.vue +41 -0
  18. package/src/components/AppCompAudio.vue +234 -266
  19. package/src/components/AppCompBranchButtons.vue +552 -571
  20. package/src/components/AppCompButtonProgress.vue +126 -132
  21. package/src/components/AppCompCarousel.vue +298 -196
  22. package/src/components/{AppCompInputCheckBox.vue → AppCompInputCheckBoxNext.vue} +195 -233
  23. package/src/components/AppCompInputDropdownNext.vue +159 -0
  24. package/src/components/{AppCompInputRadio.vue → AppCompInputRadioNext.vue} +152 -162
  25. package/src/components/{AppCompInputTextBox.vue → AppCompInputTextNext.vue} +106 -91
  26. package/src/components/AppCompInputTextTableNext.vue +141 -0
  27. package/src/components/AppCompInputTextToFillDropdownNext.vue +230 -0
  28. package/src/components/{AppCompInputTextToFillText.vue → AppCompInputTextToFillNext.vue} +171 -164
  29. package/src/components/AppCompJauge.vue +74 -67
  30. package/src/components/AppCompMenu.vue +413 -402
  31. package/src/components/AppCompMenuItem.vue +228 -191
  32. package/src/components/AppCompNavigation.vue +960 -945
  33. package/src/components/AppCompNoteCall.vue +133 -141
  34. package/src/components/AppCompNoteCredit.vue +292 -267
  35. package/src/components/AppCompPlayBar.vue +1218 -1271
  36. package/src/components/AppCompPlayBarNext.vue +2052 -0
  37. package/src/components/AppCompPlayBarProgress.vue +82 -73
  38. package/src/components/AppCompPopUpNext.vue +503 -0
  39. package/src/components/{AppCompQuiz.vue → AppCompQuizNext.vue} +2904 -2975
  40. package/src/components/AppCompQuizRecall.vue +276 -277
  41. package/src/components/{AppCompSVG.vue → AppCompSVGNext.vue} +347 -335
  42. package/src/components/AppCompSettingsMenu.vue +172 -169
  43. package/src/components/AppCompTableOfContent.vue +387 -385
  44. package/src/components/AppCompTranscript.vue +24 -19
  45. package/src/components/AppCompVideoPlayer.vue +368 -380
  46. package/src/components/AppCompViewDisplay.vue +6 -6
  47. package/src/components/BaseModule.vue +72 -71
  48. package/src/composables/useQuiz.js +206 -0
  49. package/src/externalComps/ModuleView.vue +22 -0
  50. package/src/externalComps/SummaryView.vue +91 -0
  51. package/src/main.js +272 -263
  52. package/src/mixins/$mediaMixins.js +819 -827
  53. package/src/mixins/timerMixin.js +155 -155
  54. package/src/module/stores/appStore.js +893 -0
  55. package/src/module/xapi/ADL.js +376 -376
  56. package/src/module/xapi/Crypto/Hasher.js +241 -241
  57. package/src/module/xapi/Crypto/WordArray.js +278 -278
  58. package/src/module/xapi/Crypto/algorithms/BufferedBlockAlgorithm.js +103 -103
  59. package/src/module/xapi/Crypto/algorithms/C_algo.js +315 -315
  60. package/src/module/xapi/Crypto/algorithms/HMAC.js +9 -9
  61. package/src/module/xapi/Crypto/algorithms/SHA1.js +9 -9
  62. package/src/module/xapi/Crypto/encoders/Base.js +105 -105
  63. package/src/module/xapi/Crypto/encoders/Base64.js +99 -99
  64. package/src/module/xapi/Crypto/encoders/Hex.js +61 -61
  65. package/src/module/xapi/Crypto/encoders/Latin1.js +61 -61
  66. package/src/module/xapi/Crypto/encoders/Utf8.js +45 -45
  67. package/src/module/xapi/Crypto/index.js +53 -53
  68. package/src/module/xapi/Statement/activity.js +47 -47
  69. package/src/module/xapi/Statement/agent.js +55 -55
  70. package/src/module/xapi/Statement/group.js +26 -26
  71. package/src/module/xapi/Statement/index.js +259 -259
  72. package/src/module/xapi/Statement/statement.js +253 -253
  73. package/src/module/xapi/Statement/statementRef.js +23 -23
  74. package/src/module/xapi/Statement/substatement.js +22 -22
  75. package/src/module/xapi/Statement/verb.js +36 -36
  76. package/src/module/xapi/activitytypes.js +17 -17
  77. package/src/module/xapi/launch.js +157 -157
  78. package/src/module/xapi/utils.js +167 -167
  79. package/src/module/xapi/verbs.js +294 -294
  80. package/src/module/xapi/wrapper.js +1963 -1963
  81. package/src/module/xapi/xapiStatement.js +444 -444
  82. package/src/plugins/bus.js +8 -3
  83. package/src/plugins/gsap.js +14 -17
  84. package/src/plugins/helper.js +308 -294
  85. package/src/plugins/i18n.js +44 -44
  86. package/src/plugins/idb.js +219 -212
  87. package/src/plugins/save.js +37 -37
  88. package/src/plugins/scorm.js +287 -287
  89. package/src/plugins/xapi.js +11 -11
  90. package/src/public/index.html +33 -21
  91. package/src/router/index.js +43 -40
  92. package/src/router/routes.js +312 -317
  93. package/src/shared/generalfuncs.js +210 -195
  94. package/src/shared/validators.js +1069 -959
  95. package/vite.config.js +27 -0
  96. package/src/components/AppCompInputDropdown.vue +0 -182
  97. package/src/components/AppCompInputTextTable.vue +0 -158
  98. package/src/components/AppCompInputTextToFillDropdown.vue +0 -257
  99. package/src/components/AppCompPopUp.vue +0 -583
  100. package/src/components/AppCompPopover.vue +0 -27
  101. package/src/mixins/$pageMixins.js +0 -415
  102. package/src/mixins/$quizMixins.js +0 -442
  103. package/src/module/store.js +0 -1014
@@ -1,415 +0,0 @@
1
- import { mapGetters } from 'vuex'
2
- /*
3
- @ Description: Mixins to extends general fonctionnalities in a page of an activity.
4
- @ Note: Must be used along component AppBasePage When creating page of an activity.
5
- * some data and information will not be correctly tracked if this mixins not used
6
- * when creating a page.
7
- */
8
- const $extendsPage = {
9
- // lazy laoding of components
10
- components: {
11
- AppCompQuiz: () => import('../components/AppCompQuiz.vue')
12
- },
13
-
14
- data: () => {
15
- return {
16
- userInteraction: {},
17
- state: null,
18
- anchorEnable: true,
19
- anchorInfo: null,
20
- drModeActive: null,
21
- error: null,
22
- notes: null,
23
- credits: null
24
- }
25
- },
26
- watch: {
27
- userInteraction: {
28
- handler(newValue) {
29
- /**
30
- * Objserve changes in the number of poperties to dispatch updates in the userdata in the Store
31
- */
32
- if (newValue && Object.entries(this.userInteraction).length) {
33
- const { activityRef, id, userInteraction } = this.$data
34
- this.$store.dispatch('updateUserMetaData', {
35
- activityRef,
36
- id,
37
- userInteraction
38
- })
39
- }
40
- },
41
- immediate: true,
42
- deep: true
43
- }
44
- },
45
- mounted() {
46
- this.userInteraction = this.getProgress() // Get the progress for the page
47
-
48
- if (this.userInteraction && this.userInteraction.state)
49
- // set the state of the page to existing record if any
50
- this.state = this.userInteraction.state
51
- else if (
52
- this.type === 'pg_menu' &&
53
- this.userInteraction.state !== 'completed'
54
- ) {
55
- this.state = 'completed' // set menu page state to completed
56
- } else this.state = 'started' // set the default state to started
57
-
58
- this.$set(this.userInteraction, 'state', this.state) // add the state to the userInteraction
59
-
60
- if (
61
- document.documentElement.scrollHeight <=
62
- document.documentElement.clientHeight + 20 &&
63
- this.type !== 'pg_branch'
64
- ) {
65
- this.completePage()
66
- }
67
-
68
- if (this.type === 'pg_branch') {
69
- this.$store.commit('UPDATE_CURRENT_BRANCH_PAGE', this.$data)
70
- }
71
-
72
- // get the data for note and credit
73
- let data = {
74
- note: this.notes,
75
- credit: this.credits
76
- }
77
-
78
- // give notes and credit information must be in tick because of life cycle
79
- this.$store.dispatch('updateCurrentnoteCredit', data)
80
-
81
- if (this.type == 'pg_branch') return //do not proceed to add listner when branch page
82
-
83
- window.addEventListener('scroll', this.onFirstScroll, { once: true }) //listener is removed when event fired
84
- },
85
-
86
- created() {
87
- if (this.type == 'pg_branch')
88
- this.$bus.$on('branch-page-viewed', this.completePageBranching)
89
-
90
- if (this.isBranchingPage)
91
- this.$store.commit('UPDATE_CURRENT_BRANCHING', this.$data)
92
-
93
- this.$bus.$on('media-viewed', this.setMediaViewed)
94
- this.$bus.$on('manage-media-players', this.managePlayingMedia)
95
- },
96
- beforeDestroy() {
97
- this.$bus.$off('branch-page-viewed', this.completePageBranching)
98
- this.$bus.$off('media-viewed', this.setMediaViewed)
99
- this.$bus.$off('manage-media-players', this.managePlayingMedia)
100
- window.removeEventListener('scroll', this.onFirstScroll, { once: true }) //in case user did not scroll
101
- window.removeEventListener('scroll', this.handleScroll)
102
- },
103
-
104
- methods: {
105
- onFirstScroll() {
106
- window.addEventListener('scroll', this.handleScroll)
107
- },
108
- /**
109
- * @description to handle the complete state for the gauge
110
- */
111
-
112
- handleScroll(event) {
113
- event
114
- /*
115
- * DocumentElement properties does not alway work properly on all Browser. To Ensure reliable value of its properties on all * Broswer we will calculate the Document Height by taking the maximum of body and documentElement height poperties.
116
- * ref:https://javascript.info/size-and-scroll-window
117
- */
118
-
119
- let scrollHeight = null
120
- let clientHeight = null
121
- let scrollTop = null
122
- scrollHeight = Math.max(
123
- document.body.scrollHeight,
124
- document.documentElement.scrollHeight,
125
- document.body.offsetHeight,
126
- document.documentElement.offsetHeight,
127
- document.body.clientHeight,
128
- document.documentElement.clientHeight
129
- )
130
- clientHeight = document.documentElement.clientHeight
131
- scrollTop = window.scrollY
132
-
133
- // //Set scroll limit reached at 150px above the document height.
134
- let scrollLimit = scrollHeight - 150
135
- let fullyScrolled = Math.round(clientHeight + scrollTop)
136
-
137
- //consider page completed when scolled value has reached or passed set limit
138
- if (fullyScrolled >= scrollLimit && this.state !== 'completed') {
139
- this.completePage()
140
- }
141
- },
142
- /**
143
- * @description set the state of the page to complete
144
- * @fires send-xapi-statement to AppBaseModule.vue
145
- */
146
- completePage() {
147
- if (
148
- this.type == 'pg_menu' ||
149
- this.state == 'completed' ||
150
- this.isBranchingPage ||
151
- this.type == 'pg_branch'
152
- )
153
- return
154
- this.state = 'completed'
155
-
156
- this.$set(this.userInteraction, 'state', this.state)
157
- },
158
-
159
- /**
160
- * @description set the state of the branching page to complete
161
- * @fires send-xapi-statement to AppBaseModule.vue
162
- */
163
- completePageBranching() {
164
- //Get the current branching from the store
165
- const currentBranching = this.$store.getters.getCurrentBranching
166
- if (currentBranching.id !== this.$route.meta.id) return
167
- if (currentBranching.state === 'completed') return
168
-
169
- const children = this.$route.meta.children
170
- let count = 0
171
- children.forEach((c) => {
172
- let progress = this.getProgress(c._ref)
173
-
174
- if (progress.state == 'completed') count += 1
175
- })
176
-
177
- if (count !== children.length) return
178
- currentBranching.state = 'completed' //set the state of the page to completed
179
- //update the userinteraction state
180
- this.$set(
181
- currentBranching.userInteraction,
182
- 'state',
183
- currentBranching.state
184
- )
185
- },
186
-
187
- /**
188
- * @description Get the user progress for the current page
189
- * @param {string} id (Otpional) - the id of the targeted page
190
- * @return {Oject} - the existing user data for the current page
191
- */
192
- getProgress(id) {
193
- id = id || this.id
194
-
195
- const record = this.$store.getters.getUserInteraction
196
- if (
197
- Object.entries(record).length &&
198
- record[this.activityRef] &&
199
- record[this.activityRef][id]
200
- ) {
201
- const { userInteraction } = record[this.activityRef][id]
202
- return userInteraction
203
- }
204
- return {}
205
- },
206
-
207
- anchorProgress() {
208
- const anchors = document.querySelectorAll('.anchor') // look for anchor
209
- const options = {
210
- root: null,
211
- threshold: 0
212
- }
213
-
214
- let anchorsComplete
215
- let indexStrt
216
- let anchorString
217
- let indexEnd
218
- let anchorComplete
219
-
220
- let target = document.querySelector('#App-base')
221
- // get anchor already seen
222
- anchorsComplete = this.getAnchorComplete()
223
-
224
- const observer = new IntersectionObserver((entries) => {
225
- // everytime the page passes a anchor
226
- observer.observe(target)
227
-
228
- entries.forEach((entry) => {
229
- // when it's visable in the page
230
-
231
- if (entry.isIntersecting) {
232
- // get the target
233
-
234
- this.anchorInfo = entry.target.classList
235
- indexStrt = this.anchorInfo.value.indexOf('anchor-')
236
- // work the string to get juste the anchor tag
237
- // must be the same as the class
238
- if (indexStrt == -1) {
239
- return
240
- }
241
-
242
- anchorString = this.anchorInfo.value.substring(indexStrt)
243
-
244
- indexEnd = anchorString.indexOf(' ')
245
- if (indexEnd != -1) {
246
- anchorComplete = anchorString.slice(0, indexEnd)
247
- } else {
248
- anchorComplete = anchorString
249
- }
250
-
251
- //get all the anchors of the current activity
252
- const anchors_list = this.getAnchorsForActivity(this.activityRef)
253
-
254
- //search for the current ancor
255
- const anc = anchors_list.find((a) => a.anchorTag === anchorComplete)
256
- //dispatch the current anchor to the store
257
- if (anc) {
258
- // update the store value for current section
259
- this.$store.dispatch('updateCurrentSection', anc)
260
- // Ask bread scrumb to update its information
261
-
262
- this.$bus.$emit('anchor-seen', anchorComplete)
263
- } else {
264
- if (import.meta.env.DEV)
265
- console.warn(
266
- `%c WARNING!>>> Anchor handeling: 👉${anchorComplete}👈 doesn't exist. Please provide a valid anchor.`,
267
- 'background: orange; color: white; display: block; border-radius:5px; margin:5px;'
268
- )
269
-
270
- return
271
- }
272
-
273
- // if you didn't aldreay seen anchors
274
- if (anchorsComplete != undefined) {
275
- // look if you already saw this anchor
276
- if (anc && !anchorsComplete.includes(anchorComplete)) {
277
- // push it in the array them in the store
278
- anchorsComplete.push(anchorComplete)
279
- this.$set(this.userInteraction, 'anchors', anchorsComplete)
280
- }
281
- } else {
282
- // if you never saw any anchor
283
- // push it in the array them in the store
284
- anchorsComplete = []
285
- if (anc) anchorsComplete.push(anchorComplete)
286
- this.$set(this.userInteraction, 'anchors', anchorsComplete)
287
- }
288
- }
289
- })
290
- }, options)
291
-
292
- // observer call llok for each anchor in page
293
- anchors.forEach((anchor) => {
294
- observer.observe(anchor)
295
- })
296
- },
297
- getAnchorComplete() {
298
- const userInteraction = this.getUserInteraction
299
- let completeAnchor
300
-
301
- // Verify if the element existe
302
- if (
303
- userInteraction[this.activityRef] &&
304
- userInteraction[this.activityRef][this.id] &&
305
- userInteraction[this.activityRef][this.id].userInteraction.anchors
306
- ) {
307
- // if you already saw anchors return them
308
- completeAnchor =
309
- userInteraction[this.activityRef][this.id].userInteraction.anchors
310
- return completeAnchor
311
- }
312
- },
313
- showChoiceBif(data) {
314
- // check if you made a choice
315
- if (
316
- typeof this.getBifChoice === 'undefined' ||
317
- Object.keys(this.getBifChoice).length === 0
318
- ) {
319
- return data['A']
320
- } else {
321
- if (this.getBifChoice.choix) {
322
- // get the choise from store
323
- if (data.hasOwnProperty(this.getBifChoice.choix)) {
324
- let choice = data[this.getBifChoice.choix]
325
- //return choice
326
- return choice
327
- }
328
- }
329
- }
330
- },
331
- openPopup(data) {
332
- this.$bus.$emit('open-popup', data)
333
- },
334
- /**
335
- * @description Send to the bd that the media have been view by the user- Add the id of the media to the
336
- * userInteraction of the page
337
- */
338
- setMediaViewed(mediaID) {
339
- // Should get the userData to check if current mediaElement has entry
340
- const { userInteraction } =
341
- this.getUserInteraction[this.activityRef][this.id]
342
- let { mediasViewed } = userInteraction
343
-
344
- // Should create entry for medias viewed in userInteraction if none
345
- if (!mediasViewed) {
346
- mediasViewed = []
347
-
348
- this.$set(userInteraction, 'mediasViewed', mediasViewed)
349
- }
350
- //Should add ID in media viewed list if viewed for the 1st time
351
- if (mediasViewed.includes(mediaID)) return
352
-
353
- mediasViewed.push(mediaID)
354
- this.$set(userInteraction, 'mediasViewed', mediasViewed) //Update the userInteraction data of the page
355
- }, //
356
-
357
- /**
358
- * @description - Method to manage the playing state of media element in the page.
359
- * Only one media should play at a time. When receives signal of new media playing
360
- * get the reference of the previous media in play from the store and
361
- * put it in stop state.
362
- * @param {HTMLElement} media - the actual media that is playing
363
- */
364
- managePlayingMedia(media) {
365
- if (!media) return
366
- //Should get all the media of the page from store
367
- const { mElements } = this.getCurrentPage
368
- if (!mElements || !mElements.length) return
369
-
370
- // Should stop any media playing
371
- mElements.forEach((m) => {
372
- if (m.id == media.id) return
373
-
374
- const attrKeys = Object.keys(m) //
375
- //Check if the media is playing to stop it. Playing state is given by the instance of the target play-bar
376
- if (m[attrKeys[3]].isPlaying) {
377
- m[attrKeys[1]].pause() // target the HTMLmediaElement to control it state
378
- m[attrKeys[3]].isPlaying = false //change this isPlaying value of the instance
379
- }
380
- })
381
- }
382
- },
383
- computed: {
384
- ...mapGetters([
385
- 'getUserInteraction',
386
- 'getCurrentPage',
387
- 'getModuleInfo',
388
- 'getAllActivities',
389
- 'getAllCompleted',
390
- 'getConnectionInfo',
391
- 'getAnchorsForActivity',
392
- 'getBifChoice',
393
- 'getDataFromServer'
394
- ]),
395
-
396
- pageMedias() {
397
- const { mElements, timeline } = this.$store.getters.getCurrentPage
398
- return { mElements, timeline }
399
- },
400
- console() {
401
- return console
402
- },
403
- window() {
404
- return window
405
- },
406
- alert() {
407
- return alert
408
- },
409
-
410
- isBranchingPage() {
411
- return this.buttonData || this.cardData ? true : false
412
- }
413
- }
414
- }
415
- export default $extendsPage