fcad-core-dragon 2.1.0-beta.3 → 2.1.0

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 (38) hide show
  1. package/.editorconfig +6 -31
  2. package/.prettierrc +11 -0
  3. package/.vscode/extensions.json +8 -0
  4. package/.vscode/settings.json +16 -0
  5. package/CHANGELOG +23 -0
  6. package/documentation/composants/app-comp-audio.md +35 -3
  7. package/documentation/composants/app-comp-video-player.md +42 -3
  8. package/eslint.config.js +60 -0
  9. package/package.json +9 -9
  10. package/src/$locales/en.json +3 -3
  11. package/src/$locales/fr.json +3 -3
  12. package/src/components/AppBase.vue +5 -6
  13. package/src/components/AppBaseModule.vue +15 -17
  14. package/src/components/AppBasePage.vue +866 -783
  15. package/src/components/AppBaseSkeleton.vue +24 -3
  16. package/src/components/AppCompAudio.vue +12 -2
  17. package/src/components/AppCompInputCheckBoxNx.vue +1 -2
  18. package/src/components/AppCompInputRadioNx.vue +8 -2
  19. package/src/components/AppCompInputTextToFillDropdownNx.vue +45 -0
  20. package/src/components/AppCompMenu.vue +424 -423
  21. package/src/components/AppCompNavigation.vue +2 -2
  22. package/src/components/AppCompPlayBarNext.vue +123 -94
  23. package/src/components/AppCompPopUpNext.vue +2 -2
  24. package/src/components/AppCompQuizNext.vue +12 -2
  25. package/src/components/AppCompQuizRecall.vue +10 -4
  26. package/src/components/AppCompTableOfContent.vue +1 -4
  27. package/src/components/AppCompVideoPlayer.vue +7 -0
  28. package/src/composables/useTimer.js +17 -20
  29. package/src/module/stores/appStore.js +0 -1
  30. package/src/module/xapi/Statement/index.js +2 -2
  31. package/src/plugins/gsap.js +1 -0
  32. package/src/plugins/helper.js +4 -0
  33. package/src/public/index.html +4 -4
  34. package/src/router/index.js +1 -1
  35. package/src/shared/validators.js +22 -6
  36. package/.eslintignore +0 -29
  37. package/.eslintrc.cjs +0 -81
  38. package/bk.scss +0 -117
package/.editorconfig CHANGED
@@ -1,33 +1,8 @@
1
- # http://editorconfig.org
2
- root = true
3
-
4
- [*]
5
- indent_style = space
6
- indent_size = 2
7
- end_of_line = lf
1
+ [*.{js,jsx,mjs,cjs,ts,tsx,mts,cts,vue,css,scss,sass,less,styl}]
8
2
  charset = utf-8
9
- trim_trailing_whitespace = true
3
+ indent_size = 2
4
+ indent_style = space
10
5
  insert_final_newline = true
