fcad-core-dragon 2.1.1 → 2.1.2
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.
- package/.editorconfig +7 -7
- package/.gitlab-ci.yml +124 -0
- package/.prettierrc +11 -11
- package/.vscode/extensions.json +8 -8
- package/.vscode/settings.json +46 -16
- package/CHANGELOG +520 -520
- package/README.md +57 -57
- package/documentation/.vitepress/config.js +114 -114
- package/documentation/api-examples.md +49 -49
- package/documentation/composants/app-base-button.md +58 -58
- package/documentation/composants/app-base-error-display.md +59 -59
- package/documentation/composants/app-base-popover.md +68 -68
- package/documentation/composants/app-comp-audio.md +75 -75
- package/documentation/composants/app-comp-branch-buttons.md +111 -111
- package/documentation/composants/app-comp-button-progress.md +53 -53
- package/documentation/composants/app-comp-carousel.md +53 -53
- package/documentation/composants/app-comp-container.md +53 -53
- package/documentation/composants/app-comp-input-checkbox-next.md +42 -42
- package/documentation/composants/app-comp-input-dropdown-next.md +34 -34
- package/documentation/composants/app-comp-input-radio-next.md +39 -39
- package/documentation/composants/app-comp-input-text-next.md +35 -35
- package/documentation/composants/app-comp-input-text-table-next.md +34 -34
- package/documentation/composants/app-comp-input-text-to-fill-dropdown-next.md +53 -53
- package/documentation/composants/app-comp-input-text-to-fill-next.md +31 -31
- package/documentation/composants/app-comp-jauge.md +31 -31
- package/documentation/composants/app-comp-menu-item.md +55 -55
- package/documentation/composants/app-comp-menu.md +29 -29
- package/documentation/composants/app-comp-navigation.md +41 -41
- package/documentation/composants/app-comp-note-call.md +53 -53
- package/documentation/composants/app-comp-note-credit.md +53 -53
- package/documentation/composants/app-comp-play-bar-next.md +53 -53
- package/documentation/composants/app-comp-pop-up-next.md +93 -93
- package/documentation/composants/app-comp-quiz-next.md +235 -235
- package/documentation/composants/app-comp-quiz-recall.md +53 -53
- package/documentation/composants/app-comp-svg-next.md +53 -53
- package/documentation/composants/app-comp-table-of-content.md +50 -50
- package/documentation/composants/app-comp-video-player.md +82 -82
- package/documentation/composants.md +46 -46
- package/documentation/composants_critiques/ModelPageComposant.md +53 -53
- package/documentation/composants_critiques/app-base-module.md +43 -43
- package/documentation/composants_critiques/app-base-page.md +48 -48
- package/documentation/composants_critiques/app-base.md +311 -311
- package/documentation/composants_critiques/main.md +15 -15
- package/documentation/demarrage.md +50 -50
- package/documentation/deploiement.md +57 -57
- package/documentation/index.md +33 -33
- package/documentation/markdown-examples.md +85 -85
- package/documentation/public/vite.svg +14 -14
- package/documentation/public/vuejs.svg +1 -1
- package/documentation/public/vuetify.svg +5 -5
- package/eslint.config.js +60 -60
- package/junit-report.xml +182 -0
- package/package.json +66 -59
- package/playwright/index.html +12 -0
- package/playwright/index.js +21 -0
- package/playwright-ct.config.js +95 -0
- package/src/$locales/en.json +157 -157
- package/src/$locales/fr.json +120 -120
- package/src/assets/data/onboardingMessages.json +47 -47
- package/src/components/AppBase.vue +1171 -1169
- package/src/components/AppBaseButton.vue +90 -95
- package/src/components/AppBaseErrorDisplay.vue +438 -438
- package/src/components/AppBaseFlipCard.vue +84 -84
- package/src/components/AppBaseModule.vue +1639 -1634
- package/src/components/AppBasePage.vue +867 -866
- package/src/components/AppBasePopover.vue +41 -41
- package/src/components/AppBaseSkeleton.vue +66 -66
- package/src/components/AppCompAudio.vue +261 -256
- package/src/components/AppCompBranchButtons.vue +508 -508
- package/src/components/AppCompButtonProgress.vue +137 -132
- package/src/components/AppCompCarousel.vue +342 -336
- package/src/components/AppCompContainer.vue +29 -29
- package/src/components/AppCompInputCheckBoxNx.vue +325 -323
- package/src/components/AppCompInputDropdownNx.vue +302 -299
- package/src/components/AppCompInputRadioNx.vue +287 -284
- package/src/components/AppCompInputTextNx.vue +156 -153
- package/src/components/AppCompInputTextTableNx.vue +205 -202
- package/src/components/AppCompInputTextToFillDropdownNx.vue +343 -340
- package/src/components/AppCompInputTextToFillNx.vue +316 -313
- package/src/components/AppCompJauge.vue +81 -81
- package/src/components/AppCompMenu.vue +6 -1
- package/src/components/AppCompMenuItem.vue +246 -240
- package/src/components/AppCompNavigation.vue +977 -972
- package/src/components/AppCompNoteCall.vue +167 -161
- package/src/components/AppCompNoteCredit.vue +496 -491
- package/src/components/AppCompPlayBarNext.vue +2290 -2288
- package/src/components/AppCompPopUpNext.vue +508 -504
- package/src/components/AppCompQuizNext.vue +515 -510
- package/src/components/AppCompQuizRecall.vue +355 -350
- package/src/components/AppCompSVGNext.vue +346 -346
- package/src/components/AppCompSettingsMenu.vue +177 -172
- package/src/components/AppCompTableOfContent.vue +433 -427
- package/src/components/AppCompVideoPlayer.vue +377 -377
- package/src/components/AppCompViewDisplay.vue +6 -6
- package/src/components/BaseModule.vue +55 -55
- package/src/composables/useIdleDetector.js +56 -56
- package/src/composables/useQuiz.js +89 -89
- package/src/composables/useTimer.js +172 -172
- package/src/directives/nvdaFix.js +53 -53
- package/src/externalComps/ModuleView.vue +22 -22
- package/src/externalComps/SummaryView.vue +91 -91
- package/src/main.js +493 -476
- package/src/module/stores/appStore.js +960 -947
- package/src/module/xapi/ADL.js +520 -520
- package/src/module/xapi/Crypto/Hasher.js +241 -241
- package/src/module/xapi/Crypto/WordArray.js +278 -278
- package/src/module/xapi/Crypto/algorithms/BufferedBlockAlgorithm.js +103 -103
- package/src/module/xapi/Crypto/algorithms/C_algo.js +315 -315
- package/src/module/xapi/Crypto/algorithms/HMAC.js +9 -9
- package/src/module/xapi/Crypto/algorithms/SHA1.js +9 -9
- package/src/module/xapi/Crypto/encoders/Base.js +105 -105
- package/src/module/xapi/Crypto/encoders/Base64.js +99 -99
- package/src/module/xapi/Crypto/encoders/Hex.js +61 -61
- package/src/module/xapi/Crypto/encoders/Latin1.js +61 -61
- package/src/module/xapi/Crypto/encoders/Utf8.js +45 -45
- package/src/module/xapi/Crypto/index.js +53 -53
- package/src/module/xapi/Statement/activity.js +47 -47
- package/src/module/xapi/Statement/agent.js +55 -55
- package/src/module/xapi/Statement/group.js +26 -26
- package/src/module/xapi/Statement/index.js +259 -259
- package/src/module/xapi/Statement/statement.js +253 -253
- package/src/module/xapi/Statement/statementRef.js +23 -23
- package/src/module/xapi/Statement/substatement.js +22 -22
- package/src/module/xapi/Statement/verb.js +36 -36
- package/src/module/xapi/activitytypes.js +17 -17
- package/src/module/xapi/launch.js +157 -157
- package/src/module/xapi/utils.js +167 -167
- package/src/module/xapi/verbs.js +294 -294
- package/src/module/xapi/wrapper.js +1895 -1895
- package/src/module/xapi/xapiStatement.js +444 -444
- package/src/plugins/analytics.js +34 -34
- package/src/plugins/bus.js +12 -8
- package/src/plugins/gsap.js +17 -17
- package/src/plugins/helper.js +355 -358
- package/src/plugins/i18n.js +27 -26
- package/src/plugins/idb.js +227 -227
- package/src/plugins/save.js +37 -37
- package/src/plugins/scorm.js +287 -287
- package/src/plugins/xapi.js +11 -11
- package/src/public/index.html +33 -33
- package/src/router/index.js +57 -57
- package/src/router/routes.js +312 -312
- package/src/shared/generalfuncs.js +344 -344
- package/src/shared/validators.js +1018 -1018
- package/tests/component/AppBaseButton.spec.js +53 -0
- package/tests/component/pinia.spec.js +24 -0
- package/{src/components/tests__ → tests/unit}/AppBaseButton.spec.js +53 -53
- package/tests/unit/AppCompInputCheckBoxNx.spec.js +59 -0
- package/tests/unit/AppCompInputDropdownNx.spec.js +51 -0
- package/tests/unit/AppCompInputRadioNx.spec.js +59 -0
- package/tests/unit/AppCompInputTextNx.spec.js +44 -0
- package/tests/unit/AppCompInputTextTableNx.spec.js +77 -0
- package/tests/unit/AppCompInputTextToFillDropdownNx.spec.js +60 -0
- package/tests/unit/AppCompInputTextToFillNx.spec.js +45 -0
- package/tests/unit/AppCompQuizNext.spec.js +114 -0
- package/tests/unit/AppCompVideoPlayer.spec.js +177 -0
- package/{src/components/tests__ → tests/unit}/useTimer.spec.js +91 -91
- package/vitest.config.js +28 -19
- package/vitest.setup.js +28 -0
- package/src/components/AppBaseButton.test.js +0 -21
|
@@ -1,344 +1,344 @@
|
|
|
1
|
-
// const allfile = require.context('@/', true, /\.vue$/) //get all .vue file at the root of the project where lib will be installed
|
|
2
|
-
const allfile = import.meta.glob(['@/**/*.vue', '!@/**/_*'], {
|
|
3
|
-
eager: true
|
|
4
|
-
}) //get all .vue file at the root of the project where lib will be installed
|
|
5
|
-
|
|
6
|
-
const allfileKeys = Object.keys(allfile)
|
|
7
|
-
|
|
8
|
-
//console.log('ALL PATHS', fileArray)
|
|
9
|
-
allfileKeys.forEach(function (key, index, array) {
|
|
10
|
-
array[index] = {
|
|
11
|
-
name: key.replace('/src', '.').replace('.vue', ''),
|
|
12
|
-
fullPath: allfile[key].default.__file,
|
|
13
|
-
content: allfile[key].default
|
|
14
|
-
}
|
|
15
|
-
})
|
|
16
|
-
|
|
17
|
-
const fileAssets = {
|
|
18
|
-
// return the collection of all the files in the project directory
|
|
19
|
-
allFiles: () => allfileKeys,
|
|
20
|
-
|
|
21
|
-
// Return all the file in './views' with the Name Module
|
|
22
|
-
getViews: () => {
|
|
23
|
-
return fileAssets
|
|
24
|
-
.allFiles()
|
|
25
|
-
.filter(
|
|
26
|
-
(file) =>
|
|
27
|
-
file.name.startsWith('./views') &&
|
|
28
|
-
!file.name.split('/')[2].includes('copy')
|
|
29
|
-
)
|
|
30
|
-
},
|
|
31
|
-
// return all files that are in the folder './src/module' of the project with name respecting following condition:
|
|
32
|
-
// must start with a capital P followed by a digit (P0, P1, P2...) and not contain keyword "copy"
|
|
33
|
-
getActivities: () => {
|
|
34
|
-
return fileAssets.allFiles().filter((file) => {
|
|
35
|
-
if (
|
|
36
|
-
file.name.startsWith('./module/A') &&
|
|
37
|
-
/^P[0-9]{2,3}/.test(file.name.split('/')[3]) &&
|
|
38
|
-
!file.name.split('/')[3].includes('copy')
|
|
39
|
-
)
|
|
40
|
-
return true
|
|
41
|
-
else return false
|
|
42
|
-
})
|
|
43
|
-
},
|
|
44
|
-
|
|
45
|
-
// search a specific file and return its content
|
|
46
|
-
fetchFileContent: (file) => allfile[file].default,
|
|
47
|
-
|
|
48
|
-
/**
|
|
49
|
-
* @description Validator for the content of menu setting file
|
|
50
|
-
* @param {String} fName- name of the file for use case
|
|
51
|
-
* @param {Object} fData: file's data to validate
|
|
52
|
-
* @param {Object} [requiredArgs] list of arguments to include consider in validation ()
|
|
53
|
-
*/
|
|
54
|
-
validatefileContent: (fName, fData, requiredArgs = {}) => {
|
|
55
|
-
let err = null
|
|
56
|
-
if (import.meta.env.DEV) {
|
|
57
|
-
switch (fName) {
|
|
58
|
-
case 'menuSettings': {
|
|
59
|
-
const { keys4Activity, keys4Anchors } = requiredArgs
|
|
60
|
-
|
|
61
|
-
//*validate that data is an {Object}. if Not send error message
|
|
62
|
-
if (fData.constructor !== Object)
|
|
63
|
-
err = '💥Invalid file provided for menu settings'
|
|
64
|
-
|
|
65
|
-
if (Object.entries(fData).length > 0) {
|
|
66
|
-
const content = Object.entries(fData)
|
|
67
|
-
|
|
68
|
-
for (let el of content) {
|
|
69
|
-
// validate that the content of each entry is an object
|
|
70
|
-
if (el[1].constructor !== Object || !Object.keys(el[1]).length) {
|
|
71
|
-
err = `💥 invalid data provided for key 👉 ${el[0]} 👈 in ➡ menu.setting.js \n 🚩Must be of type {Object}`
|
|
72
|
-
break
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
// Validate that each entry has the required key
|
|
76
|
-
if (!err) {
|
|
77
|
-
for (let el of content) {
|
|
78
|
-
const entry = el[1]
|
|
79
|
-
for (let k of keys4Activity) {
|
|
80
|
-
if (!entry[k]) {
|
|
81
|
-
err = `💥 Missing 👉 ${k} 👈 in ${el[0]} in ➡ menu.setting.js \n 🚩Allowed indexes are: 👉 ${keys4Activity}`
|
|
82
|
-
break
|
|
83
|
-
} else {
|
|
84
|
-
//validate that each entry as correct value type
|
|
85
|
-
switch (k) {
|
|
86
|
-
case 'anchors':
|
|
87
|
-
if (entry[k].constructor !== Array)
|
|
88
|
-
err = `💥 Invalid anchors declaration for 👉 ${el[0]} 👈 in ➡ menu.setting.j \n 🚩Must be of type {Array}`
|
|
89
|
-
else {
|
|
90
|
-
const anchors = entry.anchors
|
|
91
|
-
|
|
92
|
-
for (let a of anchors) {
|
|
93
|
-
//trow error if numbers of keys are not the same as required
|
|
94
|
-
const a_numb = anchors.indexOf(a) + 1
|
|
95
|
-
if (Object.keys(a).length !== keys4Anchors.length) {
|
|
96
|
-
err = `💥 Invalid declaration in 👉anchor ${a_numb}👈 for ➡ ${el[0]} in ➡ menu.setting.js \n 🚩 Allowed indexes are: 👉 ${keys4Anchors}`
|
|
97
|
-
break
|
|
98
|
-
}
|
|
99
|
-
// Validated that required keys condition and type is met
|
|
100
|
-
for (let k of keys4Anchors) {
|
|
101
|
-
if (!a[k]) {
|
|
102
|
-
err = `💥 Missing 👉 ${k} 👈 for anchor ${a_numb} ➡ ${el[0]} ➡ menu.setting.js \n 🚩 Allowed indexes are: 👉 ${keys4Anchors}`
|
|
103
|
-
} else if (a[k].constructor !== String) {
|
|
104
|
-
err = `💥 Invalid 👉 ${k} 👈 declaration for anchor ${a_numb} ➡ ${el[0]} ➡ menu.setting.js \n 🚩 Must be of type {String}`
|
|
105
|
-
}
|
|
106
|
-
if (err) break
|
|
107
|
-
}
|
|
108
|
-
if (err) break
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
break
|
|
113
|
-
default:
|
|
114
|
-
if (entry[k].constructor !== String)
|
|
115
|
-
err = `Invalid 👉 ${k} 👈 declaration for ➡ ${el[0]} in ➡ menu.setting.js \n 🚩 Must be of type {String}`
|
|
116
|
-
break
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
if (err) break
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
break
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
return err
|
|
130
|
-
},
|
|
131
|
-
|
|
132
|
-
/**
|
|
133
|
-
* @description Validator for the content of menu setting file
|
|
134
|
-
* @param {String} a- array of file for use case
|
|
135
|
-
* @param {Object} [requiredArgs] list of arguments to include consider in validation ()
|
|
136
|
-
*/
|
|
137
|
-
buildMapTree: (a) => {
|
|
138
|
-
// Load files in module folder
|
|
139
|
-
|
|
140
|
-
if (a.length < 0) return
|
|
141
|
-
|
|
142
|
-
const mapTree = new Map()
|
|
143
|
-
// There is a file in the module folder
|
|
144
|
-
|
|
145
|
-
a.forEach((e) => {
|
|
146
|
-
const fileRef = e.name.replace(/(\.\/)/g, '')
|
|
147
|
-
const splitted = fileRef.split('/')
|
|
148
|
-
const activityName = splitted[1]
|
|
149
|
-
const fileName = splitted[splitted.length - 1].replace(/(\.vue)/g, '')
|
|
150
|
-
const fileContent = e.content
|
|
151
|
-
if (!Object.keys(fileContent).includes('data')) return
|
|
152
|
-
// Handling single page type
|
|
153
|
-
// adding the page in a map for the Pages
|
|
154
|
-
|
|
155
|
-
// Add the key in the map for the routes if it is not in the map, with its data as new Map;
|
|
156
|
-
if (!mapTree.get(activityName)) {
|
|
157
|
-
mapTree.set(activityName, new Map())
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
if (fileName.length === 3) {
|
|
161
|
-
mapTree.get(activityName).set(fileName, {
|
|
162
|
-
ref: fileRef,
|
|
163
|
-
content: fileContent.data(),
|
|
164
|
-
fullPath: e.fullPath
|
|
165
|
-
}) // add entry for the page
|
|
166
|
-
}
|
|
167
|
-
// Handleling Groupe page type
|
|
168
|
-
else if (fileName.length > 3 && fileName.includes('_')) {
|
|
169
|
-
const keyToFind = fileName.split('_', 1)[0] // Pxx
|
|
170
|
-
const KeyToAdd = fileName.split('_')[1] // Exx
|
|
171
|
-
|
|
172
|
-
// // search for the page key in the map
|
|
173
|
-
if (!mapTree.get(activityName).has(keyToFind)) return
|
|
174
|
-
|
|
175
|
-
// save a reference for the value of the key
|
|
176
|
-
const tempSave = mapTree.get(activityName).get(keyToFind)
|
|
177
|
-
|
|
178
|
-
// transform value of found key to a new map
|
|
179
|
-
if (!mapTree.get(activityName).get(keyToFind).size) {
|
|
180
|
-
mapTree.get(activityName).set(keyToFind, new Map())
|
|
181
|
-
// Update reference of key's
|
|
182
|
-
mapTree.get(activityName).get(keyToFind).set(keyToFind, tempSave)
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
// Add page EXX in Map if it is not already added
|
|
186
|
-
if (!mapTree.get(activityName).get(keyToFind).get(KeyToAdd))
|
|
187
|
-
mapTree.get(activityName).get(keyToFind).set(fileName, {
|
|
188
|
-
ref: fileRef,
|
|
189
|
-
content: fileContent.data(),
|
|
190
|
-
fullPath: e.fullPath
|
|
191
|
-
})
|
|
192
|
-
}
|
|
193
|
-
})
|
|
194
|
-
|
|
195
|
-
return mapTree
|
|
196
|
-
},
|
|
197
|
-
|
|
198
|
-
/**
|
|
199
|
-
* @description Capitalize word in string
|
|
200
|
-
* @param {String} a- array of file for use case
|
|
201
|
-
* @param {Object} [requiredArgs] list of arguments to include consider in validation ()
|
|
202
|
-
*/
|
|
203
|
-
capitalize: (string) => {
|
|
204
|
-
let formatted = string.replaceAll('_', ' ').toLowerCase()
|
|
205
|
-
formatted = `${formatted.substring(0, 1).toUpperCase()}${formatted.slice(1).toLowerCase()}`
|
|
206
|
-
return formatted
|
|
207
|
-
},
|
|
208
|
-
|
|
209
|
-
/**
|
|
210
|
-
* @description compares 2 array
|
|
211
|
-
* @param {Array} array1
|
|
212
|
-
* @param {Array} array2
|
|
213
|
-
* @returns {Boolean}
|
|
214
|
-
*/
|
|
215
|
-
isEqual: (array1, array2) => {
|
|
216
|
-
// if length is not equal
|
|
217
|
-
if (array1.length != array2.length) {
|
|
218
|
-
return false
|
|
219
|
-
} else {
|
|
220
|
-
// comapring each element of array
|
|
221
|
-
for (let i = 0; i < array1.length; i++) {
|
|
222
|
-
if (array1[i] != array2[i]) {
|
|
223
|
-
return false
|
|
224
|
-
}
|
|
225
|
-
}
|
|
226
|
-
return true
|
|
227
|
-
}
|
|
228
|
-
},
|
|
229
|
-
/**
|
|
230
|
-
* @description used by the dropdown quiz
|
|
231
|
-
* @param {Array} answers what the user has answered
|
|
232
|
-
* @param {Array} solution the correct choices
|
|
233
|
-
* @returns {Boolean}
|
|
234
|
-
*/
|
|
235
|
-
compareSelectedAnswers: (answers, solution) => {
|
|
236
|
-
for (let index = 0; index < answers.length; index++) {
|
|
237
|
-
const elementAnswers = answers[index]
|
|
238
|
-
const elementSolution = solution[index]
|
|
239
|
-
if (elementAnswers.reponse_id !== elementSolution) {
|
|
240
|
-
return false
|
|
241
|
-
}
|
|
242
|
-
}
|
|
243
|
-
return true
|
|
244
|
-
},
|
|
245
|
-
|
|
246
|
-
/**
|
|
247
|
-
* @description used by the texte_troue_select quiz
|
|
248
|
-
* @param {Array} answers what the user has answered
|
|
249
|
-
* @param {Array} solution the correct choices
|
|
250
|
-
* @returns {Boolean}
|
|
251
|
-
*/
|
|
252
|
-
compareSelectedTextToFillAnswers: (answers, solution) => {
|
|
253
|
-
for (let index = 0; index < answers.length; index++) {
|
|
254
|
-
const elementAnswers = answers[index]
|
|
255
|
-
const elementSolution = Object.values(solution[index])[0]
|
|
256
|
-
if (elementAnswers.reponse_id !== elementSolution) {
|
|
257
|
-
return false
|
|
258
|
-
}
|
|
259
|
-
}
|
|
260
|
-
return true
|
|
261
|
-
},
|
|
262
|
-
|
|
263
|
-
/**
|
|
264
|
-
* @description used by the texte_tableau quiz and texte_troue quiz
|
|
265
|
-
* @param {Array} answers what the user has answered
|
|
266
|
-
* @param {Array} solution the correct choices
|
|
267
|
-
* @returns {Boolean}
|
|
268
|
-
*/
|
|
269
|
-
compareTextAnswers: (answers, solution) => {
|
|
270
|
-
for (let index = 0; index < answers.length; index++) {
|
|
271
|
-
const elementAnswers = answers[index]
|
|
272
|
-
const elementSolution = solution[index]
|
|
273
|
-
if (
|
|
274
|
-
!this.$helper.containsValue(
|
|
275
|
-
elementSolution.reponse_value,
|
|
276
|
-
elementAnswers.reponse
|
|
277
|
-
)
|
|
278
|
-
) {
|
|
279
|
-
return false
|
|
280
|
-
}
|
|
281
|
-
}
|
|
282
|
-
return true
|
|
283
|
-
},
|
|
284
|
-
|
|
285
|
-
/**
|
|
286
|
-
* @description used by the texte_tableau quiz and texte_troue quiz
|
|
287
|
-
* @param {Array} answers what the user has answered
|
|
288
|
-
* @param {Array} solution the correct choices
|
|
289
|
-
* @returns {Boolean}
|
|
290
|
-
*/
|
|
291
|
-
compareTextAnswers2: (answers, solution) => {
|
|
292
|
-
for (let index = 0; index < answers.length; index++) {
|
|
293
|
-
const elementAnswers = answers[index]
|
|
294
|
-
const elementSolution = solution[index]
|
|
295
|
-
if (
|
|
296
|
-
!this.$helper.containsValue(
|
|
297
|
-
Object.values(elementSolution)[0],
|
|
298
|
-
elementAnswers.reponse
|
|
299
|
-
)
|
|
300
|
-
) {
|
|
301
|
-
return false
|
|
302
|
-
}
|
|
303
|
-
}
|
|
304
|
-
return true
|
|
305
|
-
},
|
|
306
|
-
|
|
307
|
-
/**
|
|
308
|
-
* @description used by the association quiz
|
|
309
|
-
* @param {Object} answers what the user has answered
|
|
310
|
-
* @param {Object} solution the correct choices
|
|
311
|
-
* @returns {Boolean}
|
|
312
|
-
*/
|
|
313
|
-
compareObjectAnswers: (answers, solution) => {
|
|
314
|
-
let answersKey = Object.keys(answers)
|
|
315
|
-
for (let index = 0; index < answersKey.length; index++) {
|
|
316
|
-
const elementAnswers = answers[answersKey[index]]
|
|
317
|
-
const elementSolution = solution[answersKey[index]]
|
|
318
|
-
if (elementAnswers !== elementSolution) {
|
|
319
|
-
return false
|
|
320
|
-
}
|
|
321
|
-
}
|
|
322
|
-
return true
|
|
323
|
-
},
|
|
324
|
-
|
|
325
|
-
/**
|
|
326
|
-
* @description used by the dragdrop quiz
|
|
327
|
-
* @param {Object} answers what the user has answered
|
|
328
|
-
* @param {Object} solution the correct choices
|
|
329
|
-
* @returns {Boolean}
|
|
330
|
-
*/
|
|
331
|
-
compareObjectAnswers2: (answers, solution) => {
|
|
332
|
-
let answersKey = Object.keys(answers)
|
|
333
|
-
for (let index = 0; index < answersKey.length; index++) {
|
|
334
|
-
const elementAnswers = answers[answersKey[index]]
|
|
335
|
-
const elementSolution = solution[answersKey[index]]
|
|
336
|
-
if (!this.isEqual(elementAnswers, elementSolution)) {
|
|
337
|
-
return false
|
|
338
|
-
}
|
|
339
|
-
}
|
|
340
|
-
return true
|
|
341
|
-
}
|
|
342
|
-
}
|
|
343
|
-
|
|
344
|
-
export { fileAssets }
|
|
1
|
+
// const allfile = require.context('@/', true, /\.vue$/) //get all .vue file at the root of the project where lib will be installed
|
|
2
|
+
const allfile = import.meta.glob(['@/**/*.vue', '!@/**/_*'], {
|
|
3
|
+
eager: true
|
|
4
|
+
}) //get all .vue file at the root of the project where lib will be installed
|
|
5
|
+
|
|
6
|
+
const allfileKeys = Object.keys(allfile)
|
|
7
|
+
|
|
8
|
+
//console.log('ALL PATHS', fileArray)
|
|
9
|
+
allfileKeys.forEach(function (key, index, array) {
|
|
10
|
+
array[index] = {
|
|
11
|
+
name: key.replace('/src', '.').replace('.vue', ''),
|
|
12
|
+
fullPath: allfile[key].default.__file,
|
|
13
|
+
content: allfile[key].default
|
|
14
|
+
}
|
|
15
|
+
})
|
|
16
|
+
|
|
17
|
+
const fileAssets = {
|
|
18
|
+
// return the collection of all the files in the project directory
|
|
19
|
+
allFiles: () => allfileKeys,
|
|
20
|
+
|
|
21
|
+
// Return all the file in './views' with the Name Module
|
|
22
|
+
getViews: () => {
|
|
23
|
+
return fileAssets
|
|
24
|
+
.allFiles()
|
|
25
|
+
.filter(
|
|
26
|
+
(file) =>
|
|
27
|
+
file.name.startsWith('./views') &&
|
|
28
|
+
!file.name.split('/')[2].includes('copy')
|
|
29
|
+
)
|
|
30
|
+
},
|
|
31
|
+
// return all files that are in the folder './src/module' of the project with name respecting following condition:
|
|
32
|
+
// must start with a capital P followed by a digit (P0, P1, P2...) and not contain keyword "copy"
|
|
33
|
+
getActivities: () => {
|
|
34
|
+
return fileAssets.allFiles().filter((file) => {
|
|
35
|
+
if (
|
|
36
|
+
file.name.startsWith('./module/A') &&
|
|
37
|
+
/^P[0-9]{2,3}/.test(file.name.split('/')[3]) &&
|
|
38
|
+
!file.name.split('/')[3].includes('copy')
|
|
39
|
+
)
|
|
40
|
+
return true
|
|
41
|
+
else return false
|
|
42
|
+
})
|
|
43
|
+
},
|
|
44
|
+
|
|
45
|
+
// search a specific file and return its content
|
|
46
|
+
fetchFileContent: (file) => allfile[file].default,
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* @description Validator for the content of menu setting file
|
|
50
|
+
* @param {String} fName- name of the file for use case
|
|
51
|
+
* @param {Object} fData: file's data to validate
|
|
52
|
+
* @param {Object} [requiredArgs] list of arguments to include consider in validation ()
|
|
53
|
+
*/
|
|
54
|
+
validatefileContent: (fName, fData, requiredArgs = {}) => {
|
|
55
|
+
let err = null
|
|
56
|
+
if (import.meta.env.DEV) {
|
|
57
|
+
switch (fName) {
|
|
58
|
+
case 'menuSettings': {
|
|
59
|
+
const { keys4Activity, keys4Anchors } = requiredArgs
|
|
60
|
+
|
|
61
|
+
//*validate that data is an {Object}. if Not send error message
|
|
62
|
+
if (fData.constructor !== Object)
|
|
63
|
+
err = '💥Invalid file provided for menu settings'
|
|
64
|
+
|
|
65
|
+
if (Object.entries(fData).length > 0) {
|
|
66
|
+
const content = Object.entries(fData)
|
|
67
|
+
|
|
68
|
+
for (let el of content) {
|
|
69
|
+
// validate that the content of each entry is an object
|
|
70
|
+
if (el[1].constructor !== Object || !Object.keys(el[1]).length) {
|
|
71
|
+
err = `💥 invalid data provided for key 👉 ${el[0]} 👈 in ➡ menu.setting.js \n 🚩Must be of type {Object}`
|
|
72
|
+
break
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
// Validate that each entry has the required key
|
|
76
|
+
if (!err) {
|
|
77
|
+
for (let el of content) {
|
|
78
|
+
const entry = el[1]
|
|
79
|
+
for (let k of keys4Activity) {
|
|
80
|
+
if (!entry[k]) {
|
|
81
|
+
err = `💥 Missing 👉 ${k} 👈 in ${el[0]} in ➡ menu.setting.js \n 🚩Allowed indexes are: 👉 ${keys4Activity}`
|
|
82
|
+
break
|
|
83
|
+
} else {
|
|
84
|
+
//validate that each entry as correct value type
|
|
85
|
+
switch (k) {
|
|
86
|
+
case 'anchors':
|
|
87
|
+
if (entry[k].constructor !== Array)
|
|
88
|
+
err = `💥 Invalid anchors declaration for 👉 ${el[0]} 👈 in ➡ menu.setting.j \n 🚩Must be of type {Array}`
|
|
89
|
+
else {
|
|
90
|
+
const anchors = entry.anchors
|
|
91
|
+
|
|
92
|
+
for (let a of anchors) {
|
|
93
|
+
//trow error if numbers of keys are not the same as required
|
|
94
|
+
const a_numb = anchors.indexOf(a) + 1
|
|
95
|
+
if (Object.keys(a).length !== keys4Anchors.length) {
|
|
96
|
+
err = `💥 Invalid declaration in 👉anchor ${a_numb}👈 for ➡ ${el[0]} in ➡ menu.setting.js \n 🚩 Allowed indexes are: 👉 ${keys4Anchors}`
|
|
97
|
+
break
|
|
98
|
+
}
|
|
99
|
+
// Validated that required keys condition and type is met
|
|
100
|
+
for (let k of keys4Anchors) {
|
|
101
|
+
if (!a[k]) {
|
|
102
|
+
err = `💥 Missing 👉 ${k} 👈 for anchor ${a_numb} ➡ ${el[0]} ➡ menu.setting.js \n 🚩 Allowed indexes are: 👉 ${keys4Anchors}`
|
|
103
|
+
} else if (a[k].constructor !== String) {
|
|
104
|
+
err = `💥 Invalid 👉 ${k} 👈 declaration for anchor ${a_numb} ➡ ${el[0]} ➡ menu.setting.js \n 🚩 Must be of type {String}`
|
|
105
|
+
}
|
|
106
|
+
if (err) break
|
|
107
|
+
}
|
|
108
|
+
if (err) break
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
break
|
|
113
|
+
default:
|
|
114
|
+
if (entry[k].constructor !== String)
|
|
115
|
+
err = `Invalid 👉 ${k} 👈 declaration for ➡ ${el[0]} in ➡ menu.setting.js \n 🚩 Must be of type {String}`
|
|
116
|
+
break
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
if (err) break
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
break
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
return err
|
|
130
|
+
},
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* @description Validator for the content of menu setting file
|
|
134
|
+
* @param {String} a- array of file for use case
|
|
135
|
+
* @param {Object} [requiredArgs] list of arguments to include consider in validation ()
|
|
136
|
+
*/
|
|
137
|
+
buildMapTree: (a) => {
|
|
138
|
+
// Load files in module folder
|
|
139
|
+
|
|
140
|
+
if (a.length < 0) return
|
|
141
|
+
|
|
142
|
+
const mapTree = new Map()
|
|
143
|
+
// There is a file in the module folder
|
|
144
|
+
|
|
145
|
+
a.forEach((e) => {
|
|
146
|
+
const fileRef = e.name.replace(/(\.\/)/g, '')
|
|
147
|
+
const splitted = fileRef.split('/')
|
|
148
|
+
const activityName = splitted[1]
|
|
149
|
+
const fileName = splitted[splitted.length - 1].replace(/(\.vue)/g, '')
|
|
150
|
+
const fileContent = e.content
|
|
151
|
+
if (!Object.keys(fileContent).includes('data')) return
|
|
152
|
+
// Handling single page type
|
|
153
|
+
// adding the page in a map for the Pages
|
|
154
|
+
|
|
155
|
+
// Add the key in the map for the routes if it is not in the map, with its data as new Map;
|
|
156
|
+
if (!mapTree.get(activityName)) {
|
|
157
|
+
mapTree.set(activityName, new Map())
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
if (fileName.length === 3) {
|
|
161
|
+
mapTree.get(activityName).set(fileName, {
|
|
162
|
+
ref: fileRef,
|
|
163
|
+
content: fileContent.data(),
|
|
164
|
+
fullPath: e.fullPath
|
|
165
|
+
}) // add entry for the page
|
|
166
|
+
}
|
|
167
|
+
// Handleling Groupe page type
|
|
168
|
+
else if (fileName.length > 3 && fileName.includes('_')) {
|
|
169
|
+
const keyToFind = fileName.split('_', 1)[0] // Pxx
|
|
170
|
+
const KeyToAdd = fileName.split('_')[1] // Exx
|
|
171
|
+
|
|
172
|
+
// // search for the page key in the map
|
|
173
|
+
if (!mapTree.get(activityName).has(keyToFind)) return
|
|
174
|
+
|
|
175
|
+
// save a reference for the value of the key
|
|
176
|
+
const tempSave = mapTree.get(activityName).get(keyToFind)
|
|
177
|
+
|
|
178
|
+
// transform value of found key to a new map
|
|
179
|
+
if (!mapTree.get(activityName).get(keyToFind).size) {
|
|
180
|
+
mapTree.get(activityName).set(keyToFind, new Map())
|
|
181
|
+
// Update reference of key's
|
|
182
|
+
mapTree.get(activityName).get(keyToFind).set(keyToFind, tempSave)
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
// Add page EXX in Map if it is not already added
|
|
186
|
+
if (!mapTree.get(activityName).get(keyToFind).get(KeyToAdd))
|
|
187
|
+
mapTree.get(activityName).get(keyToFind).set(fileName, {
|
|
188
|
+
ref: fileRef,
|
|
189
|
+
content: fileContent.data(),
|
|
190
|
+
fullPath: e.fullPath
|
|
191
|
+
})
|
|
192
|
+
}
|
|
193
|
+
})
|
|
194
|
+
|
|
195
|
+
return mapTree
|
|
196
|
+
},
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* @description Capitalize word in string
|
|
200
|
+
* @param {String} a- array of file for use case
|
|
201
|
+
* @param {Object} [requiredArgs] list of arguments to include consider in validation ()
|
|
202
|
+
*/
|
|
203
|
+
capitalize: (string) => {
|
|
204
|
+
let formatted = string.replaceAll('_', ' ').toLowerCase()
|
|
205
|
+
formatted = `${formatted.substring(0, 1).toUpperCase()}${formatted.slice(1).toLowerCase()}`
|
|
206
|
+
return formatted
|
|
207
|
+
},
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* @description compares 2 array
|
|
211
|
+
* @param {Array} array1
|
|
212
|
+
* @param {Array} array2
|
|
213
|
+
* @returns {Boolean}
|
|
214
|
+
*/
|
|
215
|
+
isEqual: (array1, array2) => {
|
|
216
|
+
// if length is not equal
|
|
217
|
+
if (array1.length != array2.length) {
|
|
218
|
+
return false
|
|
219
|
+
} else {
|
|
220
|
+
// comapring each element of array
|
|
221
|
+
for (let i = 0; i < array1.length; i++) {
|
|
222
|
+
if (array1[i] != array2[i]) {
|
|
223
|
+
return false
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
return true
|
|
227
|
+
}
|
|
228
|
+
},
|
|
229
|
+
/**
|
|
230
|
+
* @description used by the dropdown quiz
|
|
231
|
+
* @param {Array} answers what the user has answered
|
|
232
|
+
* @param {Array} solution the correct choices
|
|
233
|
+
* @returns {Boolean}
|
|
234
|
+
*/
|
|
235
|
+
compareSelectedAnswers: (answers, solution) => {
|
|
236
|
+
for (let index = 0; index < answers.length; index++) {
|
|
237
|
+
const elementAnswers = answers[index]
|
|
238
|
+
const elementSolution = solution[index]
|
|
239
|
+
if (elementAnswers.reponse_id !== elementSolution) {
|
|
240
|
+
return false
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
return true
|
|
244
|
+
},
|
|
245
|
+
|
|
246
|
+
/**
|
|
247
|
+
* @description used by the texte_troue_select quiz
|
|
248
|
+
* @param {Array} answers what the user has answered
|
|
249
|
+
* @param {Array} solution the correct choices
|
|
250
|
+
* @returns {Boolean}
|
|
251
|
+
*/
|
|
252
|
+
compareSelectedTextToFillAnswers: (answers, solution) => {
|
|
253
|
+
for (let index = 0; index < answers.length; index++) {
|
|
254
|
+
const elementAnswers = answers[index]
|
|
255
|
+
const elementSolution = Object.values(solution[index])[0]
|
|
256
|
+
if (elementAnswers.reponse_id !== elementSolution) {
|
|
257
|
+
return false
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
return true
|
|
261
|
+
},
|
|
262
|
+
|
|
263
|
+
/**
|
|
264
|
+
* @description used by the texte_tableau quiz and texte_troue quiz
|
|
265
|
+
* @param {Array} answers what the user has answered
|
|
266
|
+
* @param {Array} solution the correct choices
|
|
267
|
+
* @returns {Boolean}
|
|
268
|
+
*/
|
|
269
|
+
compareTextAnswers: (answers, solution) => {
|
|
270
|
+
for (let index = 0; index < answers.length; index++) {
|
|
271
|
+
const elementAnswers = answers[index]
|
|
272
|
+
const elementSolution = solution[index]
|
|
273
|
+
if (
|
|
274
|
+
!this.$helper.containsValue(
|
|
275
|
+
elementSolution.reponse_value,
|
|
276
|
+
elementAnswers.reponse
|
|
277
|
+
)
|
|
278
|
+
) {
|
|
279
|
+
return false
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
return true
|
|
283
|
+
},
|
|
284
|
+
|
|
285
|
+
/**
|
|
286
|
+
* @description used by the texte_tableau quiz and texte_troue quiz
|
|
287
|
+
* @param {Array} answers what the user has answered
|
|
288
|
+
* @param {Array} solution the correct choices
|
|
289
|
+
* @returns {Boolean}
|
|
290
|
+
*/
|
|
291
|
+
compareTextAnswers2: (answers, solution) => {
|
|
292
|
+
for (let index = 0; index < answers.length; index++) {
|
|
293
|
+
const elementAnswers = answers[index]
|
|
294
|
+
const elementSolution = solution[index]
|
|
295
|
+
if (
|
|
296
|
+
!this.$helper.containsValue(
|
|
297
|
+
Object.values(elementSolution)[0],
|
|
298
|
+
elementAnswers.reponse
|
|
299
|
+
)
|
|
300
|
+
) {
|
|
301
|
+
return false
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
return true
|
|
305
|
+
},
|
|
306
|
+
|
|
307
|
+
/**
|
|
308
|
+
* @description used by the association quiz
|
|
309
|
+
* @param {Object} answers what the user has answered
|
|
310
|
+
* @param {Object} solution the correct choices
|
|
311
|
+
* @returns {Boolean}
|
|
312
|
+
*/
|
|
313
|
+
compareObjectAnswers: (answers, solution) => {
|
|
314
|
+
let answersKey = Object.keys(answers)
|
|
315
|
+
for (let index = 0; index < answersKey.length; index++) {
|
|
316
|
+
const elementAnswers = answers[answersKey[index]]
|
|
317
|
+
const elementSolution = solution[answersKey[index]]
|
|
318
|
+
if (elementAnswers !== elementSolution) {
|
|
319
|
+
return false
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
return true
|
|
323
|
+
},
|
|
324
|
+
|
|
325
|
+
/**
|
|
326
|
+
* @description used by the dragdrop quiz
|
|
327
|
+
* @param {Object} answers what the user has answered
|
|
328
|
+
* @param {Object} solution the correct choices
|
|
329
|
+
* @returns {Boolean}
|
|
330
|
+
*/
|
|
331
|
+
compareObjectAnswers2: (answers, solution) => {
|
|
332
|
+
let answersKey = Object.keys(answers)
|
|
333
|
+
for (let index = 0; index < answersKey.length; index++) {
|
|
334
|
+
const elementAnswers = answers[answersKey[index]]
|
|
335
|
+
const elementSolution = solution[answersKey[index]]
|
|
336
|
+
if (!this.isEqual(elementAnswers, elementSolution)) {
|
|
337
|
+
return false
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
return true
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
export { fileAssets }
|