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.
Files changed (95) hide show
  1. package/README.md +8 -1
  2. package/bin/cli.js +16 -0
  3. package/framework/css/components/accordions.css +117 -31
  4. package/framework/css/layouts/article.css +7 -0
  5. package/framework/docs/COURSE_AUTHORING_GUIDE.md +4 -2
  6. package/framework/docs/FRAMEWORK_GUIDE.md +25 -7
  7. package/framework/docs/USER_GUIDE.md +14 -0
  8. package/framework/js/app/AppActions.js +17 -23
  9. package/framework/js/app/AppUI.js +7 -4
  10. package/framework/js/assessment/AssessmentActions.js +16 -15
  11. package/framework/js/assessment/AssessmentFactory.js +44 -15
  12. package/framework/js/automation/api-engagement.js +6 -3
  13. package/framework/js/components/interactions/drag-drop.js +4 -4
  14. package/framework/js/components/interactions/fill-in.js +7 -4
  15. package/framework/js/components/interactions/hotspot.js +2 -2
  16. package/framework/js/components/interactions/matching.js +4 -3
  17. package/framework/js/components/ui-components/audio-player.js +30 -8
  18. package/framework/js/components/ui-components/collapse.js +4 -2
  19. package/framework/js/components/ui-components/dropdown.js +7 -3
  20. package/framework/js/components/ui-components/embed-frame.js +5 -1
  21. package/framework/js/components/ui-components/flip-card.js +12 -6
  22. package/framework/js/components/ui-components/interactive-image.js +28 -52
  23. package/framework/js/components/ui-components/lightbox.js +19 -5
  24. package/framework/js/components/ui-components/modal.js +20 -7
  25. package/framework/js/components/ui-components/notifications.js +8 -3
  26. package/framework/js/components/ui-components/video-player.js +46 -20
  27. package/framework/js/core/event-bus.js +31 -28
  28. package/framework/js/dev/runtime-linter.js +6 -2
  29. package/framework/js/drivers/cmi5-driver.js +186 -83
  30. package/framework/js/drivers/driver-factory.js +7 -1
  31. package/framework/js/drivers/driver-interface.js +1 -1
  32. package/framework/js/drivers/http-driver-base.js +6 -0
  33. package/framework/js/drivers/lti-driver.js +112 -47
  34. package/framework/js/drivers/proxy-driver.js +347 -49
  35. package/framework/js/drivers/scorm-12-driver.js +213 -130
  36. package/framework/js/drivers/scorm-2004-driver.js +32 -19
  37. package/framework/js/drivers/scorm-driver-base.js +12 -0
  38. package/framework/js/drivers/standalone-driver.js +139 -0
  39. package/framework/js/engagement/engagement-trackers.js +38 -13
  40. package/framework/js/engagement/requirement-strategies.js +5 -1
  41. package/framework/js/main.js +7 -0
  42. package/framework/js/managers/assessment-manager.js +16 -1
  43. package/framework/js/managers/audio-manager.js +50 -16
  44. package/framework/js/managers/flag-manager.js +5 -1
  45. package/framework/js/managers/objective-manager.js +15 -7
  46. package/framework/js/managers/score-manager.js +27 -6
  47. package/framework/js/managers/video-manager.js +149 -70
  48. package/framework/js/navigation/NavigationActions.js +18 -4
  49. package/framework/js/navigation/document-gallery.js +7 -2
  50. package/framework/js/navigation/navigation-validators.js +3 -2
  51. package/framework/js/state/lms-connection.js +41 -16
  52. package/framework/js/state/state-commits.js +10 -5
  53. package/framework/js/state/state-manager.js +95 -9
  54. package/framework/js/state/state-validation.js +44 -11
  55. package/framework/js/utilities/course-helpers.js +3 -2
  56. package/framework/js/utilities/media-utils.js +28 -0
  57. package/framework/js/utilities/portable-assets.js +151 -0
  58. package/framework/js/utilities/ui-initializer.js +79 -5
  59. package/framework/js/utilities/utilities.js +32 -20
  60. package/framework/js/utilities/view-manager.js +16 -1
  61. package/framework/js/validation/scorm-validators.js +69 -0
  62. package/framework/version.json +2 -2
  63. package/lib/authoring-api.js +37 -18
  64. package/lib/build-linter.js +192 -2
  65. package/lib/build-packaging.js +47 -3
  66. package/lib/build.js +69 -8
  67. package/lib/cloud.js +40 -11
  68. package/lib/convert.js +30 -2
  69. package/lib/create.js +5 -3
  70. package/lib/dev.js +1 -1
  71. package/lib/headless-browser.js +66 -14
  72. package/lib/manifest/cmi5-manifest.js +26 -4
  73. package/lib/manifest/lti-tool-config.js +7 -2
  74. package/lib/manifest/manifest-factory.d.ts +1 -1
  75. package/lib/manifest/manifest-factory.js +3 -2
  76. package/lib/manifest/scorm-12-manifest.js +2 -2
  77. package/lib/manifest/scorm-2004-manifest.js +3 -28
  78. package/lib/manifest/scorm-proxy-manifest.js +37 -32
  79. package/lib/manifest/xml-utils.js +10 -0
  80. package/lib/narration.js +2 -2
  81. package/lib/portable-html.js +196 -0
  82. package/lib/preview-export.js +1 -1
  83. package/lib/preview-server.js +27 -6
  84. package/lib/project-utils.js +9 -1
  85. package/lib/proxy-templates/proxy.html +4 -1
  86. package/lib/proxy-templates/scorm-bridge.js +82 -10
  87. package/lib/scaffold.js +9 -4
  88. package/lib/stub-player/lms-api.js +63 -8
  89. package/package.json +5 -1
  90. package/schemas/adlcp_rootv1p2.xsd +110 -0
  91. package/schemas/coursecode_scorm12_package.xsd +5 -0
  92. package/schemas/coursecode_scorm2004_package.xsd +8 -0
  93. package/schemas/imscp_rootv1p1p2.xsd +304 -0
  94. package/template/course/slides/example-ui-showcase.js +1 -1
  95. package/template/vite.config.js +50 -22
@@ -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 DIST_DIR = path.join(ROOT_DIR, 'dist');
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, '&lt;')
34
+ .replace(/>/g, '&gt;');
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 = ['imsmanifest.xml', 'index.html'];
79
- // SCORM 1.2 schemas are optional for most LMSs
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: 'dist',
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
- viteStaticCopy({
387
- targets: [
388
- { src: 'schemas/*.{xml,xsd,dtd}', dest: '.', rename: { stripBase: 1 } },
389
- { src: 'schemas/common/*', dest: 'common', rename: { stripBase: 2 } },
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
  ]