11
-
12
-
13
- # The JSON files contain newlines inconsistently
14
- [*.json]
15
- insert_final_newline = ignore
16
-
17
- # Minified JavaScript files shouldn't be changed
18
- [**.min.js]
19
- indent_style = ignore
20
- insert_final_newline = ignore
21
-
22
- # Makefiles always use tabs for indentation
23
- [Makefile]
24
- indent_style = tab
25
-
26
- # Batch files use tabs for indentation
27
- [*.bat]
28
- indent_style = tab
29
-
30
- [*.md]
31
- trim_trailing_whitespace = false
32
- insert_final_newline = false
33
-
6
+ trim_trailing_whitespace = true
7
+ end_of_line = lf
8
+ max_line_length = 80
package/.prettierrc ADDED
@@ -0,0 +1,11 @@
1
+ {
2
+ "$schema": "https://www.schemastore.org/prettierrc.json",
3
+ "singleQuote": true,
4
+ "semi": false,
5
+ "tabWidth": 2,
6
+ "trailingComma": "none",
7
+ "arrowParens": "always",
8
+ "htmlWhitespaceSensitivity": "ignore",
9
+ "endOfLine": "auto",
10
+ "printWidth": 80
11
+ }
@@ -0,0 +1,8 @@
1
+ {
2
+ "recommendations": [
3
+ "Vue.volar",
4
+ "dbaeumer.vscode-eslint",
5
+ "EditorConfig.EditorConfig",
6
+ "esbenp.prettier-vscode"
7
+ ]
8
+ }
@@ -0,0 +1,16 @@
1
+ {
2
+ "explorer.fileNesting.enabled": true,
3
+ "explorer.fileNesting.patterns": {
4
+ "tsconfig.json": "tsconfig.*.json, env.d.ts",
5
+ "vite.config.*": "jsconfig*, vitest.config.*, cypress.config.*, playwright.config.*",
6
+ "package.json": "package-lock.json, pnpm*, .yarnrc*, yarn*, .eslint*, eslint*, .oxlint*, oxlint*, .prettier*, prettier*, .editorconfig"
7
+ },
8
+ "editor.codeActionsOnSave": {
9
+ "source.fixAll": "explicit"
10
+ },
11
+ "editor.formatOnSave": true,
12
+ "editor.defaultFormatter": "esbenp.prettier-vscode",
13
+ "[vue]": {
14
+ "editor.defaultFormatter": "esbenp.prettier-vscode"
15
+ }
16
+ }
package/CHANGELOG CHANGED
@@ -1,3 +1,26 @@
1
+ 2.0.3(24 novembre 2025)
2
+ Correction Beta apporter
3
+
4
+ 2.1.0-beta.10(20 novembre 2025)
5
+ Correction de l’affichage des listes déroulantes
6
+
7
+ Correction de la validation des object de quiz si le quiz n’est pas null il ne valide pas le contenu du pop-up neutre
8
+
9
+ Correction des titres dans les pop-ups de fin d’activité et de leçon (le titre est la maintenant)
10
+
11
+ 2.1.0-beta.5(22 octobre 2025)
12
+ Correction du problème de complétion avec les fenêtres latérales
13
+
14
+ Multiples corrections de l’accessibilité
15
+
16
+ Optimisation des dépendances (package.json)
17
+
18
+ Amélioration de quizrecall (récupération du data)
19
+
20
+ 2.1.0-beta.4(26 septembre 2025)
21
+ ajout du plugin ScrollTrigger à l’objet $gsap
22
+
23
+
1
24
  2.1.0-beta.3(24 septembre 2025)
2
25
  RUPTURE DE COMPATIBILITÉ : Ajout de Google Analytics (analytics_id dans app.vue) nouvelle dépendance : npm install vue-gtag@2.0.1
3
26
 
@@ -15,9 +15,41 @@ S'affiche dans un en cadré avec un titre (obligatoire), une image (pas obligat
15
15
  `<app-comp-audio-player :aud-data="audioData2"/>`
16
16
 
17
17
 
18
- ## Paramètre
19
-
20
- Aucun paramètre n'est nécessaire pour ce composant.
18
+ ## Structure de données
19
+ Voici la structure à utiliser pour les données d'un contenu audio
20
+ > [!IMPORTANT]
21
+ > audiosData doit être un tableau (array)
22
+ ```js
23
+ import aud1 from '@/assets/medias/exemple_audio.mp3'
24
+ import posterAud1 from '@/assets/img/audio_poster.png'
25
+
26
+ export default {
27
+ data() {
28
+ return {
29
+ id: 'P01',
30
+ activityRef: 'A03',
31
+ title: 'Lecteurs médias',
32
+ type: 'pg_normal',
33
+ audiosData: [
34
+ {
35
+ id: 'aud1',
36
+ mTitle: 'Et si... Annie Ernaux nous parlait',
37
+ mSources: [
38
+ {
39
+ type: 'mp3',
40
+ src: aud1
41
+ }
42
+ ],
43
+ mPoster: posterAud1,
44
+ mAlt: "Portrait de l'autrice Annie Ernaux",
45
+ mTranscript:
46
+ '<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.</p>'
47
+ }
48
+ ]
49
+ }
50
+ }
51
+ }
52
+ ```
21
53
 
22
54
  ### Props
23
55
 
@@ -20,9 +20,48 @@ Les transcripts ouvrent dans une fenêtre latérale. Une seule fenêtre peux êt
20
20
 
21
21
  `<app-comp-video-player :vid-data="videoData" />`
22
22
 
