fcad-core-dragon 2.0.0-beta.3 → 2.0.0-beta.4

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 (95) hide show
  1. package/.editorconfig +33 -33
  2. package/.eslintignore +29 -29
  3. package/.eslintrc.cjs +81 -81
  4. package/CHANGELOG +373 -364
  5. package/README.md +71 -71
  6. package/bk.scss +117 -117
  7. package/package.json +61 -61
  8. package/src/$locales/en.json +143 -143
  9. package/src/$locales/fr.json +105 -105
  10. package/src/assets/data/onboardingMessages.json +47 -47
  11. package/src/components/AppBase.vue +1147 -1054
  12. package/src/components/AppBaseButton.vue +87 -87
  13. package/src/components/AppBaseErrorDisplay.vue +438 -438
  14. package/src/components/AppBaseFlipCard.vue +84 -84
  15. package/src/components/AppBaseModule.vue +1636 -1673
  16. package/src/components/AppBasePage.vue +779 -779
  17. package/src/components/AppBasePopover.vue +41 -41
  18. package/src/components/AppCompAudio.vue +234 -234
  19. package/src/components/AppCompBranchButtons.vue +552 -552
  20. package/src/components/AppCompButtonProgress.vue +126 -126
  21. package/src/components/AppCompCarousel.vue +298 -298
  22. package/src/components/AppCompInputCheckBoxNext.vue +195 -195
  23. package/src/components/AppCompInputDropdownNext.vue +159 -159
  24. package/src/components/AppCompInputRadioNext.vue +152 -152
  25. package/src/components/AppCompInputTextNext.vue +106 -106
  26. package/src/components/AppCompInputTextTableNext.vue +141 -141
  27. package/src/components/AppCompInputTextToFillDropdownNext.vue +230 -230
  28. package/src/components/AppCompInputTextToFillNext.vue +171 -171
  29. package/src/components/AppCompJauge.vue +74 -74
  30. package/src/components/AppCompMenu.vue +423 -413
  31. package/src/components/AppCompMenuItem.vue +228 -228
  32. package/src/components/AppCompNavigation.vue +959 -960
  33. package/src/components/AppCompNoteCall.vue +133 -133
  34. package/src/components/AppCompNoteCredit.vue +292 -292
  35. package/src/components/AppCompPlayBar.vue +1218 -1218
  36. package/src/components/AppCompPlayBarNext.vue +2052 -2052
  37. package/src/components/AppCompPlayBarProgress.vue +82 -82
  38. package/src/components/AppCompPopUpNext.vue +503 -503
  39. package/src/components/AppCompQuizNext.vue +2904 -2904
  40. package/src/components/AppCompQuizRecall.vue +276 -276
  41. package/src/components/AppCompSVGNext.vue +347 -347
  42. package/src/components/AppCompSettingsMenu.vue +172 -172
  43. package/src/components/AppCompTableOfContent.vue +387 -387
  44. package/src/components/AppCompTranscript.vue +24 -24
  45. package/src/components/AppCompVideoPlayer.vue +368 -368
  46. package/src/components/AppCompViewDisplay.vue +6 -6
  47. package/src/components/BaseModule.vue +72 -72
  48. package/src/composables/useQuiz.js +206 -206
  49. package/src/externalComps/ModuleView.vue +22 -22
  50. package/src/externalComps/SummaryView.vue +91 -91
  51. package/src/main.js +272 -272
  52. package/src/mixins/$mediaMixins.js +819 -819
  53. package/src/mixins/timerMixin.js +155 -155
  54. package/src/module/stores/appStore.js +901 -893
  55. package/src/module/xapi/ADL.js +380 -376
  56. package/src/module/xapi/Crypto/Hasher.js +241 -241
  57. package/src/module/xapi/Crypto/WordArray.js +278 -278
  58. package/src/module/xapi/Crypto/algorithms/BufferedBlockAlgorithm.js +103 -103
  59. package/src/module/xapi/Crypto/algorithms/C_algo.js +315 -315
  60. package/src/module/xapi/Crypto/algorithms/HMAC.js +9 -9
  61. package/src/module/xapi/Crypto/algorithms/SHA1.js +9 -9
  62. package/src/module/xapi/Crypto/encoders/Base.js +105 -105
  63. package/src/module/xapi/Crypto/encoders/Base64.js +99 -99
  64. package/src/module/xapi/Crypto/encoders/Hex.js +61 -61
  65. package/src/module/xapi/Crypto/encoders/Latin1.js +61 -61
  66. package/src/module/xapi/Crypto/encoders/Utf8.js +45 -45
  67. package/src/module/xapi/Crypto/index.js +53 -53
  68. package/src/module/xapi/Statement/activity.js +47 -47
  69. package/src/module/xapi/Statement/agent.js +55 -55
  70. package/src/module/xapi/Statement/group.js +26 -26
  71. package/src/module/xapi/Statement/index.js +259 -259
  72. package/src/module/xapi/Statement/statement.js +253 -253
  73. package/src/module/xapi/Statement/statementRef.js +23 -23
  74. package/src/module/xapi/Statement/substatement.js +22 -22
  75. package/src/module/xapi/Statement/verb.js +36 -36
  76. package/src/module/xapi/activitytypes.js +17 -17
  77. package/src/module/xapi/launch.js +157 -157
  78. package/src/module/xapi/utils.js +167 -167
  79. package/src/module/xapi/verbs.js +294 -294
  80. package/src/module/xapi/wrapper.js +1963 -1963
  81. package/src/module/xapi/xapiStatement.js +444 -444
  82. package/src/plugins/bus.js +8 -8
  83. package/src/plugins/gsap.js +14 -14
  84. package/src/plugins/helper.js +314 -308
  85. package/src/plugins/i18n.js +44 -44
  86. package/src/plugins/idb.js +227 -219
  87. package/src/plugins/save.js +37 -37
  88. package/src/plugins/scorm.js +287 -287
  89. package/src/plugins/xapi.js +11 -11
  90. package/src/public/index.html +33 -33
  91. package/src/router/index.js +43 -43
  92. package/src/router/routes.js +312 -312
  93. package/src/shared/generalfuncs.js +210 -210
  94. package/src/shared/validators.js +1069 -1069
  95. package/vite.config.js +0 -27
