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

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 (70) hide show
  1. package/.editorconfig +33 -33
  2. package/.eslintignore +29 -29
  3. package/.eslintrc.cjs +81 -81
  4. package/CHANGELOG +395 -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 +124 -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/shared/generalfuncs.js +210 -210
  69. package/src/shared/validators.js +2 -0
  70. 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>
@@ -104,17 +104,19 @@
104
104
  </div>
105
105
  </template>
106
106
  <script>
107
+ // const modules = import.meta.glob('@/module/**/*.vue')
108
+ import { fileAssets } from '../shared/generalfuncs.js'
107
109
  import { mapState, mapActions } from 'pinia'
108
110
  import { useAppStore } from '../module/stores/appStore'
109
111
  import BaseModule from './BaseModule.vue'
110
112
  import { timerMixin } from '../mixins/timerMixin'
111
- import AppCompTranscript from './AppCompTranscript.vue'
113
+ import AppCompContainer from './AppCompContainer.vue'
112
114
  import { defineAsyncComponent } from 'vue'
113
115
  //import
114
116
  export default {
115
117
  components: {
116
118
  BaseModule,
117
- AppCompTranscript
119
+ AppCompContainer
118
120
  },
119
121
  mixins: [timerMixin],
120
122
  props: {
@@ -154,6 +156,8 @@ export default {
154
156
  transcriptContent: null,
155
157
  transcriptContainer: null,
156
158
  branchingVisible: false,
159
+ customContentVisible: false,
160
+ customContent: null,
157
161
  lessonCompletionStatus: false,
158
162
  checkedDataFromServer: 0,
159
163
  rightSidebarEvent: new CustomEvent('sidebarEvent', {
@@ -179,8 +183,8 @@ export default {
179
183
  'getMenuSettings',
180
184
  'getRouteHistory',
181
185
  'getOnboardingEnabled',
182
- 'getApplicationSettings',
183
186
  'getDataFromServer',
187
+ 'getApplicationSettings',
184
188
  'getCompStatusTracker'
185
189
  ]),
186
190
  isMenu() {
@@ -265,49 +269,77 @@ export default {
265
269
  },
266
270
 
267
271
  dynamicSidebarContent() {
268
- if (!this.transcriptVisible && !this.branchingVisible) return null
272
+ if (
273
+ !this.transcriptVisible &&
274
+ !this.branchingVisible &&
275
+ !this.customContentVisible
276
+ )
277
+ return null
269
278
  let sidebarSettings = {}
270
279
  let _label = null
280
+ //=========================================
281
+ switch (true) {
282
+ case this.transcriptVisible:
283
+ _label =
284
+ this.$i18n.locale === 'fr'
285
+ ? 'Contenu de la transcription'
286
+ : 'Content of the transcript'
287
+
288
+ sidebarSettings = {
289
+ _component: AppCompContainer,
290
+ _comProps: {
291
+ content: this.transcriptContent,
292
+ id: 'transcript-content'
293
+ },
294
+ _context: 'ctxTranscript',
295
+ _container: this.transcriptContainer,
296
+ _label,
297
+ _id: 'transcript'
298
+ }
299
+ break
271
300
 
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
301
+ case this.branchingVisible: {
302
+ const allActivities = fileAssets.getActivities()
303
+ if (this.$route.meta.type !== 'branching' || !this.compID) return null
304
+
305
+ const componentName = this.compID
306
+ const { activityRef } = this.getCurrentPage //get activity id from current page
307
+
308
+ _label =
309
+ this.$i18n.locale === 'fr'
310
+ ? "contenu de l'embranchement"
311
+ : 'content of the branching'
312
+
313
+ sidebarSettings = {
314
+ _component: defineAsyncComponent(async () => {
315
+ const compFile = allActivities.filter((f) => {
316
+ return f.name.includes(`/${activityRef}/${componentName}`)
317
+ })[0]
318
+
319
+ return compFile.content
320
+ }),
321
+
322
+ _comProps: false,
323
+ _context: 'ctxBranching',
324
+ _label,
325
+ _id: componentName
326
+ }
327
+ break
309
328
  }
329
+
330
+ case this.customContentVisible:
331
+ sidebarSettings = {
332
+ _component: AppCompContainer,
333
+ _comProps: {
334
+ content: this.customContent
335
+ },
336
+ _context: 'ctxCustomContent',
337
+ _label,
338
+ _id: 'custom-content'
339
+ }
340
+ break
310
341
  }
342
+
311
343
  return sidebarSettings
312
344
  },
313
345
 
@@ -532,12 +564,6 @@ export default {
532
564
  }, 800)
533
565
  },
534
566
  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
567
  let nav = document.getElementById('navTool')
542
568
 
543
569
  if (nav) nav.addEventListener('mouseleave', this.onNavMouseleave)
@@ -623,6 +649,9 @@ export default {
623
649
 
624
650
  this.openBranchContent(content)
625
651
  break
652
+ case 'ctxCustomContent':
653
+ this.displayCustomContent(content, wrapper)
654
+ break
626
655
  }
627
656
  //delay animation
628
657
  this.rightSidebarVisible = true
@@ -661,10 +690,16 @@ export default {
661
690
  this.closeBranchContent()
662
691
  break
663
692
 
693
+ case 'ctxCustomContent':
694
+ this.closeCostumContent()
695
+ break
696
+
664
697
  default:
665
698
  this.branchingVisible = false
666
699
  this.transcriptVisible = false
700
+ this.customContentVisible = false
667
701
  this.transcriptContent = null
702
+ this.customContent = null
668
703
  this.compID = null
669
704
  }
670
705
  this.updatesideBIsOpen(this.rightSidebarVisible)
@@ -732,10 +767,11 @@ export default {
732
767
  * @fires 'transcript-hidden' to AppCompPlaybar
733
768
  */
734
769
  closeTranscript(container = this.transcriptContainer) {
770
+ let t = this.customContentVisible ? 10 : 200
735
771
  setTimeout(() => {
736
772
  this.transcriptContent = null
737
773
  this.transcriptVisible = false
738
- }, 300)
774
+ }, t)
739
775
  this.$bus.$emit('transcript-hidden')
740
776
  this.$bus.$emit('resize-media', 'lg', container)
741
777
  },
@@ -784,6 +820,21 @@ export default {
784
820
  this.$bus.$emit('branching-hidden')
785
821
  },
786
822
 
823
+ displayCustomContent(c, container) {
824
+ if (!c) return (this.customContentVisible = false)
825
+ //Change transcript content
826
+ if (this.transcriptVisible) this.closeTranscript()
827
+ //Change transcript content
828
+ this.customContent = c
829
+ this.customContentContainer = container
830
+ this.customContentVisible = true
831
+ },
832
+
833
+ closeCostumContent() {
834
+ this.customContentContainer = null
835
+ this.customContentVisible = false
836
+ },
837
+
787
838
  /**
788
839
  * @description reset the values of state (currentTimeline,currentMedialement, currentPage, media duration, appStatus')in the store
789
840
  */
@@ -874,25 +925,14 @@ export default {
874
925
  this.$scorm.setValue('cmi.core.lesson_status', 'incomplete') // set the lesson status to in complete
875
926
  this.$scorm.Commit() // persist data
876
927
  }
928
+ //Redirect to current page or to menu if route is module
929
+ this.$route.name && this.$route.name !== 'module'
930
+ ? this.$router.push({ name: this.$route.name })
931
+ : this.$router.push({ name: 'menu' })
877
932
 
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
933
  // set the current page
894
934
  this.fetchPage()
895
- this.$scorm.getScormAPI()
935
+
896
936
  break
897
937
  }
898
938
  case 'xapi':
@@ -917,53 +957,31 @@ export default {
917
957
  arg = arg || null
918
958
  let existingRecord // hold record record
919
959
  let toBeSaved // hold data to send to scorm
960
+
920
961
  if (this.$scorm.initialized) {
921
962
  if (this.$scorm.GetValue('cmi.suspend_data') !== '')
922
963
  existingRecord = JSON.parse(this.$scorm.GetValue('cmi.suspend_data')) // try convert the scorm record to JSON Obiect
923
964
  // create entry for user data if there is no record in Scorm
924
965
  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
- }
966
+
967
+ // create new entry for user data if does not existe
968
+ existingRecord.userData = this.getUserInteraction || {}
969
+ existingRecord.userSettings = this.getApplicationSettings || {}
970
+ // existingRecord.routeHistory = this.getRouteHistory || []
971
+ existingRecord.routeHistory = (() => {
972
+ const history = this.getRouteHistory.toReversed() //get the route history from the last
973
+
974
+ history[0] = this.$route.meta // change the last recored route to the current route
975
+
976
+ return history.toReversed()
977
+ })()
978
+ // update value of user data
979
+
980
+ toBeSaved = JSON.stringify(existingRecord) // convert to JSON string format
981
+
965
982
  this.$scorm.SetValue('cmi.suspend_data', toBeSaved) // converte to serialized string and save to scorm
966
983
  this.$scorm.Commit() // persist data in LMS
984
+ if (arg === 'disconnect') this.$scorm.Finish()
967
985
  }
968
986
  },
969
987
  /**
@@ -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>