23
- ## Paramètre
24
-
25
- Il n'y a pas de paramètre pour ce composant.
23
+ ## Structure de données
24
+
25
+ Voici la structure à utiliser pour les données d'une vidéo
26
+ > [!IMPORTANT]
27
+ > videosData doit être un tableau (array)
28
+
29
+ ```js
30
+ import videoExemple from '@/assets/medias/exemple_video.mp4'
31
+ import posterDandurand from '@/assets/img/video_poster.jpg'
32
+ import vttVid1FR from '@/assets/medias/exemple_soustitres.vtt'
33
+
34
+ export default {
35
+ data() {
36
+ return {
37
+ id: 'P01',
38
+ activityRef: 'A03',
39
+ title: 'Lecteurs médias',
40
+ type: 'pg_normal',
41
+ videosData: [
42
+ {
43
+ id: 'vid1',
44
+ mSources: [
45
+ {
46
+ type: 'mp4',
47
+ src: videoExemple
48
+ }
49
+ ],
50
+ mSubtitles: [
51
+ {
52
+ label: 'Français',
53
+ src: vttVid1FR,
54
+ srclang: 'fr'
55
+ }
56
+ ],
57
+ mPoster: posterDandurand,
58
+ mTranscript: 'exemple_transcript.html' // The file MUST be in the public folder of the project
59
+ }
60
+ ]
61
+ }
62
+ }
63
+ }
64
+ ```
26
65
 
27
66
  ### Props
28
67
 
@@ -0,0 +1,60 @@
1
+ import js from '@eslint/js'
2
+ import globals from 'globals'
3
+ import pluginVue from 'eslint-plugin-vue'
4
+ import { defineConfig, globalIgnores } from 'eslint/config'
5
+ import skipFormatting from '@vue/eslint-config-prettier/skip-formatting'
6
+
7
+ export default defineConfig([
8
+ {
9
+ files: ['**/*.{js,mjs,cjs,vue}']
10
+ },
11
+ globalIgnores([
12
+ '**/.DS_Store',
13
+ '**/node_modules',
14
+ '**/dist/**',
15
+ '**/coverage/**',
16
+ '**/yalc.lock',
17
+ '**/package-lock.json',
18
+ '**/.zip',
19
+ '**/.env.local',
20
+ '**/.env.*.local',
21
+ '**/npm-debug.log*',
22
+ '**/.idea',
23
+ '**/.vscode',
24
+ '**/*.suo',
25
+ '**/*.ntvs*',
26
+ '**/*.njsproj',
27
+ '**/*.sln',
28
+ '**/*.sw?',
29
+ '**/\\_*',
30
+ '**/.gitignore'
31
+ ]),
32
+ {
33
+ languageOptions: {
34
+ globals: {
35
+ ...globals.node,
36
+ ...globals.browser
37
+ }
38
+ }
39
+ },
40
+ js.configs.recommended,
41
+ ...pluginVue.configs['flat/recommended'],
42
+ {
43
+ rules: {
44
+ 'no-unused-vars': [
45
+ 'warn',
46
+ { vars: 'local', args: 'none', ignoreRestSiblings: true }
47
+ ],
48
+ 'vue/no-unused-vars': 'warn',
49
+ 'no-prototype-builtins': 'off',
50
+ 'vue/html-self-closing': 'off',
51
+ 'vue/no-v-html': 'off',
52
+ 'vue/no-v-text-v-html-on-component': 'off',
53
+ 'vue/no-deprecated-delete-set': 'warn',
54
+ 'vue/max-attributes-per-line': 'off',
55
+ 'vue/singleline-html-element-content-newline': 'off',
56
+ 'vue/component-name-in-template-casing': ['error', 'kebab-case']
57
+ }
58
+ },
59
+ skipFormatting
60
+ ])
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fcad-core-dragon",
3
- "version": "2.1.0-beta.3",
3
+ "version": "2.1.0",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "main": "./src/main.js",
@@ -10,14 +10,14 @@
10
10
  "docs:build": "vitepress build documentation",
11
11
  "docs:dev": "vitepress dev documentation",
12
12
  "docs:preview": "vitepress preview documentation",
13
- "format": "prettier --write src/",
14
- "lintfix": "eslint --ext .js,.vue --ignore-path .gitignore --fix src",
15
- "lintreport": "eslint src --ext .js,.vue --ignore-path .gitignore",
13
+ "lintfix": "eslint --fix src",
14
+ "lintreport": "eslint ./src",
16
15
  "preview": "vite preview",
17
16
  "reset": "rm -rf ./node_modules package-lock.json .cache dist && npm i && npm run watch",
18
17
  "test:unit": "vitest",
19
18
  "vue": "vue",
20
- "watch": "nodemon -e js,vue,html,json -x yalc publish --push"
19
+ "watch": "nodemon -e js,vue,html,json -x yalc publish --push",
20
+ "format": "prettier --write src/"
21
21
  },
22
22
  "config": {
23
23
  "projname": ""
@@ -37,20 +37,20 @@
37
37
  "vue-safe-teleport": "^0.1.2"
38
38
  },
