fcad-core-dragon 2.0.0-beta.0 → 2.0.0-beta.1

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 (49) hide show
  1. package/README.md +1 -1
  2. package/package.json +7 -9
  3. package/src/$locales/en.json +39 -15
  4. package/src/$locales/fr.json +48 -23
  5. package/src/components/AppBase.vue +245 -266
  6. package/src/components/AppBaseErrorDisplay.vue +29 -0
  7. package/src/components/AppBaseModule.vue +485 -232
  8. package/src/components/AppBasePage.vue +28 -54
  9. package/src/components/AppCompBif.vue +120 -0
  10. package/src/components/AppCompBranchButtons.vue +31 -30
  11. package/src/components/AppCompButtonProgress.vue +35 -46
  12. package/src/components/AppCompCarousel.vue +154 -247
  13. package/src/components/AppCompJauge.vue +1 -2
  14. package/src/components/AppCompMediaPlayer.vue +106 -74
  15. package/src/components/AppCompMenu.vue +87 -81
  16. package/src/components/AppCompMenuItem.vue +48 -90
  17. package/src/components/AppCompNavigation.vue +949 -0
  18. package/src/components/AppCompNoteCall.vue +126 -0
  19. package/src/components/AppCompNoteCredit.vue +164 -0
  20. package/src/components/AppCompPlayBar.vue +864 -1085
  21. package/src/components/AppCompPopUp.vue +26 -27
  22. package/src/components/AppCompPopover.vue +27 -0
  23. package/src/components/AppCompQuiz.vue +27 -36
  24. package/src/components/AppCompQuizRecall.vue +250 -0
  25. package/src/components/AppCompSVG.vue +309 -0
  26. package/src/components/AppCompSettingsMenu.vue +1 -0
  27. package/src/components/AppCompTableOfContent.vue +140 -85
  28. package/src/components/AppCompTranscript.vue +19 -0
  29. package/src/components/AppCompVideoPlayer.vue +336 -0
  30. package/src/components/BaseModule.vue +24 -105
  31. package/src/main.js +18 -9
  32. package/src/mixins/$pageMixins.js +106 -28
  33. package/src/mixins/timerMixin.js +31 -7
  34. package/src/module/store.js +33 -12
  35. package/src/module/xapi/Crypto/encoders/Hex.js +2 -1
  36. package/src/module/xapi/wrapper.js +4 -4
  37. package/src/plugins/gsap.js +4 -1
  38. package/src/plugins/helper.js +53 -18
  39. package/src/plugins/idb.js +1 -0
  40. package/src/public/index.html +1 -1
  41. package/src/router/index.js +41 -0
  42. package/src/router/routes.js +337 -0
  43. package/src/routes_bckp.js +313 -0
  44. package/src/routes_static.js +344 -0
  45. package/src/shared/generalfuncs.js +79 -4
  46. package/src/shared/validators.js +249 -0
  47. package/src/components/AppCompNavigationFull.vue +0 -1791
  48. package/src/components/AppCompToolTip.vue +0 -94
  49. package/src/routes.js +0 -734
@@ -5,7 +5,7 @@
5
5
  @Note: Page not created with this component will not have the data automatically traked by the application
6
6
  -->
7
7
  <template>
8
- <div :id="page.id" class="app-page">
8
+ <div :id="page.id" class="app-page" role="main">
9
9
  <slot v-if="!errorPage.length" name="content">
10
10
  Page
11
11
  </slot>
