@patch-adams/core 1.4.8 → 1.4.10

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/dist/index.js CHANGED
@@ -2311,6 +2311,22 @@ function generateLrsBridgeCode(options) {
2311
2311
  // This allows filtering by type (video, assessment, interaction) in Analytics
2312
2312
  if (activityType) {
2313
2313
  courseObj.definition.type = activityType;
2314
+
2315
+ // Also update resourceType extension to human-readable form for Bravais Type column
2316
+ courseObj.definition.extensions = courseObj.definition.extensions || {};
2317
+ var resourceTypeMap = {
2318
+ 'https://w3id.org/xapi/video/activity-type/video': 'Video',
2319
+ 'https://w3id.org/xapi/audio/activity-type/audio': 'Audio',
2320
+ 'http://adlnet.gov/expapi/activities/media': 'Media',
2321
+ 'http://adlnet.gov/expapi/activities/assessment': 'Assessment',
2322
+ 'http://adlnet.gov/expapi/activities/question': 'Question',
2323
+ 'http://adlnet.gov/expapi/activities/interaction': 'Interaction',
2324
+ 'http://adlnet.gov/expapi/activities/lesson': 'Lesson',
2325
+ 'http://adlnet.gov/expapi/activities/module': 'Module',
2326
+ 'http://adlnet.gov/expapi/activities/course': 'Course',
2327
+ 'http://xyleme.com/bravais/activities/document': 'Course'
2328
+ };
2329
+ courseObj.definition.extensions['resourceType'] = resourceTypeMap[activityType] || 'Course';
2314
2330
  }
2315
2331
 
2316
2332
  // Add activity-specific details to extensions
@@ -2511,6 +2527,15 @@ function generateLrsBridgeCode(options) {
2511
2527
  ctx.extensions['http://xyleme.com/bravais/extensions/statement-schema'] = 'xyleme_10';
2512
2528
  ctx.extensions['http://xyleme.com/bravais/extensions/protect_pii'] = false;
2513
2529
 
2530
+ // Add parent course activity for document-level aggregation in Bravais
2531
+ // This allows statements with activity-specific objects to still be found
2532
+ // when searching by document name in Analytics
2533
+ var parentActivity = buildParentCourseActivity();
2534
+ if (parentActivity) {
2535
+ ctx.contextActivities = ctx.contextActivities || {};
2536
+ ctx.contextActivities.parent = [parentActivity];
2537
+ }
2538
+
2514
2539
  return ctx;
2515
2540
  }
2516
2541
 
@@ -2555,18 +2580,110 @@ function generateLrsBridgeCode(options) {
2555
2580
 
2556
2581
  /**
2557
2582
  * Build activity object for questions in Xyleme format
2583
+ * Name format: "Assessment Name - Q#: Question text..."
2558
2584
  */
2559
2585
  function buildQuestionActivityObject(questionInfo) {
2560
2586
  var questionGuid = questionInfo.questionGuid || questionInfo.id || generateUUID();
2561
2587
 
2588
+ // Build human-readable display name
2589
+ var displayName = (questionInfo.assessmentName || 'Knowledge Check');
2590
+ if (questionInfo.questionNumber) {
2591
+ displayName += ' - Q' + questionInfo.questionNumber;
2592
+ }
2593
+ var questionText = questionInfo.text || questionInfo.questionText || '';
2594
+ if (questionText.length > 50) {
2595
+ displayName += ': ' + questionText.substring(0, 47) + '...';
2596
+ } else if (questionText.length > 0) {
2597
+ displayName += ': ' + questionText;
2598
+ }
2599
+
2562
2600
  return {
2563
2601
  objectType: 'Activity',
2564
2602
  id: 'http://xyleme.com/bravais/question/' + questionGuid,
2565
2603
  definition: {
2566
2604
  type: XYLEME_ACTIVITY_TYPES.question,
2567
- name: { 'en-US': questionInfo.text || questionInfo.questionText || 'Question' },
2605
+ name: { 'en-US': displayName },
2606
+ description: { 'en-US': questionText || 'Question' },
2607
+ extensions: {
2608
+ resourceType: 'Question',
2609
+ questionNumber: questionInfo.questionNumber || null
2610
+ }
2611
+ }
2612
+ };
2613
+ }
2614
+
2615
+ /**
2616
+ * Build activity object for media (video/audio) with human-readable name
2617
+ * Name format: "Video: Title" or "Audio: Title"
2618
+ */
2619
+ function buildMediaActivityObject(mediaInfo) {
2620
+ var mediaGuid = mediaInfo.mediaGuid || generateUUID();
2621
+ var mediaType = mediaInfo.type === 'audio' ? ACTIVITY_TYPES.audio : ACTIVITY_TYPES.video;
2622
+ var resourceType = mediaInfo.type === 'audio' ? 'Audio' : 'Video';
2623
+
2624
+ // Build human-readable display name
2625
+ var displayName = mediaInfo.name || '';
2626
+ if (!displayName || displayName === 'video' || displayName === 'audio' || displayName === 'Media') {
2627
+ displayName = resourceType + ': ' + (mediaInfo.lessonName || 'Media');
2628
+ } else {
2629
+ displayName = resourceType + ': ' + displayName;
2630
+ }
2631
+
2632
+ return {
2633
+ objectType: 'Activity',
2634
+ id: 'http://xyleme.com/bravais/media/' + mediaGuid,
2635
+ definition: {
2636
+ type: mediaType,
2637
+ name: { 'en-US': displayName },
2638
+ extensions: {
2639
+ resourceType: resourceType,
2640
+ mediaSrc: mediaInfo.src || '',
2641
+ mediaType: mediaInfo.type || 'video',
2642
+ duration: mediaInfo.duration || 0
2643
+ }
2644
+ }
2645
+ };
2646
+ }
2647
+
2648
+ /**
2649
+ * Build activity object for interactions (tabs, accordions, flashcards, etc.)
2650
+ * Name format: "Tab: Label" or "Accordion: Label"
2651
+ */
2652
+ function buildInteractionActivityObject(interactionInfo) {
2653
+ var typeLabels = {
2654
+ 'tab': 'Tab',
2655
+ 'accordion': 'Accordion',
2656
+ 'flashcard': 'Flashcard',
2657
+ 'hotspot': 'Hotspot',
2658
+ 'process-step': 'Process Step',
2659
+ 'process': 'Process Step',
2660
+ 'sorting': 'Sorting Activity',
2661
+ 'button': 'Button',
2662
+ 'labeled-graphic': 'Labeled Graphic',
2663
+ 'timeline': 'Timeline',
2664
+ 'scenario': 'Scenario',
2665
+ 'checklist': 'Checklist',
2666
+ 'marker': 'Marker'
2667
+ };
2668
+
2669
+ var interactionType = interactionInfo.type || interactionInfo.interactionType || 'interaction';
2670
+ var typeLabel = typeLabels[interactionType] || 'Interaction';
2671
+
2672
+ // Build human-readable display name
2673
+ var displayName = interactionInfo.name;
2674
+ if (!displayName) {
2675
+ displayName = typeLabel + ': ' + (interactionInfo.label || interactionInfo.id || 'Item');
2676
+ }
2677
+
2678
+ return {
2679
+ objectType: 'Activity',
2680
+ id: 'http://xyleme.com/bravais/interaction/' + (interactionInfo.id || generateUUID()),
2681
+ definition: {
2682
+ type: ACTIVITY_TYPES.interaction,
2683
+ name: { 'en-US': displayName },
2568
2684
  extensions: {
2569
- resourceType: 'Question'
2685
+ resourceType: 'Interaction',
2686
+ interactionType: interactionType
2570
2687
  }
2571
2688
  }
2572
2689
  };
@@ -2821,35 +2938,34 @@ function generateLrsBridgeCode(options) {
2821
2938
  sendStatement(statement);
2822
2939
  };
2823
2940
 
2824
- // Media events
2941
+ // Media events - uses activity-specific object with human-readable name
2942
+ // Parent context (added by buildXylemeContext) ensures document aggregation
2825
2943
  LRS.mediaPlayed = function(data) {
2826
2944
  if (!TRACK_MEDIA) return;
2827
2945
 
2828
2946
  // Get current lesson context
2829
2947
  var lessonInfo = getCachedLessonInfo();
2830
2948
 
2831
- var mediaType = data.type === 'audio' ? ACTIVITY_TYPES.audio : ACTIVITY_TYPES.video;
2832
2949
  var verbKey = data.action === 'play' ? 'played' :
2833
2950
  data.action === 'pause' ? 'paused' :
2834
2951
  data.action === 'completed' ? 'completed' : 'played';
2835
2952
 
2836
- // Activity type is video/audio, details include media info
2837
- var activityDetails = {
2838
- mediaSrc: data.src || 'media-' + Date.now(),
2839
- mediaName: data.name || (data.type || 'Media'),
2840
- mediaType: data.type || 'video',
2841
- 'https://w3id.org/xapi/video/extensions/length': data.duration || 0,
2842
- // Include lesson/section context
2843
- lessonId: lessonInfo.id,
2844
- lessonName: lessonInfo.name,
2845
- sectionName: lessonInfo.sectionName
2846
- };
2953
+ // Build activity-specific object with human-readable name
2954
+ // e.g., "Video: Introduction" or "Audio: Podcast Episode 1"
2955
+ var mediaObject = buildMediaActivityObject({
2956
+ type: data.type,
2957
+ src: data.src,
2958
+ name: data.name,
2959
+ duration: data.duration,
2960
+ lessonName: lessonInfo.name
2961
+ });
2847
2962
 
2848
2963
  var result = {
2849
2964
  extensions: {
2850
2965
  'https://w3id.org/xapi/video/extensions/time': data.currentTime || 0,
2851
2966
  'https://w3id.org/xapi/video/extensions/progress': data.duration > 0 ?
2852
- Math.round((data.currentTime / data.duration) * 100) / 100 : 0
2967
+ Math.round((data.currentTime / data.duration) * 100) / 100 : 0,
2968
+ 'https://w3id.org/xapi/video/extensions/length': data.duration || 0
2853
2969
  }
2854
2970
  };
2855
2971
 
@@ -2857,7 +2973,16 @@ function generateLrsBridgeCode(options) {
2857
2973
  result.completion = true;
2858
2974
  }
2859
2975
 
2860
- var statement = buildStatement(verbKey, mediaType, activityDetails, result);
2976
+ // Context includes lesson info; parent course activity added by buildXylemeContext
2977
+ var additionalContext = {
2978
+ extensions: {
2979
+ lessonId: lessonInfo.id,
2980
+ lessonName: lessonInfo.name,
2981
+ sectionName: lessonInfo.sectionName
2982
+ }
2983
+ };
2984
+
2985
+ var statement = buildStatementXyleme(verbKey, mediaObject, result, additionalContext);
2861
2986
  sendStatement(statement);
2862
2987
  };
2863
2988
 
@@ -2989,27 +3114,35 @@ function generateLrsBridgeCode(options) {
2989
3114
  LRS.assessmentEnded(data);
2990
3115
  };
2991
3116
 
2992
- // Interactions (tabs, accordions, etc.)
3117
+ // Interactions (tabs, accordions, etc.) - uses activity-specific object
3118
+ // Object name shows the interaction type and label, e.g., "Tab: Overview"
3119
+ // Parent context ensures these appear in document search results
2993
3120
  LRS.interacted = function(data) {
2994
3121
  if (!TRACK_INTERACTIONS) return;
2995
3122
 
2996
3123
  // Get current lesson context
2997
3124
  var lessonInfo = getCachedLessonInfo();
2998
3125
 
2999
- // Activity type is interaction, details include interaction ID and type
3000
- var statement = buildStatement(
3001
- 'interacted',
3002
- ACTIVITY_TYPES.interaction,
3003
- {
3126
+ // Build activity-specific object with human-readable name
3127
+ // e.g., "Tab: Getting Started", "Accordion: FAQ"
3128
+ var interactionObject = buildInteractionActivityObject({
3129
+ type: data.type || data.interactionType,
3130
+ id: data.id,
3131
+ name: data.name,
3132
+ label: data.name || data.type
3133
+ });
3134
+
3135
+ // Context includes lesson info; parent course activity added by buildXylemeContext
3136
+ var additionalContext = {
3137
+ extensions: {
3004
3138
  interactionId: data.id || 'interaction-' + Date.now(),
3005
- interactionName: data.name || data.type || 'Interaction',
3006
- interactionType: data.interactionType || data.type || 'other',
3007
- // Include lesson/section context
3008
3139
  lessonId: lessonInfo.id,
3009
3140
  lessonName: lessonInfo.name,
3010
3141
  sectionName: lessonInfo.sectionName
3011
3142
  }
3012
- );
3143
+ };
3144
+
3145
+ var statement = buildStatementXyleme('interacted', interactionObject, null, additionalContext);
3013
3146
  sendStatement(statement);
3014
3147
  };
3015
3148