39
39
  "devDependencies": {
40
+ "@eslint/js": "^9.38.0",
40
41
  "@vitejs/plugin-vue": "^6.0.1",
41
42
  "@vue/eslint-config-prettier": "^10.2.0",
42
43
  "@vue/test-utils": "^2.4.6",
43
- "eslint": "^9.31.0",
44
+ "eslint": "^9.38.0",
44
45
  "eslint-plugin-cypress": "^5.1.0",
45
46
  "eslint-plugin-vue": "~10.3.0",
47
+ "globals": "^16.4.0",
46
48
  "jsdom": "^25.0.1",
47
49
  "nodemon": "^3.1.0",
48
- "prettier": "3.6.2",
50
+ "prettier": "^3.6.2",
49
51
  "sass-embedded": "^1.91.0",
50
- "vite-plugin-vue-devtools": "^8.0.2",
51
52
  "vitepress": "^1.6.3",
52
53
  "vitest": "^3.2.4",
53
- "vue": "^3.5.18",
54
54
  "vue-router": "^4.4.5"
55
55
  },
56
56
  "engines": {
@@ -98,10 +98,10 @@
98
98
  "activity_title": "My activities",
99
99
  "activity_progress": "Progress status:",
100
100
  "carousel": "Carousel",
101
- "conclusion": "Conclusion",
101
+ "conclusion": "Conclusion to the Lesson",
102
102
  "complete": "Completed",
103
103
  "error": "error",
104
- "introduction": "Introduction",
104
+ "introduction": "Introduction to the Lesson",
105
105
  "lesson": "Lesson",
106
106
  "quiz": "Words to complete the sentence",
107
107
  "place_holder": {
@@ -154,4 +154,4 @@
154
154
  "seek_slider": "Seek slider",
155
155
  "range_expression": "at %x of %y."
156
156
  }
157
- }
157
+ }
@@ -61,10 +61,10 @@
61
61
  "activity_title": "Mes activités",
62
62
  "activity_progress": "État d’avancement :",
63
63
  "carousel": "Carrousel",
64
- "conclusion": "Conclusion",
64
+ "conclusion": "Conclusion de la leçon",
65
65
  "complete": "Terminé",
66
66
  "error": "erreur",
67
- "introduction": "Introduction",
67
+ "introduction": "Introduction de la leçon",
68
68
  "lesson": "Leçon",
69
69
  "quiz": "Mot complétant la phrase",
70
70
  "place_holder": {
@@ -117,4 +117,4 @@
117
117
  "seek_slider": "Barre de lecture",
118
118
  "range_expression": "à %x sur %y."
119
119
  }
120
- }
120
+ }
@@ -39,7 +39,7 @@
39
39
  <div v-if="appDebugMode" class="timer">
40
40
  <!-- <div class="timer"> -->
41
41
  <div>Act: {{ appTimer.ISOTimeParser(activityDuration) }}</div>
42
- <span>&nbsp|&nbsp</span>
42
+ <span>&nbsp;|&nbsp;</span>
43
43
  <div>Les: {{ appTimer.ISOTimeParser(lessonDuration) }}</div>
44
44
  </div>
45
45
  <app-icons-next :extra-icons="userExtraIcons" />
@@ -70,7 +70,7 @@ import { Timer } from '../composables/useTimer.js'
70
70
  import { IdleDetector } from '../composables/useIdleDetector.js'
71
71
  import { validateAppContent } from '../shared/validators'
72
72
  import { version as fcadVersion } from '../../package.json'
73
- import { computed, h, reactive } from 'vue'
73
+ import { computed, reactive } from 'vue'
74
74
  import mobileDetect from 'mobile-detect'
75
75
 
76
76
  export default {
@@ -193,10 +193,9 @@ export default {
193
193
  }
194
194
  },
