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
@@ -1,84 +1,84 @@
1
- <template>
2
- <!--
3
- inspire by : https://vuejsexamples.com/generic-flip-card-in-vue-that-allows-completely-arbitrary-content-on-each-side/
4
- -->
5
- <div class="flip-card" role="button" aria-pressed="false" @click="fnClick">
6
- <div class="inside-card" :class="{ flip: isFlipped }">
7
- <div class="front-card" name="front-card">
8
- <slot name="front-card" />
9
- </div>
10
- <div class="back-card">
11
- <slot name="back-card" />
12
- </div>
13
- </div>
14
- </div>
15
- </template>
16
- <script>
17
- export default {
18
- props: {
19
- isActive: {
20
- type: Boolean,
21
- default: false
22
- }
23
- },
24
- emits: ['click'],
25
- data() {
26
- return {
27
- isFlipped: false
28
- }
29
- },
30
- methods: {
31
- /**
32
- * @fires click to parent componant or page
33
- */
34
- fnClick() {
35
- this.$emit('click', this.$el)
36
- this.isFlipped = !this.isFlipped
37
- }
38
- }
39
- }
40
- </script>
41
- <style lang="scss">
42
- .flip-card {
43
- height: auto;
44
- cursor: pointer;
45
-
46
- /***** Parameretre modifiable *****/
47
- perspective: 100%;
48
- width: 90%;
49
-
50
- .inside-card {
51
- position: relative;
52
- width: 100%;
53
- height: 100%;
54
-
55
- /***** Parameretre modifiable *****/
56
- transform-style: preserve-3d;
57
- transition: transform 0.5s;
58
-
59
- &.flip {
60
- /***** Parameretre modifiable *****/
61
- transform: rotateY(180deg);
62
- }
63
-
64
- .front-card,
65
- .back-card {
66
- position: absolute;
67
- width: 100%;
68
- height: 100%;
69
- -webkit-backface-visibility: hidden;
70
- backface-visibility: hidden;
71
-
72
- .img-flip-card {
73
- width: 90%;
74
- height: auto;
75
- }
76
- }
77
-
78
- .back-card {
79
- /***** Parameretre modifiable *****/
80
- transform: rotateY(180deg);
81
- }
82
- }
83
- }
84
- </style>
1
+ <template>
2
+ <!--
3
+ inspire by : https://vuejsexamples.com/generic-flip-card-in-vue-that-allows-completely-arbitrary-content-on-each-side/
4
+ -->
5
+ <div class="flip-card" role="button" aria-pressed="false" @click="fnClick">
6
+ <div class="inside-card" :class="{ flip: isFlipped }">
7
+ <div class="front-card" name="front-card">
8
+ <slot name="front-card" />
9
+ </div>
10
+ <div class="back-card">
11
+ <slot name="back-card" />
12
+ </div>
13
+ </div>
14
+ </div>
15
+ </template>
16
+ <script>
17
+ export default {
18
+ props: {
19
+ isActive: {
20
+ type: Boolean,
21
+ default: false
22
+ }
23
+ },
24
+ emits: ['click'],
25
+ data() {
26
+ return {
27
+ isFlipped: false
28
+ }
29
+ },
30
+ methods: {
31
+ /**
32
+ * @fires click to parent componant or page
33
+ */
34
+ fnClick() {
35
+ this.$emit('click', this.$el)
36
+ this.isFlipped = !this.isFlipped
37
+ }
38
+ }
39
+ }
40
+ </script>
41
+ <style lang="scss">
42
+ .flip-card {
43
+ height: auto;
44
+ cursor: pointer;
45
+
46
+ /***** Parameretre modifiable *****/
47
+ perspective: 100%;
48
+ width: 90%;
49
+
50
+ .inside-card {
51
+ position: relative;
52
+ width: 100%;
53
+ height: 100%;
54
+
55
+ /***** Parameretre modifiable *****/
56
+ transform-style: preserve-3d;
57
+ transition: transform 0.5s;
58
+
59
+ &.flip {
60
+ /***** Parameretre modifiable *****/
61
+ transform: rotateY(180deg);
62
+ }
63
+
64
+ .front-card,
65
+ .back-card {
66
+ position: absolute;
67
+ width: 100%;
68
+ height: 100%;
69
+ -webkit-backface-visibility: hidden;
70
+ backface-visibility: hidden;
71
+
72
+ .img-flip-card {
73
+ width: 90%;
74
+ height: auto;
75
+ }
76
+ }
77
+
78
+ .back-card {
79
+ /***** Parameretre modifiable *****/
80
+ transform: rotateY(180deg);
81
+ }
82
+ }
83
+ }
84
+ </style>
@@ -7,11 +7,11 @@
7
7
 
