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,17 +1,17 @@
|
|
|
1
|
-
export default {
|
|
2
|
-
assessment: 'http://adlnet.gov/expapi/activities/assessment',
|
|
3
|
-
attempt: 'http://adlnet.gov/expapi/activities/attempt',
|
|
4
|
-
course: 'http://adlnet.gov/expapi/activities/course',
|
|
5
|
-
file: 'http://adlnet.gov/expapi/activities/file',
|
|
6
|
-
interaction: 'http://adlnet.gov/expapi/activities/interaction',
|
|
7
|
-
lesson: 'http://adlnet.gov/expapi/activities/lesson',
|
|
8
|
-
link: 'http://adlnet.gov/expapi/activities/link',
|
|
9
|
-
media: 'http://adlnet.gov/expapi/activities/media',
|
|
10
|
-
meeting: 'http://adlnet.gov/expapi/activities/meeting',
|
|
11
|
-
module: 'http://adlnet.gov/expapi/activities/module',
|
|
12
|
-
objective: 'http://adlnet.gov/expapi/activities/objective',
|
|
13
|
-
performance: 'http://adlnet.gov/expapi/activities/performance',
|
|
14
|
-
profile: 'http://adlnet.gov/expapi/activities/profile',
|
|
15
|
-
question: 'http://adlnet.gov/expapi/activities/question',
|
|
16
|
-
simulation: 'http://adlnet.gov/expapi/activities/simulation'
|
|
17
|
-
}
|
|
1
|
+
export default {
|
|
2
|
+
assessment: 'http://adlnet.gov/expapi/activities/assessment',
|
|
3
|
+
attempt: 'http://adlnet.gov/expapi/activities/attempt',
|
|
4
|
+
course: 'http://adlnet.gov/expapi/activities/course',
|
|
5
|
+
file: 'http://adlnet.gov/expapi/activities/file',
|
|
6
|
+
interaction: 'http://adlnet.gov/expapi/activities/interaction',
|
|
7
|
+
lesson: 'http://adlnet.gov/expapi/activities/lesson',
|
|
8
|
+
link: 'http://adlnet.gov/expapi/activities/link',
|
|
9
|
+
media: 'http://adlnet.gov/expapi/activities/media',
|
|
10
|
+
meeting: 'http://adlnet.gov/expapi/activities/meeting',
|
|
11
|
+
module: 'http://adlnet.gov/expapi/activities/module',
|
|
12
|
+
objective: 'http://adlnet.gov/expapi/activities/objective',
|
|
13
|
+
performance: 'http://adlnet.gov/expapi/activities/performance',
|
|
14
|
+
profile: 'http://adlnet.gov/expapi/activities/profile',
|
|
15
|
+
question: 'http://adlnet.gov/expapi/activities/question',
|
|
16
|
+
simulation: 'http://adlnet.gov/expapi/activities/simulation'
|
|
17
|
+
}
|
|
@@ -1,157 +1,157 @@
|
|
|
1
|
-
export default function (obj) {
|
|
2
|
-
const getQueryVariable = (variable) => {
|
|
3
|
-
var query = window.location.search.substring(1)
|
|
4
|
-
var vars = query.split('&')
|
|
5
|
-
for (var i = 0; i < vars.length; i++) {
|
|
6
|
-
var pair = vars[i].split('=')
|
|
7
|
-
if (decodeURIComponent(pair[0]) == variable) {
|
|
8
|
-
return decodeURIComponent(pair[1])
|
|
9
|
-
}
|
|
10
|
-
}
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
const cb_wrap = (cb) => {
|
|
14
|
-
return function () {
|
|
15
|
-
var args = arguments
|
|
16
|
-
window.setTimeout(function () {
|
|
17
|
-
var callerArgs = []
|
|
18
|
-
for (var i = 0; i < args.length; i++) {
|
|
19
|
-
callerArgs.push(args[i])
|
|
20
|
-
}
|
|
21
|
-
cb.apply(window, callerArgs)
|
|
22
|
-
}, 0)
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
//The library will append the necessary launch info to each new A that is linked to the page.
|
|
27
|
-
//NOTE: This cannot work if you programmatically change the window location. If you do, you must
|
|
28
|
-
//execute the logic in setupCourseLinks to send the initialization data to the new location (if
|
|
29
|
-
//you wish that new location to track as part of this session)
|
|
30
|
-
const observeForNewLinks = () => {
|
|
31
|
-
// select the target node
|
|
32
|
-
var target = document.body
|
|
33
|
-
// create an observer instance
|
|
34
|
-
var observer = new MutationObserver(function (mutations) {
|
|
35
|
-
mutations.forEach(function (mutation) {
|
|
36
|
-
for (var i in mutation.addedNodes) {
|
|
37
|
-
//if (mutation.addedNodes.hasOwnProperty(i)) {
|
|
38
|
-
if (Object.prototype.hasOwnProperty.call(mutation.addedNodes, i)) {
|
|
39
|
-
if (mutation.addedNodes[i].constructor == HTMLAnchorElement) {
|
|
40
|
-
var node = mutation.addedNodes[i]
|
|
41
|
-
setupCourseLinks([node])
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
})
|
|
46
|
-
})
|
|
47
|
-
// configuration of the observer:
|
|
48
|
-
var config = {
|
|
49
|
-
attributes: true,
|
|
50
|
-
childList: true,
|
|
51
|
-
subtree: true
|
|
52
|
-
}
|
|
53
|
-
// pass in the target node, as well as the observer options
|
|
54
|
-
observer.observe(target, config)
|
|
55
|
-
// later, you can stop observing
|
|
56
|
-
/// observer.disconnect();
|
|
57
|
-
}
|
|
58
|
-
//This library will init all links in the DOM that include the attribute "courseLink = true"
|
|
59
|
-
//with the information necessary for the document at that link to track as part of this session.
|
|
60
|
-
const setupCourseLinks = (_nodes) => {
|
|
61
|
-
var launchToken = getQueryVariable('xAPILaunchKey')
|
|
62
|
-
var launchEndpoint = getQueryVariable('xAPILaunchService')
|
|
63
|
-
var encrypted = getQueryVariable('encrypted')
|
|
64
|
-
var query =
|
|
65
|
-
'xAPILaunchKey=' + launchToken + '&xAPILaunchService=' + launchEndpoint
|
|
66
|
-
if (encrypted) {
|
|
67
|
-
query += '&encrypted=true'
|
|
68
|
-
}
|
|
69
|
-
for (var i = 0; i < _nodes.length; i++) {
|
|
70
|
-
var link = _nodes[i]
|
|
71
|
-
var href = link.href
|
|
72
|
-
var courseLink = link.attributes.getNamedItem('courselink')
|
|
73
|
-
if (courseLink && courseLink.value == 'true') {
|
|
74
|
-
if (href.indexOf('?') > -1) {
|
|
75
|
-
href = href + '&' + query
|
|
76
|
-
} else href = href + '?' + query
|
|
77
|
-
link.href = href
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
const xAPILaunch = (cb, terminate_on_unload, strict_callbacks) => {
|
|
83
|
-
cb = cb_wrap(cb)
|
|
84
|
-
|
|
85
|
-
try {
|
|
86
|
-
var launchToken = getQueryVariable('xAPILaunchKey')
|
|
87
|
-
var launchEndpoint = getQueryVariable('xAPILaunchService')
|
|
88
|
-
var encrypted = getQueryVariable('encrypted')
|
|
89
|
-
if (encrypted) {
|
|
90
|
-
//here, we'd have to implement decryption for the data. This makes little sense in a client side only course
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
xAPILaunch.terminate = function (message) {
|
|
94
|
-
var launch = new URL(launchEndpoint)
|
|
95
|
-
launch.pathname += 'launch/' + launchToken + '/terminate'
|
|
96
|
-
var xhr2 = new XMLHttpRequest()
|
|
97
|
-
xhr2.withCredentials = true
|
|
98
|
-
xhr2.crossDomain = true
|
|
99
|
-
|
|
100
|
-
xhr2.open('POST', launch.toString(), false)
|
|
101
|
-
xhr2.setRequestHeader('Content-type', 'application/json')
|
|
102
|
-
xhr2.send(
|
|
103
|
-
JSON.stringify({
|
|
104
|
-
code: 0,
|
|
105
|
-
description: message || 'User closed content'
|
|
106
|
-
})
|
|
107
|
-
)
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
if (!launchToken || !launchEndpoint)
|
|
111
|
-
return cb('invalid launch parameters')
|
|
112
|
-
var launch = new URL(launchEndpoint)
|
|
113
|
-
launch.pathname += 'launch/' + launchToken
|
|
114
|
-
var xhr = new XMLHttpRequest()
|
|
115
|
-
xhr.withCredentials = true
|
|
116
|
-
xhr.crossDomain = true
|
|
117
|
-
xhr.onerror = function (err) {
|
|
118
|
-
//exit the try catch so inner execptions in the callback don't trigger this catch
|
|
119
|
-
window.setTimeout(function () {
|
|
120
|
-
return cb(err)
|
|
121
|
-
})
|
|
122
|
-
}
|
|
123
|
-
xhr.onload = function (e) {
|
|
124
|
-
e
|
|
125
|
-
if (xhr.status !== 200) {
|
|
126
|
-
return xhr.onerror(xhr.responseText)
|
|
127
|
-
}
|
|
128
|
-
var body = JSON.parse(xhr.responseText)
|
|
129
|
-
var launchData = body
|
|
130
|
-
|
|
131
|
-
var conf = {}
|
|
132
|
-
conf['endpoint'] = launchData.endpoint
|
|
133
|
-
conf['actor'] = launchData.actor
|
|
134
|
-
conf.withCredentials = true
|
|
135
|
-
conf.strictCallbacks = strict_callbacks || false
|
|
136
|
-
|
|
137
|
-
window.onunload = function () {
|
|
138
|
-
if (!terminate_on_unload) return
|
|
139
|
-
xAPILaunch.terminate('User closed content')
|
|
140
|
-
}
|
|
141
|
-
const wrapper = new obj.XAPIWrapper.constructor()
|
|
142
|
-
|
|
143
|
-
wrapper.changeConfig(conf)
|
|
144
|
-
//Links that include "courseLink='true'"
|
|
145
|
-
setupCourseLinks(document.body.querySelectorAll('a'))
|
|
146
|
-
//Also, if links are added dynamically, we will do the same logic for those links.
|
|
147
|
-
observeForNewLinks()
|
|
148
|
-
return cb(null, body, wrapper)
|
|
149
|
-
}
|
|
150
|
-
xhr.open('POST', launch.toString(), true)
|
|
151
|
-
xhr.send()
|
|
152
|
-
} catch (e) {
|
|
153
|
-
cb(e)
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
obj.launch = xAPILaunch
|
|
157
|
-
}
|
|
1
|
+
export default function (obj) {
|
|
2
|
+
const getQueryVariable = (variable) => {
|
|
3
|
+
var query = window.location.search.substring(1)
|
|
4
|
+
var vars = query.split('&')
|
|
5
|
+
for (var i = 0; i < vars.length; i++) {
|
|
6
|
+
var pair = vars[i].split('=')
|
|
7
|
+
if (decodeURIComponent(pair[0]) == variable) {
|
|
8
|
+
return decodeURIComponent(pair[1])
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const cb_wrap = (cb) => {
|
|
14
|
+
return function () {
|
|
15
|
+
var args = arguments
|
|
16
|
+
window.setTimeout(function () {
|
|
17
|
+
var callerArgs = []
|
|
18
|
+
for (var i = 0; i < args.length; i++) {
|
|
19
|
+
callerArgs.push(args[i])
|
|
20
|
+
}
|
|
21
|
+
cb.apply(window, callerArgs)
|
|
22
|
+
}, 0)
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
//The library will append the necessary launch info to each new A that is linked to the page.
|
|
27
|
+
//NOTE: This cannot work if you programmatically change the window location. If you do, you must
|
|
28
|
+
//execute the logic in setupCourseLinks to send the initialization data to the new location (if
|
|
29
|
+
//you wish that new location to track as part of this session)
|
|
30
|
+
const observeForNewLinks = () => {
|
|
31
|
+
// select the target node
|
|
32
|
+
var target = document.body
|
|
33
|
+
// create an observer instance
|
|
34
|
+
var observer = new MutationObserver(function (mutations) {
|
|
35
|
+
mutations.forEach(function (mutation) {
|
|
36
|
+
for (var i in mutation.addedNodes) {
|
|
37
|
+
//if (mutation.addedNodes.hasOwnProperty(i)) {
|
|
38
|
+
if (Object.prototype.hasOwnProperty.call(mutation.addedNodes, i)) {
|
|
39
|
+
if (mutation.addedNodes[i].constructor == HTMLAnchorElement) {
|
|
40
|
+
var node = mutation.addedNodes[i]
|
|
41
|
+
setupCourseLinks([node])
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
})
|
|
46
|
+
})
|
|
47
|
+
// configuration of the observer:
|
|
48
|
+
var config = {
|
|
49
|
+
attributes: true,
|
|
50
|
+
childList: true,
|
|
51
|
+
subtree: true
|
|
52
|
+
}
|
|
53
|
+
// pass in the target node, as well as the observer options
|
|
54
|
+
observer.observe(target, config)
|
|
55
|
+
// later, you can stop observing
|
|
56
|
+
/// observer.disconnect();
|
|
57
|
+
}
|
|
58
|
+
//This library will init all links in the DOM that include the attribute "courseLink = true"
|
|
59
|
+
//with the information necessary for the document at that link to track as part of this session.
|
|
60
|
+
const setupCourseLinks = (_nodes) => {
|
|
61
|
+
var launchToken = getQueryVariable('xAPILaunchKey')
|
|
62
|
+
var launchEndpoint = getQueryVariable('xAPILaunchService')
|
|
63
|
+
var encrypted = getQueryVariable('encrypted')
|
|
64
|
+
var query =
|
|
65
|
+
'xAPILaunchKey=' + launchToken + '&xAPILaunchService=' + launchEndpoint
|
|
66
|
+
if (encrypted) {
|
|
67
|
+
query += '&encrypted=true'
|
|
68
|
+
}
|
|
69
|
+
for (var i = 0; i < _nodes.length; i++) {
|
|
70
|
+
var link = _nodes[i]
|
|
71
|
+
var href = link.href
|
|
72
|
+
var courseLink = link.attributes.getNamedItem('courselink')
|
|
73
|
+
if (courseLink && courseLink.value == 'true') {
|
|
74
|
+
if (href.indexOf('?') > -1) {
|
|
75
|
+
href = href + '&' + query
|
|
76
|
+
} else href = href + '?' + query
|
|
77
|
+
link.href = href
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const xAPILaunch = (cb, terminate_on_unload, strict_callbacks) => {
|
|
83
|
+
cb = cb_wrap(cb)
|
|
84
|
+
|
|
85
|
+
try {
|
|
86
|
+
var launchToken = getQueryVariable('xAPILaunchKey')
|
|
87
|
+
var launchEndpoint = getQueryVariable('xAPILaunchService')
|
|
88
|
+
var encrypted = getQueryVariable('encrypted')
|
|
89
|
+
if (encrypted) {
|
|
90
|
+
//here, we'd have to implement decryption for the data. This makes little sense in a client side only course
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
xAPILaunch.terminate = function (message) {
|
|
94
|
+
var launch = new URL(launchEndpoint)
|
|
95
|
+
launch.pathname += 'launch/' + launchToken + '/terminate'
|
|
96
|
+
var xhr2 = new XMLHttpRequest()
|
|
97
|
+
xhr2.withCredentials = true
|
|
98
|
+
xhr2.crossDomain = true
|
|
99
|
+
|
|
100
|
+
xhr2.open('POST', launch.toString(), false)
|
|
101
|
+
xhr2.setRequestHeader('Content-type', 'application/json')
|
|
102
|
+
xhr2.send(
|
|
103
|
+
JSON.stringify({
|
|
104
|
+
code: 0,
|
|
105
|
+
description: message || 'User closed content'
|
|
106
|
+
})
|
|
107
|
+
)
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
if (!launchToken || !launchEndpoint)
|
|
111
|
+
return cb('invalid launch parameters')
|
|
112
|
+
var launch = new URL(launchEndpoint)
|
|
113
|
+
launch.pathname += 'launch/' + launchToken
|
|
114
|
+
var xhr = new XMLHttpRequest()
|
|
115
|
+
xhr.withCredentials = true
|
|
116
|
+
xhr.crossDomain = true
|
|
117
|
+
xhr.onerror = function (err) {
|
|
118
|
+
//exit the try catch so inner execptions in the callback don't trigger this catch
|
|
119
|
+
window.setTimeout(function () {
|
|
120
|
+
return cb(err)
|
|
121
|
+
})
|
|
122
|
+
}
|
|
123
|
+
xhr.onload = function (e) {
|
|
124
|
+
e
|
|
125
|
+
if (xhr.status !== 200) {
|
|
126
|
+
return xhr.onerror(xhr.responseText)
|
|
127
|
+
}
|
|
128
|
+
var body = JSON.parse(xhr.responseText)
|
|
129
|
+
var launchData = body
|
|
130
|
+
|
|
131
|
+
var conf = {}
|
|
132
|
+
conf['endpoint'] = launchData.endpoint
|
|
133
|
+
conf['actor'] = launchData.actor
|
|
134
|
+
conf.withCredentials = true
|
|
135
|
+
conf.strictCallbacks = strict_callbacks || false
|
|
136
|
+
|
|
137
|
+
window.onunload = function () {
|
|
138
|
+
if (!terminate_on_unload) return
|
|
139
|
+
xAPILaunch.terminate('User closed content')
|
|
140
|
+
}
|
|
141
|
+
const wrapper = new obj.XAPIWrapper.constructor()
|
|
142
|
+
|
|
143
|
+
wrapper.changeConfig(conf)
|
|
144
|
+
//Links that include "courseLink='true'"
|
|
145
|
+
setupCourseLinks(document.body.querySelectorAll('a'))
|
|
146
|
+
//Also, if links are added dynamically, we will do the same logic for those links.
|
|
147
|
+
observeForNewLinks()
|
|
148
|
+
return cb(null, body, wrapper)
|
|
149
|
+
}
|
|
150
|
+
xhr.open('POST', launch.toString(), true)
|
|
151
|
+
xhr.send()
|
|
152
|
+
} catch (e) {
|
|
153
|
+
cb(e)
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
obj.launch = xAPILaunch
|
|
157
|
+
}
|