195
195
  'store.$state.userDataLoaded': {
196
- handler() {
197
- !this.store.$state.userDataLoaded
198
- ? this.updateTracker('appBase', 'loading')
199
- : this.updateTracker('appBase', 'ready')
196
+ handler(newValue) {
197
+ if (!newValue) return this.updateTracker('appBase', 'loading')
198
+ this.updateTracker('appBase', 'ready')
200
199
  },
201
200
  immediate: true
202
201
  },
@@ -29,6 +29,8 @@
29
29
  />
30
30
  </nav>
31
31
  <base-module :m-data="$data">
32
+
33
+
32
34
  <v-container
33
35
  id="wrapper-content"
34
36
  fluid
@@ -184,7 +186,6 @@ export default {
184
186
  appReady() {
185
187
  return this.getAppStatus === 'ready' ? true : false
186
188
  },
187
-
188
189
  hasMedia() {
189
190
  return typeof this.hasMediaElOrTimeline === 'object'
190
191
  },
@@ -203,7 +204,6 @@ export default {
203
204
  return true
204
205
  else return false
205
206
  },
206
-
207
207
  /**
208
208
  * @description Set the id the module
209
209
  */
@@ -233,7 +233,6 @@ export default {
233
233
  description = this.moduleConfig.description
234
234
  return description
235
235
  },
236
-
237
236
  /**
238
237
  * @description set Previous/Next can allow navigation between activities.
239
238
  *
@@ -338,7 +337,6 @@ export default {
338
337
 
339
338
  return sidebarSettings
340
339
  },
341
-
342
340
  navigationHistory() {
343
341
  return this.getRouteHistory
344
342
  }
@@ -521,7 +519,7 @@ export default {
521
519
  lessonLabel = this.$t('text.lesson')
522
520
  lessonNumber = this.moduleConfig.id.replace('module_', '')
523
521
  lessonTitle = this.theTitle
524
- titleString = lessonLabel + ' ' + lessonNumber + ' : ' + lessonTitle
522
+ titleString = lessonLabel + ' ' + lessonNumber + ' ' + lessonTitle
525
523
 
526
524
  //Remove prefix for introduction or conclusion, according to isIntroConclu setting in Module.vue
527
525
  if (typeof this.moduleConfig.isIntroConclu !== 'undefined') {
@@ -626,7 +624,7 @@ export default {
626
624
  async handleKeyboardControls(evt) {
627
625
  let { code } = evt
628
626
 
629
- if (code === 'Escape' && this.rightSidebarVisible){
627
+ if (code === 'Escape' && this.rightSidebarVisible) {
630
628
  this.closeSidebar(this.dynamicSidebarContent._context)
631
629
  }
632
630
  },
@@ -661,15 +659,15 @@ export default {
661
659
  //delay animation
662
660
  this.rightSidebarVisible = true
663
661
  this.updatesideBIsOpen(this.rightSidebarVisible)
664
- setTimeout(() => {
665
- const rightSidebarContent = this.getRightSidebar() // Emelent displayed in the sidebar-body
666
- if (!rightSidebarContent) return
667
- rightSidebarContent.scrollTop = 0
668
- const rSidebar = document.querySelector('#right-sidebar') // the sidebar
669
- rSidebar.dispatchEvent(this.rightSidebarEvent)
670
- rSidebar.setAttribute('tabindex', -1)
671
- this.resetFocus(rSidebar) //set focus on the sidebar
672
- }, 100)
662
+ // setTimeout(() => {
663
+ const rightSidebarContent = this.getRightSidebar() // Emelent displayed in the sidebar-body
664
+ if (!rightSidebarContent) return
665
+ rightSidebarContent.scrollTop = 0
666
+ const rSidebar = document.querySelector('#right-sidebar') // the sidebar
667
+ rSidebar.dispatchEvent(this.rightSidebarEvent)
668
+ rSidebar.setAttribute('tabindex', -1)
669
+ this.resetFocus(rSidebar) //set focus on the sidebar
670
+ // }, 100)
673
671
  },
674
672
  /**
675
673
  * @description close the right sidebar component
@@ -682,6 +680,7 @@ export default {
682
680
  this.rightSidebarVisible = false //
683
681
  setTimeout(() => {
684
682
  const rSidebar = document.querySelector('#right-sidebar') // the sidebar
683
+ if (!rSidebar) return
685
684
  rSidebar.setAttribute('style', 'display:none')
686
685
  rSidebar.dispatchEvent(this.rightSidebarEvent) //this will allow to run the animation of sidebar closing 1rst
687
686
  }, 100)
@@ -785,7 +784,6 @@ export default {
785
784
  openBranchContent(branchID) {
786
785
  this.branchingVisible = true
787
786
  this.compID = branchID //set compenent ID
788
-
789
787
  setTimeout(() => {
790
788
  const rightSidebar = this.getRightSidebar()
791
789
  //Should indicate that page is completed when the Rightsidebar content heigh is less then window height
@@ -847,7 +845,7 @@ export default {
847
845
 
848
846
  return new Promise((res) => {
849
847
  this.$bus.$emit('set-comp-status', 'appBaseModule', 'loading')
850
- this.updateCurrentTimeline('')
848
+ this.updateCurrentTimeline(null)
851
849
  this.updateCurrentMediaElements([])
852
850
  // this.updateCurrentPage({})
853
851
  this.$bus.$emit('set-comp-status', 'appBaseModule', 'ready')