8
8
  <template>
9
9
  <div fluid class="module">
10
- <div
10
+ <span
11
11
  id="page_info_section"
12
12
  class="sr-only"
13
13
  aria-labelledby="page_info"
14
- ></div>
14
+ ></span>
15
15
  <a class="skip-link" href="" @click.prevent="skipToMain">
16
16
  {{ $t('message.skip_content') }}
17
17
  </a>
@@ -108,13 +108,13 @@ import { mapState, mapActions } from 'pinia'
108
108
  import { useAppStore } from '../module/stores/appStore'
109
109
  import BaseModule from './BaseModule.vue'
110
110
  import { timerMixin } from '../mixins/timerMixin'
111
- import AppCompTranscript from './AppCompTranscript.vue'
111
+ import AppCompContainer from './AppCompContainer.vue'
112
112
  import { defineAsyncComponent } from 'vue'
113
113
  //import
114
114
  export default {
115
115
  components: {
116
116
  BaseModule,
117
- AppCompTranscript
117
+ AppCompContainer
118
118
  },
119
119
  mixins: [timerMixin],
120
120
  props: {
@@ -154,6 +154,8 @@ export default {
154
154
  transcriptContent: null,
155
155
  transcriptContainer: null,
156
156
  branchingVisible: false,
157
+ customContentVisible: false,
158
+ customContent: null,
157
159
  lessonCompletionStatus: false,
158
160
  checkedDataFromServer: 0,
159
161
  rightSidebarEvent: new CustomEvent('sidebarEvent', {
@@ -179,8 +181,8 @@ export default {
179
181
  'getMenuSettings',
180
182
  'getRouteHistory',
181
183
  'getOnboardingEnabled',
182
- 'getApplicationSettings',
183
184
  'getDataFromServer',
185
+ 'getApplicationSettings',
184
186
  'getCompStatusTracker'
185
187
  ]),
186
188
  isMenu() {
@@ -264,50 +266,120 @@ export default {
264
266
  return mainEl
265
267
  },
266
268
 
269
+ // dynamicSidebarContent() {
270
+ // if (!this.transcriptVisible && !this.branchingVisible) return null
271
+ // let sidebarSettings = {}
272
+ // let _label = null
273
+
274
+ // if (this.transcriptVisible) {
275
+ // _label =
276
+ // this.$i18n.locale === 'fr'
277
+ // ? 'Contenu de la transcription'
278
+ // : 'Content of the transcript'
279
+
280
+ // sidebarSettings = {
281
+ // _component: AppCompContainer,
282
+ // _comProps: {
283
+ // content: this.transcriptContent
284
+ // },
285
+ // _context: 'ctxTranscript',
286
+ // _container: this.transcriptContainer,
287
+ // _label,
288
+ // _id: 'transcript'
289
+ // }
290
+ // } else if (this.branchingVisible) {
291
+ // if (this.$route.meta.type !== 'branching' || !this.compID) return null
292
+
293
+ // const componentName = this.compID
294
+ // const { activityRef } = this.getCurrentPage //get activity id from current page
295
+
296
+ // _label =
297
+ // this.$i18n.locale === 'fr'
298
+ // ? "contenu de l'embranchement"
299
+ // : 'content of the branching'
300
+
301
+ // sidebarSettings = {
302
+ // _component: defineAsyncComponent(
303
+ // async () =>
304
+ // await import(`@/module/${activityRef}/${componentName}.vue`)
305
+ // ),
306
+
307
+ // _comProps: false,
308
+ // _context: 'ctxBranching',
309
+ // _label,
310
+ // _id: componentName
311
+ // }
312
+ // }
313
+ // return sidebarSettings
314
+ // },
267
315
  dynamicSidebarContent() {
268
- if (!this.transcriptVisible && !this.branchingVisible) return null
316
+ if (
317
+ !this.transcriptVisible &&
318
+ !this.branchingVisible &&
319
+ !this.customContentVisible
320
+ )
321
+ return null
269
322
  let sidebarSettings = {}
270
323
  let _label = null
324
+ //=========================================
325
+ switch (true) {
326
+ case this.transcriptVisible:
327
+ _label =
328
+ this.$i18n.locale === 'fr'
329
+ ? 'Contenu de la transcription'
330
+ : 'Content of the transcript'
331
+
332
+ sidebarSettings = {
333
+ _component: AppCompContainer,
334
+ _comProps: {
335
+ content: this.transcriptContent,
336
+ id: 'transcript-content'
337
+ },
338
+ _context: 'ctxTranscript',
339
+ _container: this.transcriptContainer,
340
+ _label,
341
+ _id: 'transcript'
342
+ }
343
+ break
271
344
 
272
- if (this.transcriptVisible) {
273
- _label =
274
- this.$i18n.locale === 'fr'
275
- ? 'Contenu de la transcription'
276
- : 'Content of the transcript'
277
-
278
- sidebarSettings = {
279
- _component: AppCompTranscript,
280
- _comProps: {
281
- content: this.transcriptContent
282
- },
283
- _context: 'ctxTranscript',
284
- _container: this.transcriptContainer,
285
- _label,
286
- _id: 'transcript'
287
- }
288
- } else if (this.branchingVisible) {
289
- if (this.$route.meta.type !== 'branching' || !this.compID) return null
290
-
291
- const componentName = this.compID
292
- const { activityRef } = this.getCurrentPage //get activity id from current page
293
-
294
- _label =
295
- this.$i18n.locale === 'fr'
296
- ? "contenu de l'embranchement"
297
- : 'content of the branching'
298
-
299
- sidebarSettings = {
300
- _component: defineAsyncComponent(
301
- async () =>
302
- await import(`@/module/${activityRef}/${componentName}.vue`)
303
- ),
304
-
305
- _comProps: false,
306
- _context: 'ctxBranching',
307
- _label,
308
- _id: componentName
345
+ case this.branchingVisible: {
346
+ if (this.$route.meta.type !== 'branching' || !this.compID) return null
347
+
348
+ const componentName = this.compID
349
+ const { activityRef } = this.getCurrentPage //get activity id from current page
350
+
351
+ _label =
352
+ this.$i18n.locale === 'fr'
353
+ ? "contenu de l'embranchement"
354
+ : 'content of the branching'
355
+
356
+ sidebarSettings = {
357
+ _component: defineAsyncComponent(
358
+ async () =>
359
+ await import(`@/module/${activityRef}/${componentName}.vue`)
360
+ ),
361
+
362
+ _comProps: false,
363
+ _context: 'ctxBranching',
364
+ _label,
365
+ _id: componentName
366
+ }
367
+ break
309
368
  }
369
+
370
+ case this.customContentVisible:
371
+ sidebarSettings = {
372
+ _component: AppCompContainer,
373
+ _comProps: {
374
+ content: this.customContent
375
+ },
376
+ _context: 'ctxCustomContent',
377
+ _label,
378
+ _id: 'custom-content'
379
+ }
380
+ break
310
381
  }
382
+
311
383
  return sidebarSettings
312
384
  },
313
385
 
@@ -532,12 +604,6 @@ export default {
532
604
  }, 800)
533
605
  },
534
606
  mounted() {
535
- //A11Y: Bring back the focus on the body element after each navigation
536
- document.body.setAttribute('tabindex', -1) //needed to use .focus()
537
- this.$router.afterEach(() => {
538
- document.body.focus()
539
- })
540
-
541
607
  let nav = document.getElementById('navTool')
542
608
 
543
609
  if (nav) nav.addEventListener('mouseleave', this.onNavMouseleave)
@@ -623,6 +689,9 @@ export default {
623
689
 
624
690
  this.openBranchContent(content)
625
691
  break
692
+ case 'ctxCustomContent':
693
+ this.displayCustomContent(content, wrapper)
694
+ break
626
695
  }
627
696
  //delay animation
628
697
  this.rightSidebarVisible = true
@@ -661,10 +730,16 @@ export default {
661
730
  this.closeBranchContent()
662
731
  break
663
732
 
733
+ case 'ctxCustomContent':
734
+ this.closeCostumContent()
735
+ break
736
+
664
737
  default:
665
738
  this.branchingVisible = false
666
739
  this.transcriptVisible = false
740
+ this.customContentVisible = false
667
741
  this.transcriptContent = null
742
+ this.customContent = null
668
743
  this.compID = null
669
744
  }
670
745
  this.updatesideBIsOpen(this.rightSidebarVisible)
@@ -732,10 +807,11 @@ export default {
732
807
  * @fires 'transcript-hidden' to AppCompPlaybar
733
808
  */
734
809
  closeTranscript(container = this.transcriptContainer) {
810
+ let t = this.customContentVisible ? 10 : 200
735
811
  setTimeout(() => {
736
812
  this.transcriptContent = null
737
813
  this.transcriptVisible = false
738
- }, 300)
814
+ }, t)
739
815
  this.$bus.$emit('transcript-hidden')
740
816
  this.$bus.$emit('resize-media', 'lg', container)
741
817
  },
@@ -784,6 +860,21 @@ export default {
784
860
  this.$bus.$emit('branching-hidden')
785
861
  },
786
862
 
863
+ displayCustomContent(c, container) {
864
+ if (!c) return (this.customContentVisible = false)
865
+ //Change transcript content
866
+ if (this.transcriptVisible) this.closeTranscript()
867
+ //Change transcript content
868
+ this.customContent = c
869
+ this.customContentContainer = container
870
+ this.customContentVisible = true
871
+ },
872
+
873
+ closeCostumContent() {
874
+ this.customContentContainer = null
875
+ this.customContentVisible = false
876
+ },
877
+
787
878
  /**
788
879
  * @description reset the values of state (currentTimeline,currentMedialement, currentPage, media duration, appStatus')in the store
789
880
  */
@@ -874,25 +965,14 @@ export default {
874
965
  this.$scorm.setValue('cmi.core.lesson_status', 'incomplete') // set the lesson status to in complete
875
966
  this.$scorm.Commit() // persist data
876
967
  }
968
+ //Redirect to current page or to menu if route is module
969
+ this.$route.name && this.$route.name !== 'module'
970
+ ? this.$router.push({ name: this.$route.name })
971
+ : this.$router.push({ name: 'menu' })
877
972
 
878
- // check for the bookmark existance in LMS
879
- const bookmark = this.$scorm.GetValue(
880
- 'cmi.core.lesson_location',
881
- false
882
- )
883
-
884
- // if none stored in the LMS redirect to the 1st page
885
- if (bookmark === '' || bookmark === undefined) {
886
- //Redirect to current page or to menu if route is module
887
- this.$route.name && this.$route.name !== 'module'
888
- ? this.$router.push({ name: this.$route.name })
889
- : this.$router.push({ name: 'menu' })
890
- } else if (bookmark) {
891
- this.$router.push({ name: bookmark })
892
- }
893
973
  // set the current page
894
974
  this.fetchPage()
895
- this.$scorm.getScormAPI()
975
+
896
976
  break
897
977
  }
898
978
  case 'xapi':
@@ -917,53 +997,31 @@ export default {
917
997
  arg = arg || null
918
998
  let existingRecord // hold record record
919
999
  let toBeSaved // hold data to send to scorm
1000
+
920
1001
  if (this.$scorm.initialized) {
921
1002
  if (this.$scorm.GetValue('cmi.suspend_data') !== '')
922
1003
  existingRecord = JSON.parse(this.$scorm.GetValue('cmi.suspend_data')) // try convert the scorm record to JSON Obiect
923
1004
  // create entry for user data if there is no record in Scorm
924
1005
  if (!existingRecord) existingRecord = {}
925
- // There is a passed arg
926
- if (arg !== null) {
927
- // update only the user record
928
- if (arg === 'userInteraction') {
929
- // create new entry for user data if does not existe
930
- if (!existingRecord['userData']) existingRecord['userData'] = {}
931
- // update value of user data
932
- if (this.getUserInteraction)
933
- existingRecord.userData = this.getUserInteraction
934
- toBeSaved = JSON.stringify(existingRecord) // convert to JSON string format
935
- }
936
- // update only the module record
937
- else if (arg === 'module') {
938
- // create new entry for module data if does not existe
939
- if (!existingRecord['moduleData']) existingRecord['moduleData'] = {}
940
- // update value for module data
941
- toBeSaved = JSON.stringify(existingRecord) // convert to JSON string format
942
- }
943
- // no valid arg
944
- else return
945
- }
946
- // Update module & user record
947
- else {
948
- // create entry for module and user data if does not existe
949
- if (
950
- !existingRecord['userData'] &&
951
- !existingRecord['moduleData'] &&
952
- !existingRecord['routeHistory']
953
- ) {
954
- existingRecord['moduleData'] = {}
955
- existingRecord['userData'] = {}
956
- existingRecord['routeHistory'] = []
957
- }
958
- // update values for module and user data
959
- existingRecord.userData = this.getUserInteraction
960
- existingRecord.routeHistory = this.routeData
961
- // update value of user data
962
- existingRecord.moduleConfig = JSON.stringify({}) // update value of module data
963
- toBeSaved = JSON.stringify(existingRecord)
964
- }
1006
+
1007
+ // create new entry for user data if does not existe
1008
+ existingRecord.userData = this.getUserInteraction || {}
1009
+ existingRecord.userSettings = this.getApplicationSettings || {}
1010
+ // existingRecord.routeHistory = this.getRouteHistory || []
1011
+ existingRecord.routeHistory = (() => {
1012
+ const history = this.getRouteHistory.toReversed() //get the route history from the last
1013
+
1014
+ history[0] = this.$route.meta // change the last recored route to the current route
1015
+
1016
+ return history.toReversed()
1017
+ })()
1018
+ // update value of user data
1019
+
1020
+ toBeSaved = JSON.stringify(existingRecord) // convert to JSON string format
1021
+
965
1022
  this.$scorm.SetValue('cmi.suspend_data', toBeSaved) // converte to serialized string and save to scorm
966
1023
  this.$scorm.Commit() // persist data in LMS
1024
+ if (arg === 'disconnect') this.$scorm.Finish()
967
1025
  }
968
1026
  },
969
1027
  /**
@@ -15,9 +15,12 @@
15
15
  :error-text="`Vous avez une/des erreur(s) dans la création de votre PAGE. Veuillez
16
16
  corriger les erreurs ci-dessous:`"
17
17
  />
18
- <span id="page_info" class="sr-only" aria-hidden="true">
19
- {{ A11yPageInfo }}
20
- </span>
18
+ <span
19
+ id="page_info"
20
+ ref="page_info"
21
+ class="sr-only"
22
+ aria-hidden="true"
23
+ ></span>
21
24
  <div id="hiddenAlertContainer" role="alert" class="sr-only"></div>
22
25
  </div>
23
26
  </template>
@@ -100,7 +103,11 @@ export default {
100
103
  }
101
104
  },
102
105
  computed: {
103
- ...mapState(useAppStore, ['getDataNoteCredit', 'getAllActivities']),
106
+ ...mapState(useAppStore, [
107
+ 'getDataNoteCredit',
108
+ 'getAllActivities',
109
+ 'getApplicationSettings'
110
+ ]),
104
111
  getRouteHistory() {
105
112
  return this.store.getRouteHistory
106
113
  },
@@ -373,6 +380,9 @@ export default {
373
380
  this.$bus.$on('video-transcript-toggle', this.onVideoTranscriptToggle)
374
381
  },
375
382
  mounted() {
383
+ //Fix for firefox not updating aria-labelledby (was stuck saying Activite 1, page 1 on every pages)
384
+ this.$refs['page_info'].innerHTML = this.A11yPageInfo
385
+
376
386
  setTimeout(() => {
377
387
  if (this.pageData && this.type === 'pg_branch') return //Prevent scrolling to top of Parent when branching page are being viewed
378
388
  this.$bus.$emit('move-to-target', 'page_info_section')
@@ -1,41 +1,41 @@
1
- <!--
2
- @ Description: This component is used to create a popover that is accessible via keyboard navigation (tab + space/enter)
3
- -->
4
- <template>
5
- <v-tooltip
6
- ref="tooltip"
7
- v-bind="$attrs"
8
- v-model="show"
9
- transition="false"
10
- :open-on-click="true"
11
- :persistent="false"
12
- >
13
- <slot></slot>
14
- </v-tooltip>
15
- </template>
16
-
17
- <script>
18
- export default {
19
- name: 'AppBasePopover',
20
- data() {
21
- return {
22
- show: false,
23
- alertContainer: null
24
- }
25
- },
26
- watch: {
27
- show: {
28
- handler(newValue) {
29
- if (newValue) {
30
- const content = this.$refs.tooltip.contentEl.textContent
31
- this.alertContainer.textContent = ''
32
- this.alertContainer.textContent = content
33
- }
34
- }
35
- }
36
- },
37
- mounted() {
38
- this.alertContainer = document.getElementById('hiddenAlertContainer')
39
- }
40
- }
41
- </script>
1
+ <!--
2
+ @ Description: This component is used to create a popover that is accessible via keyboard navigation (tab + space/enter)
3
+ -->
4
+ <template>
5
+ <v-tooltip
6
+ ref="tooltip"
7
+ v-bind="$attrs"
8
+ v-model="show"
9
+ transition="false"
10
+ :open-on-click="true"
11
+ :persistent="false"
12
+ >
13
+ <slot></slot>
14
+ </v-tooltip>
15
+ </template>
16
+
17
+ <script>
18
+ export default {
19
+ name: 'AppBasePopover',
20
+ data() {
21
+ return {
22
+ show: false,
23
+ alertContainer: null
24
+ }
25
+ },
26
+ watch: {
27
+ show: {
28
+ handler(newValue) {
29
+ if (newValue) {
30
+ const content = this.$refs.tooltip.contentEl.textContent
31
+ this.alertContainer.textContent = ''
32
+ this.alertContainer.textContent = content
33
+ }
34
+ }
35
+ }
36
+ },
37
+ mounted() {
38
+ this.alertContainer = document.getElementById('hiddenAlertContainer')
39
+ }
40
+ }
41
+ </script>