@@ -1,308 +1,314 @@
1
- import routes from '../router/routes'
2
- import { useAppStore } from '../module/stores/appStore'
3
- import { name as fcadName, version as fcadVersion } from '../../package.json'
4
-
5
- import axios from 'axios'
6
-
7
- import locale_en from '../$locales/en.json'
8
- import locale_fr from '../$locales/fr.json'
9
-
10
- export default function helper(app, name) {
11
- Object.defineProperty(app.config.globalProperties, name, {
12
- value: {
13
- /***
14
- * @description: helper to get the collection of routes of activies from vue-Router.
15
- * @note If need more info from the router , use directly the vue-router
16
- * @param {String} ID [optional] - ID of an activity (ex: A01).
17
- * @return {Array} - return all routes for an activity Or all the routes of the module
18
- *
19
- */
20
- getRoutesFromVueRouter: (ID) => {
21
- //let all_routes
22
- //const appStore = useAppStore()
23
- //const routes = appStore.$state.allModuleRoutes
24
- //let { children: all_routes, meta } = routes[0]
25
- let { children: all_routes, meta } = routes[1].children[0]
26
-
27
- if (ID) {
28
- let f = all_routes.find((route) => route.meta.id === ID)
29
- if (f) {
30
- all_routes = f.children
31
- meta = f.meta
32
- }
33
- }
34
- return { all_routes, meta }
35
- },
36
- /** @description: helper to get the build timestamp. Useful for QA
37
- *
38
- */
39
- getBuildTime() {
40
- return document.documentElement.dataset.buildTime
41
- },
42
- /**
43
- * @description: helper to get the FCAD version full string. Useful for QA
44
- *
45
- */
46
- getFcadVersionString() {
47
- return `${fcadName} v${fcadVersion}`
48
- },
49
- /** @description: helper to get the FCAD version number. Useful for QA
50
- *
51
- */
52
- getFcadVersion() {
53
- return `${fcadVersion}`
54
- },
55
-
56
- /**
57
- * @description: helper to get App setting information from the store.
58
- * @param {String} sName - a key of specific value from the settings
59
- * ex: 'specification' to return the specification of the app: xapi |scorm
60
- * @return {Object|null} -
61
- */
62
- getSettingsFromStore(sName = null) {
63
- const store = useAppStore()
64
- if (
65
- !store.$state.appConfigs ||
66
- store.$state.appConfigs[sName] == undefined
67
- )
68
- return null
69
-
70
- if (sName) return store.$state.appConfigs[sName]
71
- else return store.$state.appConfigs
72
- },
73
-
74
- /**
75
- * @description: helper to get the menu information from the store.
76
- *
77
- */
78
- getMenuInfoFromStore() {
79
- const store = useAppStore()
80
- if (store.$state.menuSetting) return store.$state.menuSetting
81
- else return null
82
- },
83
- /***
84
- * @description Method to return a myme time of a document
85
- * @param {String} aType extension of the document exemple: doc , pdf ect...
86
- * @return {String} mime
87
- */
88
- mimeTypeFor(aType) {
89
- let mimeType = false
90
- switch (aType) {
91
- case 'doc':
92
- mimeType = 'application/msword'
93
- break
94
-
95
- case 'docx':
96
- mimeType =
97
- 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'
98
- break
99
-
100
- case 'pdf':
101
- mimeType = 'application/pdf'
102
- break
103
-
104
- case 'txt':
105
- mimeType = 'text/plain'
106
- break
107
-
108
- case 'jpeg' || 'jpg':
109
- mimeType = 'image/jpeg'
110
- break
111
-
112
- case 'png':
113
- mimeType = 'image/png'
114
- break
115
- }
116
- return mimeType
117
- },
118
- /***
119
- * @description method to download a file.
120
- * @param {String} filePath url of the file to download
121
- * @param {String} outputName 'the default name for the download file'
122
- * @summary Use axios to simulate a file request from server.
123
- * Create <a> tag with downloadable link and download the element to user PC.
124
- * Remove a element after download
125
- * @usage:
126
- * - case 1: the file is in the public folder of your project. Use full path ex: downloadFile('./public/
127
- * myfile')
128
- * - case 2: file is in another folder in a src of your project. Use relative path. File is handle as webpack
129
- * module requirement with method require(). ex: downloadFile(require('@/accets/another_folder/** myfile'))
130
- *
131
- */
132
- async downloadFile(filepath, outputName) {
133
- try {
134
- if (filepath && filepath.constructor === String) {
135
- const res = await axios.get(filepath, { responseType: 'blob' }) // use http request
136
-
137
- const blob = new Blob([res.data], {
138
- type: res.data.type
139
- }) // create a blob element
140
-
141
- const alink = document.createElement('a') //create a element
142
-
143
- alink.href = URL.createObjectURL(blob) //create url reference for the object
144
- alink.download = outputName || `myFile` // set download name
145
- alink.click() //symulate click event to download the object
146
-
147
- URL.revokeObjectURL(alink.href) //release the url referrence of the object
148
- } else throw new Error('No URL provided for download')
149
- } catch (err) {
150
- // plugin has access to $bus through the Vue.proptotype
151
- const msg = this.getKeyFromLocal('message.err_download_file')
152
-
153
- app.config.globalProperties.$bus.$emit('open-popup', {
154
- type: 'popup-info',
155
- value: { text_1: `⚠️ ${msg}` }
156
- })
157
- console.error('DOWNLOAD ERROR: 💥', err)
158
- }
159
- },
160
- /***
161
- * @description - helper methode to retrive a word from a local file.
162
- * @param {String} key - key of the word to retrive ex: 'a.b.c'
163
- * @return {String } - return the value of the key ex: 'hello world' if exist or the key ('a.b.c')
164
- */
165
- getKeyFromLocal(key) {
166
- if (!key) throw new Error('Missing Key for search')
167
- const store = useAppStore()
168
- const lang = store.state.appConfigs.lang // get lang from the store
169
- const dic = { en: locale_en, fr: locale_fr } //contents of the json locales
170
- const keys = key.split('.')
171
-
172
- let value
173
- for (let i = 0; i < keys.length; i++) {
174
- let n = keys[i]
175
- if (i === 0 && dic[lang][n]) value = dic[lang][n]
176
- else if (value[n]) value = value[n]
177
- else return (value = key)
178
- }
179
-
180
- return value
181
- },
182
-
183
- /***
184
- * @description: Insert line break opportunities into a URL
185
- * @param {String} url - original url string to formate
186
- * @credit - https://css-tricks.com/better-line-breaks-for-long-urls/
187
- */
188
- breakUrlString(url) {
189
- // Split the URL into an array to distinguish double slashes from single slashes
190
- const doubleSlash = url.split('//')
191
-
192
- // Format the strings on either side of double slashes separately
193
- let formatted = doubleSlash
194
- .map(
195
- (str) =>
196
- // Insert a word break opportunity after a colon
197
- str
198
- .replace(/(?<after>:)/giu, '$1<wbr>')
199
- // Before a single slash, tilde, period, comma, hyphen, underline, question mark, number sign, or percent symbol
200
- .replace(/(?<before>[/~.,\-_?#%])/giu, '<wbr>$1')
201
- // Before and after an equals sign or ampersand
202
- .replace(/(?<beforeAndAfter>[=&])/giu, '<wbr>$1<wbr>')
203
- // Reconnect the strings with word break opportunities after double slashes
204
- )
205
- .join('//<wbr>')
206
-
207
- return formatted
208
- },
209
- /***
210
- * @description: Creates the right url and id for the next lesson, depending on the environment (projets/campus)
211
- * Works with full url (ex: https://projets...) or a partial url (ex: 109-101-MQ-60-TP/M1Intro/index.php) set in app.
212
- * When working locally, uses the projets.cegepadistance.ca environment
213
- * @param {Object} linkedResource - Setting from app.settings.js
214
- * @return {Object} - linkedResource object with the right url and id values according to current environment
215
- */
216
- getNextLessonEnv(linkedResource) {
217
- let courseLocation, host, courseId
218
- /**ID*/
219
- if (linkedResource.id.startsWith('http')) {
220
- courseId = linkedResource.id.split('lrs-xapi/')[1]
221
- } else {
222
- courseId = linkedResource.id
223
- if (courseId.startsWith('/')) {
224
- courseId = courseId.substring(1)
225
- }
226
- }
227
-
228
- /**URL*/
229
- //If the value is a complete url, split and keep the end only ex: 109-101-MQ-60-TP/M1Intro/index.php
230
- if (linkedResource.url.startsWith('http')) {
231
- courseLocation = linkedResource.url.split('lrs-xapi/')[1]
232
- } else {
233
- courseLocation = linkedResource.url
234
- if (courseLocation.startsWith('/')) {
235
- courseLocation = courseLocation.substring(1)
236
- }
237
- }
238
-
239
- host = import.meta.env.PROD
240
- ? window.location.host
241
- : 'projets.cegepadistance.ca'
242
-
243
- linkedResource.id = `https://${host}/lrs-xapi/${courseId}`
244
- linkedResource.url = `https://${host}/lrs-xapi/${courseLocation}`
245
-
246
- return linkedResource
247
- },
248
-
249
- //Method to get let last activity
250
- getlastItemInMap(map) {
251
- return [...map][map.size - 1]
252
- },
253
-
254
- /***
255
- * Method to format Time to ISOS String
256
- * @param {String} T - time Iso Time
257
- * @return {String} - time PT Format
258
- */
259
-
260
- formatToISOSTime(t) {
261
- if (!t) return
262
- let regex = new RegExp(':', 'gm')
263
- let T = !regex.test(t) ? this.formatTime(t) : t
264
-
265
- // let timeStr = `PT${t}S`
266
-
267
- let timeStr =
268
- T.match(regex).length > 1
269
- ? `PT${T.split(':')[0]}H${T.split(':')[1]}M${T.split(':')[2]}S`
270
- : `PT00H${T.split(':')[0]}M${T.split(':')[1]}S`
271
-
272
- return timeStr
273
- },
274
- /***
275
- * Method to format Time to ISOS String
276
- * @param {String} T - time Iso Time
277
- * @return {String} - time PT Format
278
- */
279
- formatTime(time) {
280
- let returnStr = ``
281
- // format a time from second to 00:00:00
282
- const option = { minimumIntegerDigits: 2, useGrouping: false }
283
- const minutes = Math.floor(time / 60).toLocaleString('en-US', option)
284
- const seconds = Math.floor(time - minutes * 60).toLocaleString(
285
- 'en-US',
286
- option
287
- )
288
- const hours = Math.floor(time / 3600).toLocaleString('en-US', option)
289
- if (hours == '00') {
290
- returnStr = `${minutes}:${seconds}`
291
- } else {
292
- returnStr = `${hours}:${minutes}:${seconds}`
293
- }
294
- return returnStr
295
- }, // END formatTime
296
-
297
- /**
298
- * @description check if a values exists in a array
299
- * @param {Array} array
300
- * @param value
301
- * @returns {Boolean}
302
- */
303
- containsValue(array, value) {
304
- return array.includes(value)
305
- }
306
- }
307
- })
308
- }
1
+ import routes from '../router/routes'
2
+ import { useAppStore } from '../module/stores/appStore'
3
+ import { name as fcadName, version as fcadVersion } from '../../package.json'
4
+
5
+ import axios from 'axios'
6
+
7
+ import locale_en from '../$locales/en.json'
8
+ import locale_fr from '../$locales/fr.json'
9
+
10
+ export default function helper(app, name) {
11
+ Object.defineProperty(app.config.globalProperties, name, {
12
+ value: {
13
+ /***
14
+ * @description: helper to get the collection of routes of activies from vue-Router.
15
+ * @note If need more info from the router , use directly the vue-router
16
+ * @param {String} ID [optional] - ID of an activity (ex: A01).
17
+ * @return {Array} - return all routes for an activity Or all the routes of the module
18
+ *
19
+ */
20
+ getRoutesFromVueRouter: (ID) => {
21
+ //let all_routes
22
+ //const appStore = useAppStore()
23
+ //const routes = appStore.$state.allModuleRoutes
24
+ //let { children: all_routes, meta } = routes[0]
25
+ let { children: all_routes, meta } = routes[1].children[0]
26
+
27
+ if (ID) {
28
+ let f = all_routes.find((route) => route.meta.id === ID)
29
+ if (f) {
30
+ all_routes = f.children
31
+ meta = f.meta
32
+ }
33
+ }
34
+ return { all_routes, meta }
35
+ },
36
+ /** @description: helper to get the build timestamp. Useful for QA
37
+ *
38
+ */
39
+ getBuildTime() {
40
+ return document.documentElement.dataset.buildTime
41
+ },
42
+ /** @description: helper to get the template version used by projgen to create this project. Useful for QA
43
+ *
44
+ */
45
+ getTemplateVersion() {
46
+ return document.documentElement.dataset.templateVersion
47
+ },
48
+ /**
49
+ * @description: helper to get the FCAD version full string. Useful for QA
50
+ *
51
+ */
52
+ getFcadVersionString() {
53
+ return `[${fcadName} v${fcadVersion}] [fcad-template v${this.getTemplateVersion()}] [build ${this.getBuildTime()}]`
54
+ },
55
+ /** @description: helper to get the FCAD version number. Useful for QA
56
+ *
57
+ */
58
+ getFcadVersion() {
59
+ return `${fcadVersion}`
60
+ },
61
+
62
+ /**
63
+ * @description: helper to get App setting information from the store.
64
+ * @param {String} sName - a key of specific value from the settings
65
+ * ex: 'specification' to return the specification of the app: xapi |scorm
66
+ * @return {Object|null} -
67
+ */
68
+ getSettingsFromStore(sName = null) {
69
+ const store = useAppStore()
70
+ if (
71
+ !store.$state.appConfigs ||
72
+ store.$state.appConfigs[sName] == undefined
73
+ )
74
+ return null
75
+
76
+ if (sName) return store.$state.appConfigs[sName]
77
+ else return store.$state.appConfigs
78
+ },
79
+
80
+ /**
81
+ * @description: helper to get the menu information from the store.
82
+ *
83
+ */
84
+ getMenuInfoFromStore() {
85
+ const store = useAppStore()
86
+ if (store.$state.menuSetting) return store.$state.menuSetting
87
+ else return null
88
+ },
89
+ /***
90
+ * @description Method to return a myme time of a document
91
+ * @param {String} aType extension of the document exemple: doc , pdf ect...
92
+ * @return {String} mime
93
+ */
94
+ mimeTypeFor(aType) {
95
+ let mimeType = false
96
+ switch (aType) {
97
+ case 'doc':
98
+ mimeType = 'application/msword'
99
+ break
100
+
101
+ case 'docx':
102
+ mimeType =
103
+ 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'
104
+ break
105
+
106
+ case 'pdf':
107
+ mimeType = 'application/pdf'
108
+ break
109
+
110
+ case 'txt':
111
+ mimeType = 'text/plain'
112
+ break
113
+
114
+ case 'jpeg' || 'jpg':
115
+ mimeType = 'image/jpeg'
116
+ break
117
+
118
+ case 'png':
119
+ mimeType = 'image/png'
120
+ break
121
+ }
122
+ return mimeType
123
+ },
124
+ /***
125
+ * @description method to download a file.
126
+ * @param {String} filePath url of the file to download
127
+ * @param {String} outputName 'the default name for the download file'
128
+ * @summary Use axios to simulate a file request from server.
129
+ * Create <a> tag with downloadable link and download the element to user PC.
130
+ * Remove a element after download
131
+ * @usage:
132
+ * - case 1: the file is in the public folder of your project. Use full path ex: downloadFile('./public/
133
+ * myfile')
134
+ * - case 2: file is in another folder in a src of your project. Use relative path. File is handle as webpack
135
+ * module requirement with method require(). ex: downloadFile(require('@/accets/another_folder/** myfile'))
136
+ *
137
+ */
138
+ async downloadFile(filepath, outputName) {
139
+ try {
140
+ if (filepath && filepath.constructor === String) {
141
+ const res = await axios.get(filepath, { responseType: 'blob' }) // use http request
142
+
143
+ const blob = new Blob([res.data], {
144
+ type: res.data.type
145
+ }) // create a blob element
146
+
147
+ const alink = document.createElement('a') //create a element
148
+
149
+ alink.href = URL.createObjectURL(blob) //create url reference for the object
150
+ alink.download = outputName || `myFile` // set download name
151
+ alink.click() //symulate click event to download the object
152
+
153
+ URL.revokeObjectURL(alink.href) //release the url referrence of the object
154
+ } else throw new Error('No URL provided for download')
155
+ } catch (err) {
156
+ // plugin has access to $bus through the Vue.proptotype
157
+ const msg = this.getKeyFromLocal('message.err_download_file')
158
+
159
+ app.config.globalProperties.$bus.$emit('open-popup', {
160
+ type: 'popup-info',
161
+ value: { text_1: `⚠️ ${msg}` }
162
+ })
163
+ console.error('DOWNLOAD ERROR: 💥', err)
164
+ }
165
+ },
166
+ /***
167
+ * @description - helper methode to retrive a word from a local file.
168
+ * @param {String} key - key of the word to retrive ex: 'a.b.c'
169
+ * @return {String } - return the value of the key ex: 'hello world' if exist or the key ('a.b.c')
170
+ */
171
+ getKeyFromLocal(key) {
172
+ if (!key) throw new Error('Missing Key for search')
173
+ const store = useAppStore()
174
+ const lang = store.state.appConfigs.lang // get lang from the store
175
+ const dic = { en: locale_en, fr: locale_fr } //contents of the json locales
176
+ const keys = key.split('.')
177
+
178
+ let value
179
+ for (let i = 0; i < keys.length; i++) {
180
+ let n = keys[i]
181
+ if (i === 0 && dic[lang][n]) value = dic[lang][n]
182
+ else if (value[n]) value = value[n]
183
+ else return (value = key)
184
+ }
185
+
186
+ return value
187
+ },
188
+
189
+ /***
190
+ * @description: Insert line break opportunities into a URL
191
+ * @param {String} url - original url string to formate
192
+ * @credit - https://css-tricks.com/better-line-breaks-for-long-urls/
193
+ */
194
+ breakUrlString(url) {
195
+ // Split the URL into an array to distinguish double slashes from single slashes
196
+ const doubleSlash = url.split('//')
197
+
198
+ // Format the strings on either side of double slashes separately
199
+ let formatted = doubleSlash
200
+ .map(
201
+ (str) =>
202
+ // Insert a word break opportunity after a colon
203
+ str
204
+ .replace(/(?<after>:)/giu, '$1<wbr>')
205
+ // Before a single slash, tilde, period, comma, hyphen, underline, question mark, number sign, or percent symbol
206
+ .replace(/(?<before>[/~.,\-_?#%])/giu, '<wbr>$1')
207
+ // Before and after an equals sign or ampersand
208
+ .replace(/(?<beforeAndAfter>[=&])/giu, '<wbr>$1<wbr>')
209
+ // Reconnect the strings with word break opportunities after double slashes
210
+ )
211
+ .join('//<wbr>')
212
+
213
+ return formatted
214
+ },
215
+ /***
216
+ * @description: Creates the right url and id for the next lesson, depending on the environment (projets/campus)
217
+ * Works with full url (ex: https://projets...) or a partial url (ex: 109-101-MQ-60-TP/M1Intro/index.php) set in app.
218
+ * When working locally, uses the projets.cegepadistance.ca environment
219
+ * @param {Object} linkedResource - Setting from app.settings.js
220
+ * @return {Object} - linkedResource object with the right url and id values according to current environment
221
+ */
222
+ getNextLessonEnv(linkedResource) {
223
+ let courseLocation, host, courseId
224
+ /**ID*/
225
+ if (linkedResource.id.startsWith('http')) {
226
+ courseId = linkedResource.id.split('lrs-xapi/')[1]
227
+ } else {
228
+ courseId = linkedResource.id
229
+ if (courseId.startsWith('/')) {
230
+ courseId = courseId.substring(1)
231
+ }
232
+ }
233
+
234
+ /**URL*/
235
+ //If the value is a complete url, split and keep the end only ex: 109-101-MQ-60-TP/M1Intro/index.php
236
+ if (linkedResource.url.startsWith('http')) {
237
+ courseLocation = linkedResource.url.split('lrs-xapi/')[1]
238
+ } else {
239
+ courseLocation = linkedResource.url
240
+ if (courseLocation.startsWith('/')) {
241
+ courseLocation = courseLocation.substring(1)
242
+ }
243
+ }
244
+
245
+ host = import.meta.env.PROD
246
+ ? window.location.host
247
+ : 'projets.cegepadistance.ca'
248
+
249
+ linkedResource.id = `https://${host}/lrs-xapi/${courseId}`
250
+ linkedResource.url = `https://${host}/lrs-xapi/${courseLocation}`
251
+
252
+ return linkedResource
253
+ },
254
+
255
+ //Method to get let last activity
256
+ getlastItemInMap(map) {
257
+ return [...map][map.size - 1]
258
+ },
259
+
260
+ /***
261
+ * Method to format Time to ISOS String
262
+ * @param {String} T - time Iso Time
263
+ * @return {String} - time PT Format
264
+ */
265
+
266
+ formatToISOSTime(t) {
267
+ if (!t) return
268
+ let regex = new RegExp(':', 'gm')
269
+ let T = !regex.test(t) ? this.formatTime(t) : t
270
+
271
+ // let timeStr = `PT${t}S`
272
+
273
+ let timeStr =
274
+ T.match(regex).length > 1
275
+ ? `PT${T.split(':')[0]}H${T.split(':')[1]}M${T.split(':')[2]}S`
276
+ : `PT00H${T.split(':')[0]}M${T.split(':')[1]}S`
277
+
278
+ return timeStr
279
+ },
280
+ /***
281
+ * Method to format Time to ISOS String
282
+ * @param {String} T - time Iso Time
283
+ * @return {String} - time PT Format
284
+ */
285
+ formatTime(time) {
286
+ let returnStr = ``
287
+ // format a time from second to 00:00:00
288
+ const option = { minimumIntegerDigits: 2, useGrouping: false }
289
+ const minutes = Math.floor(time / 60).toLocaleString('en-US', option)
290
+ const seconds = Math.floor(time - minutes * 60).toLocaleString(
291
+ 'en-US',
292
+ option
293
+ )
294
+ const hours = Math.floor(time / 3600).toLocaleString('en-US', option)
295
+ if (hours == '00') {
296
+ returnStr = `${minutes}:${seconds}`
297
+ } else {
298
+ returnStr = `${hours}:${minutes}:${seconds}`
299
+ }
300
+ return returnStr
301
+ }, // END formatTime
302
+
303
+ /**
304
+ * @description check if a values exists in a array
305
+ * @param {Array} array
306
+ * @param value
307
+ * @returns {Boolean}
308
+ */
309
+ containsValue(array, value) {
310
+ return array.includes(value)
311
+ }
312
+ }
313
+ })
314
+ }