@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.js CHANGED
@@ -2527,6 +2527,15 @@ function generateLrsBridgeCode(options) {
2527
2527
  ctx.extensions['http://xyleme.com/bravais/extensions/statement-schema'] = 'xyleme_10';
2528
2528
  ctx.extensions['http://xyleme.com/bravais/extensions/protect_pii'] = false;
2529
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
+
2530
2539
  return ctx;
2531
2540
  }
2532
2541
 
@@ -2571,18 +2580,110 @@ function generateLrsBridgeCode(options) {
2571
2580
 
2572
2581
  /**
2573
2582
  * Build activity object for questions in Xyleme format
2583
+ * Name format: "Assessment Name - Q#: Question text..."
2574
2584
  */
2575
2585
  function buildQuestionActivityObject(questionInfo) {
2576
2586
  var questionGuid = questionInfo.questionGuid || questionInfo.id || generateUUID();
2577
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
+
2578
2600
  return {
2579
2601
  objectType: 'Activity',
2580
2602
  id: 'http://xyleme.com/bravais/question/' + questionGuid,
2581
2603
  definition: {
2582
2604
  type: XYLEME_ACTIVITY_TYPES.question,
2583
- name: { 'en-US': questionInfo.text || questionInfo.questionText || 'Question' },
2605
+ name: { 'en-US': displayName },
2606
+ description: { 'en-US': questionText || 'Question' },
2584
2607
  extensions: {
2585
- resourceType: 'Question'
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 },
2684
+ extensions: {
2685
+ resourceType: 'Interaction',
2686
+ interactionType: interactionType
2586
2687
  }
2587
2688
  }
2588
2689
  };
@@ -2837,35 +2938,34 @@ function generateLrsBridgeCode(options) {
2837
2938
  sendStatement(statement);
2838
2939
  };
2839
2940
 
2840
- // Media events
2941
+ // Media events - uses activity-specific object with human-readable name
2942
+ // Parent context (added by buildXylemeContext) ensures document aggregation
2841
2943
  LRS.mediaPlayed = function(data) {
2842
2944
  if (!TRACK_MEDIA) return;
2843
2945
 
2844
2946
  // Get current lesson context
2845
2947
  var lessonInfo = getCachedLessonInfo();
2846
2948
 
2847
- var mediaType = data.type === 'audio' ? ACTIVITY_TYPES.audio : ACTIVITY_TYPES.video;
2848
2949
  var verbKey = data.action === 'play' ? 'played' :
2849
2950
  data.action === 'pause' ? 'paused' :
2850
2951
  data.action === 'completed' ? 'completed' : 'played';
2851
2952
 
2852
- // Activity type is video/audio, details include media info
2853
- var activityDetails = {
2854
- mediaSrc: data.src || 'media-' + Date.now(),
2855
- mediaName: data.name || (data.type || 'Media'),
2856
- mediaType: data.type || 'video',
2857
- 'https://w3id.org/xapi/video/extensions/length': data.duration || 0,
2858
- // Include lesson/section context
2859
- lessonId: lessonInfo.id,
2860
- lessonName: lessonInfo.name,
2861
- sectionName: lessonInfo.sectionName
2862
- };
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
+ });
2863
2962
 
2864
2963
  var result = {
2865
2964
  extensions: {
2866
2965
  'https://w3id.org/xapi/video/extensions/time': data.currentTime || 0,
2867
2966
  'https://w3id.org/xapi/video/extensions/progress': data.duration > 0 ?
2868
- 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
2869
2969
  }
2870
2970
  };
2871
2971
 
@@ -2873,7 +2973,16 @@ function generateLrsBridgeCode(options) {
2873
2973
  result.completion = true;
2874
2974
  }
2875
2975
 
2876
- 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);
2877
2986
  sendStatement(statement);
2878
2987
  };
2879
2988
 
@@ -3005,27 +3114,35 @@ function generateLrsBridgeCode(options) {
3005
3114
  LRS.assessmentEnded(data);
3006
3115
  };
3007
3116
 
3008
- // 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
3009
3120
  LRS.interacted = function(data) {
3010
3121
  if (!TRACK_INTERACTIONS) return;
3011
3122
 
3012
3123
  // Get current lesson context
3013
3124
  var lessonInfo = getCachedLessonInfo();
3014
3125
 
3015
- // Activity type is interaction, details include interaction ID and type
3016
- var statement = buildStatement(
3017
- 'interacted',
3018
- ACTIVITY_TYPES.interaction,
3019
- {
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: {
3020
3138
  interactionId: data.id || 'interaction-' + Date.now(),
3021
- interactionName: data.name || data.type || 'Interaction',
3022
- interactionType: data.interactionType || data.type || 'other',
3023
- // Include lesson/section context
3024
3139
  lessonId: lessonInfo.id,
3025
3140
  lessonName: lessonInfo.name,
3026
3141
  sectionName: lessonInfo.sectionName
3027
3142
  }
3028
- );
3143
+ };
3144
+
3145
+ var statement = buildStatementXyleme('interacted', interactionObject, null, additionalContext);
3029
3146
  sendStatement(statement);
3030
3147
  };
3031
3148