@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.cjs CHANGED
@@ -2319,6 +2319,22 @@ function generateLrsBridgeCode(options) {
2319
2319
  // This allows filtering by type (video, assessment, interaction) in Analytics
2320
2320
  if (activityType) {
2321
2321
  courseObj.definition.type = activityType;
2322
+
2323
+ // Also update resourceType extension to human-readable form for Bravais Type column
2324
+ courseObj.definition.extensions = courseObj.definition.extensions || {};
2325
+ var resourceTypeMap = {
2326
+ 'https://w3id.org/xapi/video/activity-type/video': 'Video',
2327
+ 'https://w3id.org/xapi/audio/activity-type/audio': 'Audio',
2328
+ 'http://adlnet.gov/expapi/activities/media': 'Media',
2329
+ 'http://adlnet.gov/expapi/activities/assessment': 'Assessment',
2330
+ 'http://adlnet.gov/expapi/activities/question': 'Question',
2331
+ 'http://adlnet.gov/expapi/activities/interaction': 'Interaction',
2332
+ 'http://adlnet.gov/expapi/activities/lesson': 'Lesson',
2333
+ 'http://adlnet.gov/expapi/activities/module': 'Module',
2334
+ 'http://adlnet.gov/expapi/activities/course': 'Course',
2335
+ 'http://xyleme.com/bravais/activities/document': 'Course'
2336
+ };
2337
+ courseObj.definition.extensions['resourceType'] = resourceTypeMap[activityType] || 'Course';
2322
2338
  }
2323
2339
 
2324
2340
  // Add activity-specific details to extensions
@@ -2519,6 +2535,15 @@ function generateLrsBridgeCode(options) {
2519
2535
  ctx.extensions['http://xyleme.com/bravais/extensions/statement-schema'] = 'xyleme_10';
2520
2536
  ctx.extensions['http://xyleme.com/bravais/extensions/protect_pii'] = false;
2521
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
+
2522
2547
  return ctx;
2523
2548
  }
2524
2549
 
@@ -2563,18 +2588,110 @@ function generateLrsBridgeCode(options) {
2563
2588
 
2564
2589
  /**
2565
2590
  * Build activity object for questions in Xyleme format
2591
+ * Name format: "Assessment Name - Q#: Question text..."
2566
2592
  */
2567
2593
  function buildQuestionActivityObject(questionInfo) {
2568
2594
  var questionGuid = questionInfo.questionGuid || questionInfo.id || generateUUID();
2569
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
+
2570
2608
  return {
2571
2609
  objectType: 'Activity',
2572
2610
  id: 'http://xyleme.com/bravais/question/' + questionGuid,
2573
2611
  definition: {
2574
2612
  type: XYLEME_ACTIVITY_TYPES.question,
2575
- name: { 'en-US': questionInfo.text || questionInfo.questionText || 'Question' },
2613
+ name: { 'en-US': displayName },
2614
+ description: { 'en-US': questionText || 'Question' },
2615
+ extensions: {
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 },
2576
2692
  extensions: {
2577
- resourceType: 'Question'
2693
+ resourceType: 'Interaction',
2694
+ interactionType: interactionType
2578
2695
  }
2579
2696
  }
2580
2697
  };
@@ -2829,35 +2946,34 @@ function generateLrsBridgeCode(options) {
2829
2946
  sendStatement(statement);
2830
2947
  };
2831
2948
 
2832
- // Media events
2949
+ // Media events - uses activity-specific object with human-readable name
2950
+ // Parent context (added by buildXylemeContext) ensures document aggregation
2833
2951
  LRS.mediaPlayed = function(data) {
2834
2952
  if (!TRACK_MEDIA) return;
2835
2953
 
2836
2954
  // Get current lesson context
2837
2955
  var lessonInfo = getCachedLessonInfo();
2838
2956
 
2839
- var mediaType = data.type === 'audio' ? ACTIVITY_TYPES.audio : ACTIVITY_TYPES.video;
2840
2957
  var verbKey = data.action === 'play' ? 'played' :
2841
2958
  data.action === 'pause' ? 'paused' :
2842
2959
  data.action === 'completed' ? 'completed' : 'played';
2843
2960
 
2844
- // Activity type is video/audio, details include media info
2845
- var activityDetails = {
2846
- mediaSrc: data.src || 'media-' + Date.now(),
2847
- mediaName: data.name || (data.type || 'Media'),
2848
- mediaType: data.type || 'video',
2849
- 'https://w3id.org/xapi/video/extensions/length': data.duration || 0,
2850
- // Include lesson/section context
2851
- lessonId: lessonInfo.id,
2852
- lessonName: lessonInfo.name,
2853
- sectionName: lessonInfo.sectionName
2854
- };
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
+ });
2855
2970
 
2856
2971
  var result = {
2857
2972
  extensions: {
2858
2973
  'https://w3id.org/xapi/video/extensions/time': data.currentTime || 0,
2859
2974
  'https://w3id.org/xapi/video/extensions/progress': data.duration > 0 ?
2860
- 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
2861
2977
  }
2862
2978
  };
2863
2979
 
@@ -2865,7 +2981,16 @@ function generateLrsBridgeCode(options) {
2865
2981
  result.completion = true;
2866
2982
  }
2867
2983
 
2868
- 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);
2869
2994
  sendStatement(statement);
2870
2995
  };
2871
2996
 
@@ -2997,27 +3122,35 @@ function generateLrsBridgeCode(options) {
2997
3122
  LRS.assessmentEnded(data);
2998
3123
  };
2999
3124
 
3000
- // 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
3001
3128
  LRS.interacted = function(data) {
3002
3129
  if (!TRACK_INTERACTIONS) return;
3003
3130
 
3004
3131
  // Get current lesson context
3005
3132
  var lessonInfo = getCachedLessonInfo();
3006
3133
 
3007
- // Activity type is interaction, details include interaction ID and type
3008
- var statement = buildStatement(
3009
- 'interacted',
3010
- ACTIVITY_TYPES.interaction,
3011
- {
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: {
3012
3146
  interactionId: data.id || 'interaction-' + Date.now(),
3013
- interactionName: data.name || data.type || 'Interaction',
3014
- interactionType: data.interactionType || data.type || 'other',
3015
- // Include lesson/section context
3016
3147
  lessonId: lessonInfo.id,
3017
3148
  lessonName: lessonInfo.name,
3018
3149
  sectionName: lessonInfo.sectionName
3019
3150
  }
3020
- );
3151
+ };
3152
+
3153
+ var statement = buildStatementXyleme('interacted', interactionObject, null, additionalContext);
3021
3154
  sendStatement(statement);
3022
3155
  };
3023
3156