coursecode 0.1.57 → 0.1.59
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/README.md +8 -1
- package/bin/cli.js +16 -0
- package/framework/css/components/accordions.css +117 -31
- package/framework/css/layouts/article.css +7 -0
- package/framework/docs/COURSE_AUTHORING_GUIDE.md +4 -2
- package/framework/docs/FRAMEWORK_GUIDE.md +25 -7
- package/framework/docs/USER_GUIDE.md +14 -0
- package/framework/js/app/AppActions.js +17 -23
- package/framework/js/app/AppUI.js +7 -4
- package/framework/js/assessment/AssessmentActions.js +16 -15
- package/framework/js/assessment/AssessmentFactory.js +44 -15
- package/framework/js/automation/api-engagement.js +6 -3
- package/framework/js/components/interactions/drag-drop.js +4 -4
- package/framework/js/components/interactions/fill-in.js +7 -4
- package/framework/js/components/interactions/hotspot.js +2 -2
- package/framework/js/components/interactions/matching.js +4 -3
- package/framework/js/components/ui-components/audio-player.js +30 -8
- package/framework/js/components/ui-components/collapse.js +4 -2
- package/framework/js/components/ui-components/dropdown.js +7 -3
- package/framework/js/components/ui-components/embed-frame.js +5 -1
- package/framework/js/components/ui-components/flip-card.js +12 -6
- package/framework/js/components/ui-components/interactive-image.js +28 -52
- package/framework/js/components/ui-components/lightbox.js +19 -5
- package/framework/js/components/ui-components/modal.js +20 -7
- package/framework/js/components/ui-components/notifications.js +8 -3
- package/framework/js/components/ui-components/video-player.js +46 -20
- package/framework/js/core/event-bus.js +31 -28
- package/framework/js/dev/runtime-linter.js +6 -2
- package/framework/js/drivers/cmi5-driver.js +186 -83
- package/framework/js/drivers/driver-factory.js +7 -1
- package/framework/js/drivers/driver-interface.js +1 -1
- package/framework/js/drivers/http-driver-base.js +6 -0
- package/framework/js/drivers/lti-driver.js +112 -47
- package/framework/js/drivers/proxy-driver.js +347 -49
- package/framework/js/drivers/scorm-12-driver.js +213 -130
- package/framework/js/drivers/scorm-2004-driver.js +32 -19
- package/framework/js/drivers/scorm-driver-base.js +12 -0
- package/framework/js/drivers/standalone-driver.js +139 -0
- package/framework/js/engagement/engagement-trackers.js +38 -13
- package/framework/js/engagement/requirement-strategies.js +5 -1
- package/framework/js/main.js +7 -0
- package/framework/js/managers/assessment-manager.js +16 -1
- package/framework/js/managers/audio-manager.js +50 -16
- package/framework/js/managers/flag-manager.js +5 -1
- package/framework/js/managers/objective-manager.js +15 -7
- package/framework/js/managers/score-manager.js +27 -6
- package/framework/js/managers/video-manager.js +149 -70
- package/framework/js/navigation/NavigationActions.js +18 -4
- package/framework/js/navigation/document-gallery.js +7 -2
- package/framework/js/navigation/navigation-validators.js +3 -2
- package/framework/js/state/lms-connection.js +41 -16
- package/framework/js/state/state-commits.js +10 -5
- package/framework/js/state/state-manager.js +95 -9
- package/framework/js/state/state-validation.js +44 -11
- package/framework/js/utilities/course-helpers.js +3 -2
- package/framework/js/utilities/media-utils.js +28 -0
- package/framework/js/utilities/portable-assets.js +151 -0
- package/framework/js/utilities/ui-initializer.js +79 -5
- package/framework/js/utilities/utilities.js +32 -20
- package/framework/js/utilities/view-manager.js +16 -1
- package/framework/js/validation/scorm-validators.js +69 -0
- package/framework/version.json +2 -2
- package/lib/authoring-api.js +37 -18
- package/lib/build-linter.js +192 -2
- package/lib/build-packaging.js +47 -3
- package/lib/build.js +69 -8
- package/lib/cloud.js +40 -11
- package/lib/convert.js +30 -2
- package/lib/create.js +5 -3
- package/lib/dev.js +1 -1
- package/lib/headless-browser.js +66 -14
- package/lib/manifest/cmi5-manifest.js +26 -4
- package/lib/manifest/lti-tool-config.js +7 -2
- package/lib/manifest/manifest-factory.d.ts +1 -1
- package/lib/manifest/manifest-factory.js +3 -2
- package/lib/manifest/scorm-12-manifest.js +2 -2
- package/lib/manifest/scorm-2004-manifest.js +3 -28
- package/lib/manifest/scorm-proxy-manifest.js +37 -32
- package/lib/manifest/xml-utils.js +10 -0
- package/lib/narration.js +2 -2
- package/lib/portable-html.js +196 -0
- package/lib/preview-export.js +1 -1
- package/lib/preview-server.js +27 -6
- package/lib/project-utils.js +9 -1
- package/lib/proxy-templates/proxy.html +4 -1
- package/lib/proxy-templates/scorm-bridge.js +82 -10
- package/lib/scaffold.js +9 -4
- package/lib/stub-player/lms-api.js +63 -8
- package/package.json +5 -1
- package/schemas/adlcp_rootv1p2.xsd +110 -0
- package/schemas/coursecode_scorm12_package.xsd +5 -0
- package/schemas/coursecode_scorm2004_package.xsd +8 -0
- package/schemas/imscp_rootv1p1p2.xsd +304 -0
- package/template/course/slides/example-ui-showcase.js +1 -1
- package/template/vite.config.js +50 -22
package/template/vite.config.js
CHANGED
|
@@ -10,10 +10,13 @@ let createStandardPackage;
|
|
|
10
10
|
let createExternalPackagesForClients;
|
|
11
11
|
let validateExternalHostingConfig;
|
|
12
12
|
let loadExternalAccessConfig;
|
|
13
|
+
let createPortableHtmlPlugin;
|
|
13
14
|
|
|
14
15
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
15
16
|
const ROOT_DIR = path.resolve(__dirname);
|
|
16
|
-
const
|
|
17
|
+
const BUILD_OUTPUT = process.env.COURSECODE_OUT_DIR || 'dist';
|
|
18
|
+
const DIST_DIR = path.resolve(ROOT_DIR, BUILD_OUTPUT);
|
|
19
|
+
const PORTABLE_HTML = process.env.COURSECODE_PORTABLE_HTML === 'true';
|
|
17
20
|
const SUPPORTED_BROWSER_TARGETS = ['chrome111', 'edge111', 'firefox114', 'safari16.4'];
|
|
18
21
|
|
|
19
22
|
function directoryContainsFiles(directory) {
|
|
@@ -23,6 +26,14 @@ function directoryContainsFiles(directory) {
|
|
|
23
26
|
));
|
|
24
27
|
}
|
|
25
28
|
|
|
29
|
+
function escapeHtmlAttribute(value) {
|
|
30
|
+
return String(value)
|
|
31
|
+
.replace(/&/g, '&')
|
|
32
|
+
.replace(/"/g, '"')
|
|
33
|
+
.replace(/</g, '<')
|
|
34
|
+
.replace(/>/g, '>');
|
|
35
|
+
}
|
|
36
|
+
|
|
26
37
|
async function loadBuildUtils() {
|
|
27
38
|
if (
|
|
28
39
|
generateManifest &&
|
|
@@ -30,7 +41,8 @@ async function loadBuildUtils() {
|
|
|
30
41
|
createStandardPackage &&
|
|
31
42
|
createExternalPackagesForClients &&
|
|
32
43
|
validateExternalHostingConfig &&
|
|
33
|
-
loadExternalAccessConfig
|
|
44
|
+
loadExternalAccessConfig &&
|
|
45
|
+
createPortableHtmlPlugin
|
|
34
46
|
) {
|
|
35
47
|
return;
|
|
36
48
|
}
|
|
@@ -44,6 +56,7 @@ async function loadBuildUtils() {
|
|
|
44
56
|
loadExternalAccessConfig
|
|
45
57
|
} = await import('coursecode/build-packaging'));
|
|
46
58
|
({ default: contentDiscoveryPlugin } = await import('coursecode/vite-plugin-content-discovery'));
|
|
59
|
+
({ createPortableHtmlPlugin } = await import('coursecode/portable-html'));
|
|
47
60
|
} catch {
|
|
48
61
|
// Fallback for npm link / local dev — preview-server provides COURSECODE_LIB_DIR
|
|
49
62
|
const libDir = process.env.COURSECODE_LIB_DIR;
|
|
@@ -57,6 +70,7 @@ async function loadBuildUtils() {
|
|
|
57
70
|
loadExternalAccessConfig
|
|
58
71
|
} = await import(toUrl('build-packaging.js')));
|
|
59
72
|
({ default: contentDiscoveryPlugin } = await import(toUrl('vite-plugin-content-discovery.js')));
|
|
73
|
+
({ createPortableHtmlPlugin } = await import(toUrl('portable-html.js')));
|
|
60
74
|
}
|
|
61
75
|
}
|
|
62
76
|
|
|
@@ -75,8 +89,13 @@ function validatePackage(format = 'scorm2004') {
|
|
|
75
89
|
} else if (format === 'lti') {
|
|
76
90
|
requiredFiles = ['lti-tool-config.json', 'index.html'];
|
|
77
91
|
} else if (format === 'scorm1.2') {
|
|
78
|
-
requiredFiles = [
|
|
79
|
-
|
|
92
|
+
requiredFiles = [
|
|
93
|
+
'imsmanifest.xml',
|
|
94
|
+
'index.html',
|
|
95
|
+
'imscp_rootv1p1p2.xsd',
|
|
96
|
+
'adlcp_rootv1p2.xsd',
|
|
97
|
+
'ims_xml.xsd'
|
|
98
|
+
];
|
|
80
99
|
} else {
|
|
81
100
|
// SCORM 2004 default
|
|
82
101
|
requiredFiles = [
|
|
@@ -199,6 +218,7 @@ async function loadCourseConfig() {
|
|
|
199
218
|
lmsFormat,
|
|
200
219
|
externalUrl: process.env.LTI_EXTERNAL_URL || config.externalUrl || null,
|
|
201
220
|
masteryScore: masteryScore ?? null,
|
|
221
|
+
moveOn: config.lms?.moveOn || null,
|
|
202
222
|
accessControl: loadExternalAccessConfig(ROOT_DIR, config),
|
|
203
223
|
galleryConfig: config.navigation?.documentGallery || null
|
|
204
224
|
};
|
|
@@ -276,7 +296,7 @@ function scormPostBuild(isDev, { isWatchBuild }) {
|
|
|
276
296
|
// Stamp LMS format meta tag for runtime driver selection
|
|
277
297
|
indexContent = indexContent.replace(
|
|
278
298
|
'<meta charset="UTF-8" />',
|
|
279
|
-
`<meta charset="UTF-8" />\n <meta name="lms-format" content="${config.lmsFormat}" />`
|
|
299
|
+
`<meta charset="UTF-8" />\n <meta name="lms-format" content="${config.lmsFormat}" />\n <meta name="coursecode-id" content="${escapeHtmlAttribute(`${config.title}:${config.version}`)}" />`
|
|
280
300
|
);
|
|
281
301
|
|
|
282
302
|
fs.writeFileSync(indexDest, indexContent, 'utf-8');
|
|
@@ -287,6 +307,11 @@ function scormPostBuild(isDev, { isWatchBuild }) {
|
|
|
287
307
|
}
|
|
288
308
|
}
|
|
289
309
|
|
|
310
|
+
if (PORTABLE_HTML) {
|
|
311
|
+
if (!isDev) console.log('✓ Portable runtime assembled (LMS package files omitted)');
|
|
312
|
+
return;
|
|
313
|
+
}
|
|
314
|
+
|
|
290
315
|
// Generate manifest using factory
|
|
291
316
|
const files = isDev ? ['index.html'] : scanDistFiles();
|
|
292
317
|
const manifestOptions = { externalUrl: config.externalUrl };
|
|
@@ -333,6 +358,17 @@ export default defineConfig(async ({ mode }) => {
|
|
|
333
358
|
const isDev = mode === 'development';
|
|
334
359
|
const isWatchBuild = process.argv.includes('--watch');
|
|
335
360
|
const courseConfig = await loadCourseConfig();
|
|
361
|
+
const staticCopyTargets = [
|
|
362
|
+
...(!PORTABLE_HTML ? [
|
|
363
|
+
{ src: 'schemas/*.{xml,xsd,dtd}', dest: '.', rename: { stripBase: 1 } },
|
|
364
|
+
{ src: 'schemas/common/*', dest: 'common', rename: { stripBase: 2 } },
|
|
365
|
+
{ src: 'framework/js/vendor/**/*', dest: 'js/vendor', rename: { stripBase: 3 } }
|
|
366
|
+
] : []),
|
|
367
|
+
// Publish runtime assets only. Authoring source stays out of every output.
|
|
368
|
+
...(directoryContainsFiles(path.join(ROOT_DIR, 'course', 'assets'))
|
|
369
|
+
? [{ src: 'course/assets', dest: 'course', rename: { stripBase: 1 } }]
|
|
370
|
+
: [])
|
|
371
|
+
];
|
|
336
372
|
|
|
337
373
|
return {
|
|
338
374
|
root: '.',
|
|
@@ -356,7 +392,7 @@ export default defineConfig(async ({ mode }) => {
|
|
|
356
392
|
},
|
|
357
393
|
|
|
358
394
|
build: {
|
|
359
|
-
outDir:
|
|
395
|
+
outDir: BUILD_OUTPUT,
|
|
360
396
|
emptyOutDir: !isWatchBuild,
|
|
361
397
|
// Stable browser contract for LMS launches. SCORM defines the LMS API,
|
|
362
398
|
// not an obsolete browser requirement; IE11/SystemJS is unsupported.
|
|
@@ -372,9 +408,9 @@ export default defineConfig(async ({ mode }) => {
|
|
|
372
408
|
// LTI OIDC/JWT validation remains server-side, so no browser crypto
|
|
373
409
|
// verification dependency is required here.
|
|
374
410
|
output: {
|
|
375
|
-
entryFileNames: 'assets/[name].js',
|
|
376
|
-
chunkFileNames: 'assets/[name].js',
|
|
377
|
-
assetFileNames: 'assets/[name].[ext]'
|
|
411
|
+
entryFileNames: 'assets/[name]-[hash].js',
|
|
412
|
+
chunkFileNames: 'assets/[name]-[hash].js',
|
|
413
|
+
assetFileNames: 'assets/[name]-[hash].[ext]'
|
|
378
414
|
}
|
|
379
415
|
}
|
|
380
416
|
},
|
|
@@ -383,20 +419,12 @@ export default defineConfig(async ({ mode }) => {
|
|
|
383
419
|
// Content discovery - generates manifest at build time
|
|
384
420
|
contentDiscoveryPlugin({ galleryConfig: courseConfig.galleryConfig }),
|
|
385
421
|
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
// Publish runtime assets only. Never ship authoring references,
|
|
391
|
-
// configuration source, assessment source, or hidden project files.
|
|
392
|
-
// A blank course is valid and may not contain any assets yet.
|
|
393
|
-
...(directoryContainsFiles(path.join(ROOT_DIR, 'course', 'assets'))
|
|
394
|
-
? [{ src: 'course/assets', dest: 'course', rename: { stripBase: 1 } }]
|
|
395
|
-
: []),
|
|
396
|
-
{ src: 'framework/js/vendor/**/*', dest: 'js/vendor', rename: { stripBase: 3 } }
|
|
397
|
-
],
|
|
422
|
+
...(PORTABLE_HTML ? [createPortableHtmlPlugin()] : []),
|
|
423
|
+
|
|
424
|
+
...(staticCopyTargets.length > 0 ? [viteStaticCopy({
|
|
425
|
+
targets: staticCopyTargets,
|
|
398
426
|
watch: isDev ? { rerun: true } : undefined
|
|
399
|
-
}),
|
|
427
|
+
})] : []),
|
|
400
428
|
|
|
401
429
|
scormPostBuild(isDev, { isWatchBuild })
|
|
402
430
|
]
|