@@ -52,18 +52,16 @@ export default {
52
52
  validator(value) {
53
53
  let isValid = true
54
54
  if (process.env.NODE_ENV === 'development') {
55
- const RequiredpageKeys = ['id', 'activityRef', 'type']
56
- let RequiredTypeValues = ['pg_normal', 'pg_menu']
57
-
58
- // Specifics for none DR Mode
59
- if (!value.drModeActive)
60
- RequiredTypeValues = [
61
- ...RequiredTypeValues,
62
- 'pg_animation',
63
- 'pg_media'
64
- ]
55
+ const requiredPageKeys = ['id', 'activityRef', 'type']
56
+ let requiredTypeValues = [
57
+ 'pg_normal',
58
+ 'pg_menu',
59
+ 'pg_animation',
60
+ 'pg_media',
61
+ 'pg_branch'
62
+ ]
65
63
 
66
- RequiredpageKeys.forEach((key) => {
64
+ requiredPageKeys.forEach((key) => {
67
65
  if (!Object.keys(value).includes(key)) {
68
66
  console.warn(
69
67
  `%c WARNING!>>> PAGE: PAGE: Missing ${key} for the page in $data `,
@@ -72,13 +70,9 @@ export default {
72
70
  isValid = false
73
71
  } else if (
74
72
  key === 'type' &&
75
- !RequiredTypeValues.includes(value[key])
73
+ !requiredTypeValues.includes(value[key])
76
74
  ) {
77
- let errString = ''
78
- if (value.drModeActive)
79
- errString = `Invalid value assigment for type of the page in $data, while DR mode active.`
80
- else
81
- errString = `Invalid value assigment for type of the page in $data.`
75
+ let errString = `Invalid value assigment for type of the page in $data.`
82
76
 
83
77
  console.warn(
84
78
  `%c WARNING!>>> PAGE: ${errString}`,
@@ -102,7 +96,6 @@ export default {
102
96
  ...mapGetters([
103
97
  'getRouteHistory',
104
98
  'getAllActivitiesState',
105
- 'getIntroStatus',
106
99
  'getAllCompleted',
107
100
  'getErrorChoiceDetect'
108
101
  ]),
@@ -120,21 +113,18 @@ export default {
120
113
  errorPage() {
121
114
  let err = false
122
115
  if (process.env.NODE_ENV === 'development') {
123
- this.page.drModeActive
124
- const RequiredpageKeys = ['id', 'activityRef', 'type']
116
+ const requiredPageKeys = ['id', 'activityRef', 'type']
125
117
  const errorList = []
126
118
  let count = 0
127
- let RequiredTypeValues = ['pg_normal', 'pg_menu']
119
+ let requiredTypeValues = [
120
+ 'pg_normal',
121
+ 'pg_menu',
122
+ 'pg_animation',
123
+ 'pg_media',
124
+ 'pg_branch'
125
+ ]
128
126
 
129
- // Specifics for none DR Mode
130
- if (!this.page.drModeActive)
131
- RequiredTypeValues = [
132
- ...RequiredTypeValues,
133
- 'pg_animation',
134
- 'pg_media'
135
- ]
136
-
137
- RequiredpageKeys.forEach((key) => {
127
+ requiredPageKeys.forEach((key) => {
138
128
  // required key is missing in $data that was passed for the page
139
129
  if (!Object.keys(this.page).includes(key)) {
140
130
  errorList.push(`Missing page ${key} in $data`)
@@ -142,15 +132,10 @@ export default {
142
132
  // Validator value for type
143
133
  else if (
144
134
  key === 'type' &&
145
- !RequiredTypeValues.includes(this.page[key])
135
+ !requiredTypeValues.includes(this.page[key])
146
136
  ) {
147
- if (this.page.drModeActive)
148
- errorList.push(
149
- `Invalide value assigment for type >>${this.page[key]}<< not supported in DR mode`
150
- )
151
- else
152
- errorList.push(`Invalid value assigment for page type in $data`)
153
- } else if (!this.page.drModeActive && count < 1) {
137
+ errorList.push(`Invalid value assigment for page type in $data`)
138
+ } else if (count < 1) {
154
139
  let errString = null
155
140
  const requiredValues = ['video', 'audio']
156
141
  switch (this.page.type) {
@@ -171,8 +156,6 @@ export default {
171
156
  break
172
157
  // valdation for media page type content
173
158
  case 'pg_media':
174
- // const requiredpageKeys = ['mType', 'mSources']
175
-
176
159
  if (
177
160
  !this.page.mediaData ||
178
161
  Object.keys(this.page.mediaData).length < 1
@@ -220,14 +203,12 @@ export default {
220
203
  }
221
204
  //Start validating that the files exsist
222
205
  if (!errString) {
223
-
224
206
  // start validating that the file for subtitle exist in medias folder
225
207
  if (mSubtitle && mSubtitle.src) return
226
208
 
227
209
  //validate that mPoster file is present in media file when set
228
210
  if (mPoster) {
229
211
  if (mPoster.constructor === String) return
230
-
231
212
  else {
232
213
  let errStringInconsole =
233
214
  '\n 💥 Invalid type declaration for mPoster.\n 🚩 Must be of type {String}'
@@ -298,7 +279,7 @@ export default {
298
279
  }
299
280
  }
300
281
 
301
- window.scrollTo(0, 0)
282
+ //window.scrollTo(0, 0)
302
283
  },
303
284
  mounted() {},
304
285
 
@@ -324,15 +305,8 @@ export default {
324
305
  }
325
306
  }
326
307
 
327
- #splashscreen {
328
- .modal-content {
329
- width: 100%;
330
- max-width: 800px;
331
- min-width: 500px;
332
- margin: 0 auto;
333
- #splash-form {
334
- margin-top: 40px;
335
- }
336
- }
308
+ .overlay-close-widget {
309
+ width: 100%;
310
+ height: 100%;
337
311
  }
338
312
  </style>
@@ -0,0 +1,120 @@
1
+ <!--
2
+ *@ Description: This component is used to display button for each choice
3
+ *@ What it does: The component set value a or b to the store and go to the next page
4
+ *
5
+ *@Note :
6
+ This component effect TOC(disable if the choice is not made) and NavigationFull(make jump if choise is not made).
7
+ This component need Menu setting to declare where the branching start and when the branching end.
8
+ To switch between choice see getchoiceBif() in PageMixing
9
+ See template for usage exemple
10
+ -->
11
+
12
+ <template>
13
+ <div class="box-bif">
14
+ <app-base-button
15
+ id="btn-bif-a"
16
+ class="btn-bif"
17
+ :title="titleA"
18
+ @click="setChoice('A')"
19
+ >
20
+ <div class="choice-a">
21
+ <slot name="content-a" />
22
+ </div>
23
+ </app-base-button>
24
+
25
+ <app-base-button
26
+ id="btn-bif-b"
27
+ class="btn-bif"
28
+ :title="titleB"
29
+ @click="setChoice('B')"
30
+ >
31
+ <div class="choice-b">
32
+ <slot name="content-b" />
33
+ </div>
34
+ </app-base-button>
35
+
36
+ </div>
37
+ </template>
38
+ <script>
39
+ import AppBaseButton from './AppBaseButton.vue'
40
+ import { mapGetters } from 'vuex'
41
+
42
+ export default {
43
+ name: 'AppCompBif',
44
+ components: { AppBaseButton },
45
+ props: {
46
+ titleA: {
47
+ type: String,
48
+ default: ''
49
+ },
50
+ titleB: {
51
+ type: String,
52
+ default: ''
53
+ },
54
+ consigne: {
55
+ type: Boolean,
56
+ default: true
57
+ }
58
+ },
59
+ data() {
60
+ return {}
61
+ },
62
+ computed: {
63
+ ...mapGetters(['getUserInteraction', 'getCurrentPage'])
64
+ },
65
+ mounted() {},
66
+ methods: {
67
+ setChoice(choix) {
68
+ const userInteraction = this.getProgress()
69
+ this.$set(userInteraction, 'bifChoice', choix)
70
+
71
+ let data
72
+ let num
73
+ let dataAct
74
+
75
+ // gestion go to next page
76
+ if (this.getCurrentPage.id.indexOf('0') == 1) {
77
+ data = this.getCurrentPage.id.substring(
78
+ this.getCurrentPage.id.indexOf('P') + 2
79
+ )
80
+ } else {
81
+ data = this.getCurrentPage.id.substring(
82
+ this.getCurrentPage.id.indexOf('P') + 1
83
+ )
84
+ }
85
+
86
+ num = parseInt(data)
87
+
88
+ // gestion go to next activity
89
+ if (this.$route.meta.activity_ref.indexOf('0') == 1) {
90
+ dataAct = this.$route.meta.activity_ref.substring(
91
+ this.$route.meta.activity_ref.indexOf('A') + 2
92
+ )
93
+ } else {
94
+ dataAct = this.$route.meta.activity_ref.substring(
95
+ this.$route.meta.activity_ref.indexOf('A') + 1
96
+ )
97
+ }
98
+
99
+ // go to next page
100
+ this.$router.push({
101
+ name: `activite_${dataAct}.page_${num + 1}`
102
+ })
103
+ },
104
+ getProgress() {
105
+ const { id, activity_ref } = this.$route.meta
106
+
107
+ const record = this.$store.getters.getUserInteraction
108
+ if (
109
+ Object.entries(record).length &&
110
+ record[activity_ref] &&
111
+ record[activity_ref][id]
112
+ ) {
113
+ const { userInteraction } = record[activity_ref][id]
114
+ return userInteraction
115
+ }
116
+ return {}
117
+ }
118
+ }
119
+ }
120
+ </script>
@@ -49,14 +49,6 @@ Si la composante est appelée sans prop, les boutons par défaut seront génér
49
49
  </b-col>
50
50
  </b-row>
51
51
  <b-row v-else>
52
- <b-col v-if="consigne">
53
- <!--- Paramètre ajouter pour la faire apparaitre au besoin --->
54
- <app-base-instruction
55
- v-show="consigne"
56
- :text-instruction="$t(`instruction.branch`)"
57
- :text-button="$t('button.instructions')"
58
- />
59
- </b-col>
60
52
  <b-col
61
53
  v-for="branch of branchsStateData"
62
54
  :id="branch.id"
@@ -75,7 +67,8 @@ Si la composante est appelée sans prop, les boutons par défaut seront génér
75
67
  </slot>
76
68
 
77
69
  <app-comp-button-progress
78
- :percent="branch.progression"
70
+ :set-target="sidebar"
71
+ :percent="branch.progression ? branch.progression : 0"
79
72
  :branch-data="branch"
80
73
  :btn-title="getMatchingElement(branch.id).btnTitle"
81
74
  no-interaction
@@ -87,7 +80,8 @@ Si la composante est appelée sans prop, les boutons par défaut seront génér
87
80
  >
88
81
  <b-card style="max-width: 20rem;" no-body>
89
82
  <app-comp-button-progress
90
- :percent="branch.progression"
83
+ :set-target="sidebar"
84
+ :percent="branch.progression ? branch.progression : 0"
91
85
  :branch-data="branch"
92
86
  :btn-title="getMatchingElement(branch.id).btnTitle"
93
87
  ></app-comp-button-progress>
@@ -107,7 +101,8 @@ Si la composante est appelée sans prop, les boutons par défaut seront génér
107
101
  </div>
108
102
  <div v-else class="branch-btn-wrapper">
109
103
  <app-comp-button-progress
110
- :percent="branch.progression"
104
+ :set-target="sidebar"
105
+ :percent="branch.progression ? branch.progression : 0"
111
106
  :branch-data="branch"
112
107
  :btn-title="branch.text"
113
108
  ></app-comp-button-progress>
@@ -130,6 +125,10 @@ export default {
130
125
  type: Boolean,
131
126
  default: false
132
127
  },
128
+ sidebar: {
129
+ type: String,
130
+ default: 'branch-viewer'
131
+ },
133
132
  btnTitle: {
134
133
  type: String,
135
134
  default: ' '
@@ -287,19 +286,14 @@ export default {
287
286
  }
288
287
  },
289
288
  watch: {
290
- // getConnectionInfo:{
291
- // //in development environment (localhost), don't wait for the axios call
292
- // // immediate: process.env.NODE_ENV === 'development',
293
- // handler(){
294
- // this.getbranchsData()
295
- // }
296
- // },
297
-
298
289
  getAllCompleted: {
299
290
  //watch the completions to update the branches progression
300
291
  handler() {
301
- if (this.getAllCompleted[this.idActivity].length)
302
- this.getbranchsData()
292
+ if (
293
+ this.getAllCompleted[this.idActivity] &&
294
+ this.getAllCompleted[this.idActivity].length
295
+ )
296
+ this.getbranchsData()
303
297
  }
304
298
  }
305
299
  },
@@ -319,15 +313,16 @@ export default {
319
313
  this.branchsStateData = []
320
314
  this.branchs.forEach((branch, index) => {
321
315
  let branchData = {}
322
- branchData.id = branch._ref.slice(0, 7)
316
+ branchData.id = branch._ref
323
317
  branchData.route = branch._namedRoute
324
-
325
- const { state = "new", progression=0 } = this.getBranchProgression(branchData.id)
326
-
318
+ let { state = 'new', progression = 0 } = this.getBranchProgression(
319
+ branchData.id
320
+ )
327
321
  // if (!state || !progression) return
328
322
 
329
323
  branchData.state = state
330
324
  branchData.progression = progression
325
+ if (isNaN(branchData.progression)) branchData.progression = 0
331
326
 
332
327
  if (this.isCard) {
333
328
  const {
@@ -340,7 +335,10 @@ export default {
340
335
 
341
336
  branchData = { ...branchData, text, title, imgFile, imgAlt, btnTitle }
342
337
 
343
- if (typeof branchData.imgAlt === 'undefined') {
338
+ if (
339
+ typeof branchData.imgAlt === 'undefined' &&
340
+ process.env.NODE_ENV === 'development'
341
+ ) {
344
342
  branchData.imgAlt = ''
345
343
  console.warn(
346
344
  `Bouton d’embranchement: ALT image sans valeur définie pour ${branchData.id}`
@@ -362,16 +360,16 @@ export default {
362
360
  if (!this.getAllCompleted[this.idActivity]) return result // no progression found for this activity return result
363
361
 
364
362
  const total = this.getBranchPagesCount(idBranch) // get all pages for in this branch
365
-
366
363
  //get all completed branches pages
367
364
  const completedPages = this.getAllCompleted[this.idActivity].filter(
368
365
  (page) => {
369
366
  return Object.keys(page)[0].search(idBranch) !== -1
370
367
  }
371
368
  )
372
-
373
369
  result.progression = Math.floor((completedPages.length / total) * 100)
374
370
 
371
+ if (isNaN(result.progression)) result.progression = 0
372
+
375
373
  if (result.progression === 0) {
376
374
  result.state = this.status.NEW
377
375
  } else if (result.progression === 100) {
@@ -388,11 +386,14 @@ export default {
388
386
  * @return {Array} /Return the total of pages in a specific branch
389
387
  */
390
388
  getBranchPagesCount(idBranch) {
389
+ if (this.$router.currentRoute.meta.type !== 'branching') return
390
+
391
391
  const allPages = this.getAllActivities.list
392
392
  .get(this.idActivity)
393
393
  .get(this.$router.currentRoute.meta.id)
394
- .get(idBranch.slice(4, 7))
395
- return allPages.size
394
+ .get(idBranch)
395
+
396
+ return allPages.size ? allPages.size : 1
396
397
  },
397
398
 
398
399
  /**
@@ -17,56 +17,20 @@
17
17
  </svg>
18
18
  <button
19
19
  :id="`btn_branch_${branchData.id}`"
20
+ :target-ref="branchData.id"
20
21
  :title="btnTitle || $t('text.place_holder.for_title_btn_progress')"
21
22
  :class="
22
23
  branchData.state === status.COMPLETE
23
24
  ? 'branch-btn-default branche-complete'
24
25
  : 'branch-btn-default'
25
26
  "
26
- @click="$router.push({ name: branchData.route })"
27
+ @click="openBranch(branchData.id)"
27
28
  >
28
- <svg
29
- v-if="branchData.state === status.COMPLETE"
30
- id="branch-btn-crochet"
31
- xmlns="http://www.w3.org/2000/svg"
32
- width="24"
33
- height="24"
34
- viewBox="0 0 24 24"
35
- >
36
- <path
37
- id="Tracé_3833"
38
- data-name="Tracé 3833"
39
- d="M0,0H24V24H0Z"
40
- fill="none"
41
- />
42
- <path
43
- id="Tracé_3834"
44
- data-name="Tracé 3834"
45
- d="M9,16.2,4.8,12,3.4,13.4,9,19,21,7,19.6,5.6Z"
46
- fill="#e6f5ff"
47
- />
29
+ <svg v-if="branchData.state === status.COMPLETE" width="24" height="24">
30
+ <use href="#branch-crochet-icon"></use>
48
31
  </svg>
49
-
50
- <svg
51
- v-if="branchData.state != status.COMPLETE"
52
- id="navigate_next_black_24dp"
53
- xmlns="http://www.w3.org/2000/svg"
54
- width="24"
55
- height="24"
56
- viewBox="0 0 24 24"
57
- >
58
- <path
59
- id="Path_3899"
60
- data-name="Path 3899"
61
- d="M0,0H24V24H0Z"
62
- fill="none"
63
- />
64
- <path
65
- id="Path_3900"
66
- data-name="Path 3900"
67
- d="M10.02,6,8.61,7.41,13.19,12,8.61,16.59,10.02,18l6-6Z"
68
- fill="#fff"
69
- />
32
+ <svg v-if="branchData.state != status.COMPLETE" width="24" height="24">
33
+ <use href="#navigate-next-icon"></use>
70
34
  </svg>
71
35
  </button>
72
36
  </div>
@@ -79,7 +43,7 @@ export default {
79
43
  default: false
80
44
  },
81
45
  percent: {
82
- type: Number,
46
+ type: [Number],
83
47
  default: 0,
84
48
  required: true
85
49
  },
@@ -87,6 +51,11 @@ export default {
87
51
  type: Object,
88
52
  required: true
89
53
  },
54
+ setTarget: {
55
+ type: [String],
56
+ default: ''
57
+ },
58
+
90
59
  btnTitle: {
91
60
  type: String,
92
61
  default: null
@@ -101,11 +70,31 @@ export default {
101
70
  NEW: 'new',
102
71
  STARTED: 'started',
103
72
  COMPLETE: 'complete'
104
- }
73
+ },
74
+ withRouter: false, //Only for demo purpose. Remove after demo
75
+ isActive: false
105
76
  }
106
77
  },
107
- beforeMount() {},
108
- methods: {}
78
+
79
+ created() {
80
+ if (isNaN(this.percent)) this.percent = 0
81
+ this.$bus.$on('branching-hidden', this.resetIsActive)
82
+ },
83
+
84
+ beforeDestroy() {
85
+ this.$bus.$off('branching-hidden', this.resetIsActive)
86
+ },
87
+
88
+ methods: {
89
+ openBranch(e) {
90
+ this.isActive = true
91
+ this.$bus.$emit('open-sidebar', { ctx: 'ctxBranching', e })
92
+ },
93
+
94
+ resetIsActive() {
95
+ this.isActive = false
96
+ }
97
+ }
109
98
  }
110
99
  </script>
111
100
  <style lang="scss">