@patch-adams/core 1.4.9 → 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.cjs CHANGED
@@ -2535,6 +2535,15 @@ function generateLrsBridgeCode(options) {
2535
2535
  ctx.extensions['http://xyleme.com/bravais/extensions/statement-schema'] = 'xyleme_10';
2536
2536
  ctx.extensions['http://xyleme.com/bravais/extensions/protect_pii'] = false;
2537
2537
 
2538
+ // Add parent course activity for document-level aggregation in Bravais
2539
+ // This allows statements with activity-specific objects to still be found
2540
+ // when searching by document name in Analytics
2541
+ var parentActivity = buildParentCourseActivity();
2542
+ if (parentActivity) {
2543
+ ctx.contextActivities = ctx.contextActivities || {};
2544
+ ctx.contextActivities.parent = [parentActivity];
2545
+ }
2546
+
2538
2547
  return ctx;
2539
2548
  }
2540
2549
 
@@ -2579,18 +2588,110 @@ function generateLrsBridgeCode(options) {
2579
2588
 
2580
2589
  /**
2581
2590
  * Build activity object for questions in Xyleme format
2591
+ * Name format: "Assessment Name - Q#: Question text..."
2582
2592
  */
2583
2593
  function buildQuestionActivityObject(questionInfo) {
2584
2594
  var questionGuid = questionInfo.questionGuid || questionInfo.id || generateUUID();
2585
2595
 
2596
+ // Build human-readable display name
2597
+ var displayName = (questionInfo.assessmentName || 'Knowledge Check');
2598
+ if (questionInfo.questionNumber) {
2599
+ displayName += ' - Q' + questionInfo.questionNumber;
2600
+ }
2601
+ var questionText = questionInfo.text || questionInfo.questionText || '';
2602
+ if (questionText.length > 50) {
2603
+ displayName += ': ' + questionText.substring(0, 47) + '...';
2604
+ } else if (questionText.length > 0) {
2605
+ displayName += ': ' + questionText;
2606
+ }
2607
+
2586
2608
  return {
2587
2609
  objectType: 'Activity',
2588
2610
  id: 'http://xyleme.com/bravais/question/' + questionGuid,
2589
2611
  definition: {
2590
2612
  type: XYLEME_ACTIVITY_TYPES.question,
2591
- name: { 'en-US': questionInfo.text || questionInfo.questionText || 'Question' },
2613
+ name: { 'en-US': displayName },
2614
+ description: { 'en-US': questionText || 'Question' },
2592
2615
  extensions: {
2593
- resourceType: 'Question'
2616
+ resourceType: 'Question',
2617
+ questionNumber: questionInfo.questionNumber || null
2618
+ }
2619
+ }
2620
+ };
2621
+ }
2622
+
2623
+ /**
2624
+ * Build activity object for media (video/audio) with human-readable name
2625
+ * Name format: "Video: Title" or "Audio: Title"
2626
+ */
2627
+ function buildMediaActivityObject(mediaInfo) {
2628
+ var mediaGuid = mediaInfo.mediaGuid || generateUUID();
2629
+ var mediaType = mediaInfo.type === 'audio' ? ACTIVITY_TYPES.audio : ACTIVITY_TYPES.video;
2630
+ var resourceType = mediaInfo.type === 'audio' ? 'Audio' : 'Video';
2631
+
2632
+ // Build human-readable display name
2633
+ var displayName = mediaInfo.name || '';
2634
+ if (!displayName || displayName === 'video' || displayName === 'audio' || displayName === 'Media') {
2635
+ displayName = resourceType + ': ' + (mediaInfo.lessonName || 'Media');
2636
+ } else {
2637
+ displayName = resourceType + ': ' + displayName;
2638
+ }
2639
+
2640
+ return {
2641
+ objectType: 'Activity',
2642
+ id: 'http://xyleme.com/bravais/media/' + mediaGuid,
2643
+ definition: {
2644
+ type: mediaType,
2645
+ name: { 'en-US': displayName },
2646
+ extensions: {
2647
+ resourceType: resourceType,
2648
+ mediaSrc: mediaInfo.src || '',
2649
+ mediaType: mediaInfo.type || 'video',
2650
+ duration: mediaInfo.duration || 0
2651
+ }
2652
+ }
2653
+ };
2654
+ }
2655
+
2656
+ /**
2657
+ * Build activity object for interactions (tabs, accordions, flashcards, etc.)
2658
+ * Name format: "Tab: Label" or "Accordion: Label"
2659
+ */
2660
+ function buildInteractionActivityObject(interactionInfo) {
2661
+ var typeLabels = {
2662
+ 'tab': 'Tab',
2663
+ 'accordion': 'Accordion',
2664
+ 'flashcard': 'Flashcard',
2665
+ 'hotspot': 'Hotspot',
2666
+ 'process-step': 'Process Step',
2667
+ 'process': 'Process Step',
2668
+ 'sorting': 'Sorting Activity',
2669
+ 'button': 'Button',
2670
+ 'labeled-graphic': 'Labeled Graphic',
2671
+ 'timeline': 'Timeline',
2672
+ 'scenario': 'Scenario',
2673
+ 'checklist': 'Checklist',
2674
+ 'marker': 'Marker'
2675
+ };
2676
+
2677
+ var interactionType = interactionInfo.type || interactionInfo.interactionType || 'interaction';
2678
+ var typeLabel = typeLabels[interactionType] || 'Interaction';
2679
+
2680
+ // Build human-readable display name
2681
+ var displayName = interactionInfo.name;
2682
+ if (!displayName) {
2683
+ displayName = typeLabel + ': ' + (interactionInfo.label || interactionInfo.id || 'Item');
2684
+ }
2685
+
2686
+ return {
2687
+ objectType: 'Activity',
2688
+ id: 'http://xyleme.com/bravais/interaction/' + (interactionInfo.id || generateUUID()),
2689
+ definition: {
2690
+ type: ACTIVITY_TYPES.interaction,
2691
+ name: { 'en-US': displayName },
2692
+ extensions: {
2693
+ resourceType: 'Interaction',
2694
+ interactionType: interactionType
2594
2695
  }
2595
2696
  }
2596
2697
  };
@@ -2845,35 +2946,34 @@ function generateLrsBridgeCode(options) {
2845
2946
  sendStatement(statement);
2846
2947
  };
2847
2948
 
2848
- // Media events
2949
+ // Media events - uses activity-specific object with human-readable name
2950
+ // Parent context (added by buildXylemeContext) ensures document aggregation
2849
2951
  LRS.mediaPlayed = function(data) {
2850
2952
  if (!TRACK_MEDIA) return;
2851
2953
 
2852
2954
  // Get current lesson context
2853
2955
  var lessonInfo = getCachedLessonInfo();
2854
2956
 
2855
- var mediaType = data.type === 'audio' ? ACTIVITY_TYPES.audio : ACTIVITY_TYPES.video;
2856
2957
  var verbKey = data.action === 'play' ? 'played' :
2857
2958
  data.action === 'pause' ? 'paused' :
2858
2959
  data.action === 'completed' ? 'completed' : 'played';
2859
2960
 
2860
- // Activity type is video/audio, details include media info
2861
- var activityDetails = {
2862
- mediaSrc: data.src || 'media-' + Date.now(),
2863
- mediaName: data.name || (data.type || 'Media'),
2864
- mediaType: data.type || 'video',
2865
- 'https://w3id.org/xapi/video/extensions/length': data.duration || 0,
2866
- // Include lesson/section context
2867
- lessonId: lessonInfo.id,
2868
- lessonName: lessonInfo.name,
2869
- sectionName: lessonInfo.sectionName
2870
- };
2961
+ // Build activity-specific object with human-readable name
2962
+ // e.g., "Video: Introduction" or "Audio: Podcast Episode 1"
2963
+ var mediaObject = buildMediaActivityObject({
2964
+ type: data.type,
2965
+ src: data.src,
2966
+ name: data.name,
2967
+ duration: data.duration,
2968
+ lessonName: lessonInfo.name
2969
+ });
2871
2970
 
2872
2971
  var result = {
2873
2972
  extensions: {
2874
2973
  'https://w3id.org/xapi/video/extensions/time': data.currentTime || 0,
2875
2974
  'https://w3id.org/xapi/video/extensions/progress': data.duration > 0 ?
2876
- Math.round((data.currentTime / data.duration) * 100) / 100 : 0
2975
+ Math.round((data.currentTime / data.duration) * 100) / 100 : 0,
2976
+ 'https://w3id.org/xapi/video/extensions/length': data.duration || 0
2877
2977
  }
2878
2978
  };
2879
2979
 
@@ -2881,7 +2981,16 @@ function generateLrsBridgeCode(options) {
2881
2981
  result.completion = true;
2882
2982
  }
2883
2983
 
2884
- var statement = buildStatement(verbKey, mediaType, activityDetails, result);
2984
+ // Context includes lesson info; parent course activity added by buildXylemeContext
2985
+ var additionalContext = {
2986
+ extensions: {
2987
+ lessonId: lessonInfo.id,
2988
+ lessonName: lessonInfo.name,
2989
+ sectionName: lessonInfo.sectionName
2990
+ }
2991
+ };
2992
+
2993
+ var statement = buildStatementXyleme(verbKey, mediaObject, result, additionalContext);
2885
2994
  sendStatement(statement);
2886
2995
  };
2887
2996
 
@@ -3013,27 +3122,35 @@ function generateLrsBridgeCode(options) {
3013
3122
  LRS.assessmentEnded(data);
3014
3123
  };
3015
3124
 
3016
- // Interactions (tabs, accordions, etc.)
3125
+ // Interactions (tabs, accordions, etc.) - uses activity-specific object
3126
+ // Object name shows the interaction type and label, e.g., "Tab: Overview"
3127
+ // Parent context ensures these appear in document search results
3017
3128
  LRS.interacted = function(data) {
3018
3129
  if (!TRACK_INTERACTIONS) return;
3019
3130
 
3020
3131
  // Get current lesson context
3021
3132
  var lessonInfo = getCachedLessonInfo();
3022
3133
 
3023
- // Activity type is interaction, details include interaction ID and type
3024
- var statement = buildStatement(
3025
- 'interacted',
3026
- ACTIVITY_TYPES.interaction,
3027
- {
3134
+ // Build activity-specific object with human-readable name
3135
+ // e.g., "Tab: Getting Started", "Accordion: FAQ"
3136
+ var interactionObject = buildInteractionActivityObject({
3137
+ type: data.type || data.interactionType,
3138
+ id: data.id,
3139
+ name: data.name,
3140
+ label: data.name || data.type
3141
+ });
3142
+
3143
+ // Context includes lesson info; parent course activity added by buildXylemeContext
3144
+ var additionalContext = {
3145
+ extensions: {
3028
3146
  interactionId: data.id || 'interaction-' + Date.now(),
3029
- interactionName: data.name || data.type || 'Interaction',
3030
- interactionType: data.interactionType || data.type || 'other',
3031
- // Include lesson/section context
3032
3147
  lessonId: lessonInfo.id,
3033
3148
  lessonName: lessonInfo.name,
3034
3149
  sectionName: lessonInfo.sectionName
3035
3150
  }
3036
- );
3151
+ };
3152
+
3153
+ var statement = buildStatementXyleme('interacted', interactionObject, null, additionalContext);
3037
3154
  sendStatement(statement);
3038
3155
  };
3039
3156