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

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