fcad-core-dragon 2.1.0-beta.2 → 2.1.0-beta.4

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.
@@ -81,7 +81,6 @@
81
81
  </svg>
82
82
  </app-base-button>
83
83
  </div>
84
-
85
84
  <div id="right-sidebar-body">
86
85
  <component
87
86
  :is="dynamicSidebarContent._component"
@@ -111,7 +110,7 @@ export default {
111
110
  BaseModule,
112
111
  AppCompContainer
113
112
  },
114
- inject: ['elapsedIdleTime', 'timerCurrentState', 'lessonDuration'],
113
+ inject: ['elapsedIdleTime', 'lessonDuration', 'appTimer'],
115
114
  props: {
116
115
  moduleConfig: {
117
116
  type: Object,
@@ -156,7 +155,8 @@ export default {
156
155
  text: () => 'this is a test',
157
156
  name: 'sidebarEvent'
158
157
  }
159
- })
158
+ }),
159
+ lessonStarted: false
160
160
  }
161
161
  },
162
162
  computed: {
@@ -190,9 +190,15 @@ export default {
190
190
  },
191
191
  activityHasChanged() {
192
192
  const rd = this.routeData.toReversed()
193
+
194
+ const routeWasMenu =
195
+ this.$router.options.history.state.back &&
196
+ this.$router.options.history.state.back.includes('menu')
197
+
193
198
  if (
194
199
  rd.length <= 1 ||
195
- rd[1].activity_ref !== this.$route.meta.activity_ref
200
+ rd[0].activity_ref !== this.$route.meta.activity_ref ||
201
+ routeWasMenu
196
202
  )
197
203
  return true
198
204
  else return false
@@ -346,7 +352,7 @@ export default {
346
352
  immediate: true
347
353
  },
348
354
  $route: {
349
- handler() {
355
+ handler(newValue) {
350
356
  this.getFocusables().then((r) => {
351
357
  //Pressing Tab or Shit + tab should make it possible to cycle focus through them
352
358
  if (!r) return
@@ -361,16 +367,20 @@ export default {
361
367
  *Start Timer on New activities
362
368
  */
363
369
 
364
- const trackedRouteType = ['introduction', 'conclusion', 'normal']
365
-
370
+ const trackedRouteType = [
371
+ 'introduction',
372
+ 'conclusion',
373
+ 'normal',
374
+ 'branching'
375
+ ]
366
376
  if (trackedRouteType.includes(this.$route.meta.type)) {
367
- if (this.$route.name.includes('.')) return
377
+ //Navigation should only trigger timer and xapi statement when app is ready and activity has changed
378
+ if (!this.activityHasChanged || !this.appReady) return
368
379
 
369
- //Start the timer every time that there is a new activity
380
+ //Start the timer every time route is a new activity
370
381
  this.$bus.$emit('start-timer')
371
382
  //Send statement when activity as changed
372
- if (this.activityHasChanged)
373
- this.sendStartStatement({ id: this.$route.meta.activity_ref })
383
+ this.sendStartStatement({ id: this.$route.meta.activity_ref })
374
384
  }
375
385
  this.transcriptVisible = false
376
386
  },
@@ -378,6 +388,19 @@ export default {
378
388
  immediate: true
379
389
  },
380
390
 
391
+ appReady: {
392
+ async handler(newValue) {
393
+ //Should only start timer when the app has fully loaded
394
+
395
+ if (!this.lessonStarted) this.initLesson()
396
+
397
+ if (this.activityHasChanged && newValue) {
398
+ this.$bus.$emit('start-timer')
399
+ }
400
+ },
401
+ immediate: true
402
+ },
403
+
381
404
  /**
382
405
  * @description Defined in Store Watch all completed activities to send a lesson completion statement
383
406
  */
@@ -403,7 +426,8 @@ export default {
403
426
  */
404
427
  elapsedIdleTime: {
405
428
  handler() {
406
- if (this.timerCurrentState !== 'started') return
429
+ if (this.appTimer.getTimerState() !== 'started') return
430
+
407
431
  //send a statement every x time (second)
408
432
  if (
409
433
  this.elapsedIdleTime % 500 === 0 &&
@@ -451,7 +475,7 @@ export default {
451
475
  : this.$route.name)()
452
476
  }
453
477
  ],
454
- duration: this.lessonDuration
478
+ duration: this.appTimer.ISOTimeParser(this.lessonDuration)
455
479
  }
456
480
 
457
481
  this.$bus.$emit('send-xapi-statement', stmt)
@@ -459,6 +483,7 @@ export default {
459
483
  }
460
484
  }
461
485
  },
486
+ immediate: true,
462
487
  deep: true
463
488
  }
464
489
  },
@@ -541,10 +566,6 @@ export default {
541
566
  this.$bus.$on('send-completion-event', this.sendCompletionStatus)
542
567
  this.$bus.$on('send-starting-event', this.sendStartStatement)
543
568
 
544
- this.initLesson().then(() => {
545
- this.$bus.$emit('start-idle-detector')
546
- })
547
-
548
569
  if (this.navigationHistory.length != 0) {
549
570
  this.routeData = this.navigationHistory
550
571
  }
@@ -605,8 +626,9 @@ export default {
605
626
  async handleKeyboardControls(evt) {
606
627
  let { code } = evt
607
628
 
608
- if (code === 'Escape' && this.rightSidebarVisible)
609
- return (this.rightSidebarVisible = false)
629
+ if (code === 'Escape' && this.rightSidebarVisible){
630
+ this.closeSidebar(this.dynamicSidebarContent._context)
631
+ }
610
632
  },
611
633
 
612
634
  /**
@@ -781,8 +803,10 @@ export default {
781
803
 
782
804
  /**
783
805
  * @description Close the branch page in the right sidebar
784
- * * @summary When call remove listner for scroll event in the sidebar , reset compID and branch visibility
785
- * * @fires 'branching-hidden' to AppCompButtonProgress
806
+ * and update the current page data with the parent of the branch page
807
+ *
808
+ * @summary When call remove listner for scroll event in the sidebar , reset compID and branch visibility
809
+ * @fires 'branching-hidden' to AppCompButtonProgress
786
810
  */
787
811
  closeBranchContent() {
788
812
  const rightSidebar = this.getRightSidebar()
@@ -796,6 +820,7 @@ export default {
796
820
  this.branchingVisible = false
797
821
  }, 300)
798
822
  this.$bus.$emit('branching-hidden')
823
+ this.updateContent(this.$route) // update the content of the current page
799
824
  },
800
825
 
801
826
  displayCustomContent(c, container) {
@@ -817,29 +842,19 @@ export default {
817
842
  * @description reset the values of state (currentTimeline,currentMedialement, currentPage, media duration, appStatus')in the store
818
843
  */
819
844
  async unload() {
845
+ if (!this.getCurrentPage || Object.keys(this.getCurrentPage).length == 0)
846
+ return
847
+
820
848
  return new Promise((res) => {
821
849
  this.$bus.$emit('set-comp-status', 'appBaseModule', 'loading')
822
850
  this.updateCurrentTimeline('')
823
851
  this.updateCurrentMediaElements([])
824
- this.updateCurrentPage({})
852
+ // this.updateCurrentPage({})
825
853
  this.$bus.$emit('set-comp-status', 'appBaseModule', 'ready')
826
854
  res(this.getCompStatusTracker)
827
855
  })
828
856
  },
829
857
 
830
- /**
831
- * @description fetch a page from the store
832
- */
833
- async fetchPage() {
834
- this.$bus.$emit('set-comp-status', 'appBaseModule', 'loading')
835
- const fetched = await new Promise((resolve) => {
836
- setTimeout(() => {
837
- resolve(this.getCurrentPage)
838
- this.$bus.$emit('set-comp-status', 'appBaseModule', 'ready')
839
- }, 200)
840
- })
841
- return fetched
842
- },
843
858
  /**
844
859
  * @description get User data
845
860
  */
@@ -889,43 +904,44 @@ export default {
889
904
  }
890
905
  } else return false
891
906
  },
907
+ /**
908
+ * @description Initialize the lesson
909
+ * - check the package type and launch the lesson accordingly
910
+ * - update the content of the current page in the store with data of the page requested
911
+ */
892
912
  async initLesson() {
893
- await this.unload().then(() => {
894
- const packageType = this.getModuleInfo.packageType
895
- switch (packageType) {
896
- case 'scorm': {
897
- // launching the lesson (if the lesson is not already completed)
898
- const lessonStatus = this.$scorm.GetValue(
899
- 'cmi.core.lesson_status',
900
- true
901
- )
902
- if (lessonStatus === 'unknown') {
903
- this.$scorm.setValue('cmi.core.lesson_status', 'incomplete') // set the lesson status to in complete
904
- this.$scorm.Commit() // persist data
905
- }
906
- //Redirect to current page or to menu if route is module
913
+ if (this.lessonStarted) return
914
+
915
+ const packageType = this.getModuleInfo.packageType
916
+ switch (packageType) {
917
+ case 'scorm': {
918
+ // launching the lesson (if the lesson is not already completed)
919
+ const lessonStatus = this.$scorm.GetValue(
920
+ 'cmi.core.lesson_status',
921
+ true
922
+ )
923
+ if (lessonStatus === 'unknown') {
924
+ this.$scorm.setValue('cmi.core.lesson_status', 'incomplete') // set the lesson status to in complete
925
+ this.$scorm.Commit() // persist data
926
+ }
927
+ //Redirect to current page or to menu if route is module
928
+ this.$route.name && this.$route.name !== 'module'
929
+ ? this.$router.push({ name: this.$route.name })
930
+ : this.$router.push({ name: 'menu' })
931
+ break
932
+ }
933
+ case 'xapi':
934
+ {
907
935
  this.$route.name && this.$route.name !== 'module'
908
936
  ? this.$router.push({ name: this.$route.name })
909
937
  : this.$router.push({ name: 'menu' })
910
-
911
- // set the current page
912
- this.fetchPage()
913
-
914
- break
915
938
  }
916
- case 'xapi':
917
- {
918
- this.$route.name && this.$route.name !== 'module'
919
- ? this.$router.push({ name: this.$route.name })
920
- : this.$router.push({ name: 'menu' })
921
-
922
- this.fetchPage()
923
- // }
924
- }
925
- break
926
- }
927
- })
939
+ break
940
+ }
941
+ this.lessonStarted = true
942
+ await this.updateContent(this.$route)
928
943
  },
944
+ //=============================================================================
929
945
 
930
946
  /**
931
947
  * @description save interaction or Module state to scrom suspend_data
@@ -945,16 +961,12 @@ export default {
945
961
  // create new entry for user data if does not existe
946
962
  existingRecord.userData = this.getUserInteraction || {}
947
963
  existingRecord.userSettings = this.getApplicationSettings || {}
948
- // existingRecord.routeHistory = this.getRouteHistory || []
949
964
  existingRecord.routeHistory = (() => {
950
965
  const history = this.getRouteHistory.toReversed() //get the route history from the last
951
-
952
966
  history[0] = this.$route.meta // change the last recored route to the current route
953
-
954
967
  return history.toReversed()
955
968
  })()
956
969
  // update value of user data
957
-
958
970
  toBeSaved = JSON.stringify(existingRecord) // convert to JSON string format
959
971
 
960
972
  this.$scorm.SetValue('cmi.suspend_data', toBeSaved) // converte to serialized string and save to scorm
@@ -963,55 +975,28 @@ export default {
963
975
  }
964
976
  },
965
977
  /**
966
- * @param {Object} to
967
- * @param {Object} from unused
968
- * @param {Function} next
978
+ * @description update content when route change or a page change is requested
979
+ * - update the information of the current page in the store with data of the page requested
980
+ *
981
+ * @param {Object} to destination route
969
982
  */
970
- updateContent(to, from, next) {
983
+ async updateContent(to, caller = null) {
984
+ this.$bus.$emit('set-comp-status', 'appBaseModule', 'loading')
971
985
  if (this.getModuleInfo.packageType === 'scorm')
972
986
  this.saveToScorm('userInteraction') //save to scorm
973
987
 
974
- this.unload().then((res) => {
975
- if (res.length) {
976
- //======== Handle redirect to correct path when user enter incorrect path for existing route ====//
977
- let toName = null
978
- if (!to.name) {
979
- toName = to.fullPath.replace(/\//g, ' ').trim() //clean route name
988
+ await this.unload()
989
+ const { activity_ref: activity_Id, id: page_Id } = to.meta ? to.meta : to
980
990
 
981
- //apply apply correct format for routes that concerne an activity
982
- if (toName.includes('activite-')) {
983
- toName = toName.split(' ')[0].replace('-', '_')
984
- }
985
- //Go to menu when introactive is false other wise will navigate to introduction
986
- else if (
987
- toName.includes('introduction') &&
988
- !this.theIntroIsActivated
989
- )
990
- toName = 'menu'
991
- }
992
- //When User inter path to module
993
- else if (to.name === 'module') {
994
- toName = 'menu'
995
- }
996
- //Default redirection
997
- else {
998
- false
999
- // next()
1000
- }
1001
- //===================== Handeling a page request from Store=========================== ====//
1002
- //get the page from store
1003
- this.fetchPage().then((res) => {
1004
- //Save current page has bookmark in scorm
1005
- if (
1006
- this.getModuleInfo.packageType === 'scorm' &&
1007
- this.$scorm.initialized
1008
- )
1009
- this.$scorm.setBookMark(this.$route.name)
1010
- })
1011
- }
1012
- })
991
+ await this.updateCurrentPage({ activity_Id, page_Id }, caller)
992
+ this.$bus.$emit('set-comp-status', 'appBaseModule', 'ready')
1013
993
  },
1014
994
 
995
+ /**
996
+ * @description update the route history when navigation happen
997
+ * @param {Object} from - origin route
998
+ *
999
+ */
1015
1000
  updateRouteHistory(from) {
1016
1001
  //The route is not in the history: should be push at the end of the history
1017
1002
  const targetIndex = this.routeData.findIndex((r) => {
@@ -1139,6 +1124,8 @@ export default {
1139
1124
  left: 0,
1140
1125
  behavior: 'auto'
1141
1126
  })
1127
+
1128
+ this.$analytics.sendEvent('skip_to_main_content')
1142
1129
  },
1143
1130
 
1144
1131
  /**
@@ -1421,7 +1408,7 @@ export default {
1421
1408
  // Note: User Settings are sent on a different URI and statement
1422
1409
  const { isFistTime, userSettings, ...lessonsData } =
1423
1410
  this.getUserInteraction
1424
-
1411
+ const activityDuration = this.appTimer.getTime()
1425
1412
  stmt = {
1426
1413
  id: this.getCurrentPage.activityRef,
1427
1414
  verb: 'completed',
@@ -1436,7 +1423,7 @@ export default {
1436
1423
  }
1437
1424
  }
1438
1425
  ],
1439
- duration: this.activityDuration,
1426
+ duration: this.appTimer.ISOTimeParser(activityDuration),
1440
1427
  completion: true
1441
1428
  }
1442
1429
 
@@ -1484,12 +1471,12 @@ export default {
1484
1471
  }
1485
1472
  }
1486
1473
  ],
1487
- duration: this.lessonDuration,
1474
+ duration: this.appTimer.ISOTimeParser(this.lessonDuration),
1488
1475
  completion: true
1489
1476
  }
1490
1477
  this.lessonCompletionStatus = true // set the status of this lesson as completed
1491
1478
  let completedState = {
1492
- duration: this.lessonDuration,
1479
+ duration: this.appTimer.ISOTimeParser(this.lessonDuration),
1493
1480
  completion: this.lessonCompletionStatus
1494
1481
  }
1495
1482
  this.setCompletionState(completedState)
@@ -130,6 +130,7 @@ export default {
130
130
  },
131
131
 
132
132
  getCurrentPage() {
133
+ console.log('📘 ', this.store.getCurrentPage)
133
134
  return this.store.getCurrentPage
134
135
  },
135
136
 
@@ -367,18 +368,20 @@ export default {
367
368
  */
368
369
 
369
370
  if (this.pageData && this.errorPage === false) {
370
- // Update the store with the current page information
371
- this.store.updateCurrentPage({
372
- activity_Id: this.pageData.activityRef,
373
- page_Id: this.pageData.id
374
- })
375
371
  // Handeling presence of animation in the page
376
372
  if (this.pageData.animation) {
377
373
  // update the store with the information of currentTimeline
378
374
  }
379
375
 
380
- if (this.type == 'pg_branch')
376
+ if (this.type == 'pg_branch') {
377
+ // Update the store with the current page information when branching page is created
378
+ // Note: Branching doesn't trigger router navigation so is done directly here
379
+ this.store.updateCurrentPage({
380
+ activity_Id: this.pageData.activityRef,
381
+ page_Id: this.pageData.id
382
+ })
381
383
  this.$bus.$on('branch-page-viewed', this.completePageBranching)
384
+ }
382
385
  }
383
386
 
384
387
  if (this.isBranchingPage) this.updateCurrentBranching(this.$data)
@@ -391,12 +394,8 @@ export default {
391
394
  //Fix for firefox not updating aria-labelledby (was stuck saying Activite 1, page 1 on every pages)
392
395
  this.$refs['page_info'].innerHTML = this.A11yPageInfo
393
396
 
394
- setTimeout(() => {
395
- if (this.pageData && this.type === 'pg_branch') return //Prevent scrolling to top of Parent when branching page are being viewed
396
- this.$bus.$emit('move-to-target', 'page_info_section')
397
- }, 100)
398
-
399
- //==============================================================
397
+ if (this.pageData && this.type === 'pg_branch') return //Prevent scrolling to top of Parent when branching page are being viewed
398
+ this.$bus.$emit('move-to-target', 'page_info_section')
400
399
 
401
400
  if (this.userInteraction && this.userInteraction.state)
402
401
  // set the state of the page to existing record if any
@@ -427,7 +426,6 @@ export default {
427
426
  window.addEventListener('scroll', this.onFirstScroll, { once: true }) //listener is removed when event fired
428
427
  },
429
428
  unmounted() {
430
- //this.pageData = null
431
429
  this.$bus.$off('branch-page-viewed', this.completePageBranching)
432
430
  this.$bus.$off('media-viewed', this.setMediaViewed)
433
431
  this.$bus.$off('manage-media-players', this.managePlayingMedia)
@@ -718,6 +716,8 @@ export default {
718
716
  if (playbarInstance.isPlaying) {
719
717
  HTMLmediaElement.pause() // target the HTMLmediaElement to control it state
720
718
  playbarInstance.isPlaying = false //change this isPlaying value of the instance
719
+
720
+ playbarInstance.timer.pause() // pause the timer of the instance
721
721
  }
722
722
  })
723
723
  },
@@ -333,7 +333,7 @@ export default {
333
333
  justify-content: center;
334
334
  margin: 25px;
335
335
  padding: 20px;
336
- background-color: #eaabb685;
336
+ background-color: #eaabb6b3;
337
337
  border-block: dotted yellow 5px;
338
338
  p {
339
339
  padding: 15px;
@@ -343,6 +343,7 @@ export default {
343
343
  button {
344
344
  background-color: #8dff95;
345
345
  font-size: 1.3em;
346
+ padding: 5px 12px;
346
347
  }
347
348
  #resetOverlay {
348
349
  position: absolute;