@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/cli.js CHANGED
@@ -2646,6 +2646,22 @@ function generateLrsBridgeCode(options) {
2646
2646
  // This allows filtering by type (video, assessment, interaction) in Analytics
2647
2647
  if (activityType) {
2648
2648
  courseObj.definition.type = activityType;
2649
+
2650
+ // Also update resourceType extension to human-readable form for Bravais Type column
2651
+ courseObj.definition.extensions = courseObj.definition.extensions || {};
2652
+ var resourceTypeMap = {
2653
+ 'https://w3id.org/xapi/video/activity-type/video': 'Video',
2654
+ 'https://w3id.org/xapi/audio/activity-type/audio': 'Audio',
2655
+ 'http://adlnet.gov/expapi/activities/media': 'Media',
2656
+ 'http://adlnet.gov/expapi/activities/assessment': 'Assessment',
2657
+ 'http://adlnet.gov/expapi/activities/question': 'Question',
2658
+ 'http://adlnet.gov/expapi/activities/interaction': 'Interaction',
2659
+ 'http://adlnet.gov/expapi/activities/lesson': 'Lesson',
2660
+ 'http://adlnet.gov/expapi/activities/module': 'Module',
2661
+ 'http://adlnet.gov/expapi/activities/course': 'Course',
2662
+ 'http://xyleme.com/bravais/activities/document': 'Course'
2663
+ };
2664
+ courseObj.definition.extensions['resourceType'] = resourceTypeMap[activityType] || 'Course';
2649
2665
  }
2650
2666
 
2651
2667
  // Add activity-specific details to extensions
@@ -2846,6 +2862,15 @@ function generateLrsBridgeCode(options) {
2846
2862
  ctx.extensions['http://xyleme.com/bravais/extensions/statement-schema'] = 'xyleme_10';
2847
2863
  ctx.extensions['http://xyleme.com/bravais/extensions/protect_pii'] = false;
2848
2864
 
2865
+ // Add parent course activity for document-level aggregation in Bravais
2866
+ // This allows statements with activity-specific objects to still be found
2867
+ // when searching by document name in Analytics
2868
+ var parentActivity = buildParentCourseActivity();
2869
+ if (parentActivity) {
2870
+ ctx.contextActivities = ctx.contextActivities || {};
2871
+ ctx.contextActivities.parent = [parentActivity];
2872
+ }
2873
+
2849
2874
  return ctx;
2850
2875
  }
2851
2876
 
@@ -2890,18 +2915,110 @@ function generateLrsBridgeCode(options) {
2890
2915
 
2891
2916
  /**
2892
2917
  * Build activity object for questions in Xyleme format
2918
+ * Name format: "Assessment Name - Q#: Question text..."
2893
2919
  */
2894
2920
  function buildQuestionActivityObject(questionInfo) {
2895
2921
  var questionGuid = questionInfo.questionGuid || questionInfo.id || generateUUID();
2896
2922
 
2923
+ // Build human-readable display name
2924
+ var displayName = (questionInfo.assessmentName || 'Knowledge Check');
2925
+ if (questionInfo.questionNumber) {
2926
+ displayName += ' - Q' + questionInfo.questionNumber;
2927
+ }
2928
+ var questionText = questionInfo.text || questionInfo.questionText || '';
2929
+ if (questionText.length > 50) {
2930
+ displayName += ': ' + questionText.substring(0, 47) + '...';
2931
+ } else if (questionText.length > 0) {
2932
+ displayName += ': ' + questionText;
2933
+ }
2934
+
2897
2935
  return {
2898
2936
  objectType: 'Activity',
2899
2937
  id: 'http://xyleme.com/bravais/question/' + questionGuid,
2900
2938
  definition: {
2901
2939
  type: XYLEME_ACTIVITY_TYPES.question,
2902
- name: { 'en-US': questionInfo.text || questionInfo.questionText || 'Question' },
2940
+ name: { 'en-US': displayName },
2941
+ description: { 'en-US': questionText || 'Question' },
2942
+ extensions: {
2943
+ resourceType: 'Question',
2944
+ questionNumber: questionInfo.questionNumber || null
2945
+ }
2946
+ }
2947
+ };
2948
+ }
2949
+
2950
+ /**
2951
+ * Build activity object for media (video/audio) with human-readable name
2952
+ * Name format: "Video: Title" or "Audio: Title"
2953
+ */
2954
+ function buildMediaActivityObject(mediaInfo) {
2955
+ var mediaGuid = mediaInfo.mediaGuid || generateUUID();
2956
+ var mediaType = mediaInfo.type === 'audio' ? ACTIVITY_TYPES.audio : ACTIVITY_TYPES.video;
2957
+ var resourceType = mediaInfo.type === 'audio' ? 'Audio' : 'Video';
2958
+
2959
+ // Build human-readable display name
2960
+ var displayName = mediaInfo.name || '';
2961
+ if (!displayName || displayName === 'video' || displayName === 'audio' || displayName === 'Media') {
2962
+ displayName = resourceType + ': ' + (mediaInfo.lessonName || 'Media');
2963
+ } else {
2964
+ displayName = resourceType + ': ' + displayName;
2965
+ }
2966
+
2967
+ return {
2968
+ objectType: 'Activity',
2969
+ id: 'http://xyleme.com/bravais/media/' + mediaGuid,
2970
+ definition: {
2971
+ type: mediaType,
2972
+ name: { 'en-US': displayName },
2973
+ extensions: {
2974
+ resourceType: resourceType,
2975
+ mediaSrc: mediaInfo.src || '',
2976
+ mediaType: mediaInfo.type || 'video',
2977
+ duration: mediaInfo.duration || 0
2978
+ }
2979
+ }
2980
+ };
2981
+ }
2982
+
2983
+ /**
2984
+ * Build activity object for interactions (tabs, accordions, flashcards, etc.)
2985
+ * Name format: "Tab: Label" or "Accordion: Label"
2986
+ */
2987
+ function buildInteractionActivityObject(interactionInfo) {
2988
+ var typeLabels = {
2989
+ 'tab': 'Tab',
2990
+ 'accordion': 'Accordion',
2991
+ 'flashcard': 'Flashcard',
2992
+ 'hotspot': 'Hotspot',
2993
+ 'process-step': 'Process Step',
2994
+ 'process': 'Process Step',
2995
+ 'sorting': 'Sorting Activity',
2996
+ 'button': 'Button',
2997
+ 'labeled-graphic': 'Labeled Graphic',
2998
+ 'timeline': 'Timeline',
2999
+ 'scenario': 'Scenario',
3000
+ 'checklist': 'Checklist',
3001
+ 'marker': 'Marker'
3002
+ };
3003
+
3004
+ var interactionType = interactionInfo.type || interactionInfo.interactionType || 'interaction';
3005
+ var typeLabel = typeLabels[interactionType] || 'Interaction';
3006
+
3007
+ // Build human-readable display name
3008
+ var displayName = interactionInfo.name;
3009
+ if (!displayName) {
3010
+ displayName = typeLabel + ': ' + (interactionInfo.label || interactionInfo.id || 'Item');
3011
+ }
3012
+
3013
+ return {
3014
+ objectType: 'Activity',
3015
+ id: 'http://xyleme.com/bravais/interaction/' + (interactionInfo.id || generateUUID()),
3016
+ definition: {
3017
+ type: ACTIVITY_TYPES.interaction,
3018
+ name: { 'en-US': displayName },
2903
3019
  extensions: {
2904
- resourceType: 'Question'
3020
+ resourceType: 'Interaction',
3021
+ interactionType: interactionType
2905
3022
  }
2906
3023
  }
2907
3024
  };
@@ -3156,35 +3273,34 @@ function generateLrsBridgeCode(options) {
3156
3273
  sendStatement(statement);
3157
3274
  };
3158
3275
 
3159
- // Media events
3276
+ // Media events - uses activity-specific object with human-readable name
3277
+ // Parent context (added by buildXylemeContext) ensures document aggregation
3160
3278
  LRS.mediaPlayed = function(data) {
3161
3279
  if (!TRACK_MEDIA) return;
3162
3280
 
3163
3281
  // Get current lesson context
3164
3282
  var lessonInfo = getCachedLessonInfo();
3165
3283
 
3166
- var mediaType = data.type === 'audio' ? ACTIVITY_TYPES.audio : ACTIVITY_TYPES.video;
3167
3284
  var verbKey = data.action === 'play' ? 'played' :
3168
3285
  data.action === 'pause' ? 'paused' :
3169
3286
  data.action === 'completed' ? 'completed' : 'played';
3170
3287
 
3171
- // Activity type is video/audio, details include media info
3172
- var activityDetails = {
3173
- mediaSrc: data.src || 'media-' + Date.now(),
3174
- mediaName: data.name || (data.type || 'Media'),
3175
- mediaType: data.type || 'video',
3176
- 'https://w3id.org/xapi/video/extensions/length': data.duration || 0,
3177
- // Include lesson/section context
3178
- lessonId: lessonInfo.id,
3179
- lessonName: lessonInfo.name,
3180
- sectionName: lessonInfo.sectionName
3181
- };
3288
+ // Build activity-specific object with human-readable name
3289
+ // e.g., "Video: Introduction" or "Audio: Podcast Episode 1"
3290
+ var mediaObject = buildMediaActivityObject({
3291
+ type: data.type,
3292
+ src: data.src,
3293
+ name: data.name,
3294
+ duration: data.duration,
3295
+ lessonName: lessonInfo.name
3296
+ });
3182
3297
 
3183
3298
  var result = {
3184
3299
  extensions: {
3185
3300
  'https://w3id.org/xapi/video/extensions/time': data.currentTime || 0,
3186
3301
  'https://w3id.org/xapi/video/extensions/progress': data.duration > 0 ?
3187
- Math.round((data.currentTime / data.duration) * 100) / 100 : 0
3302
+ Math.round((data.currentTime / data.duration) * 100) / 100 : 0,
3303
+ 'https://w3id.org/xapi/video/extensions/length': data.duration || 0
3188
3304
  }
3189
3305
  };
3190
3306
 
@@ -3192,7 +3308,16 @@ function generateLrsBridgeCode(options) {
3192
3308
  result.completion = true;
3193
3309
  }
3194
3310
 
3195
- var statement = buildStatement(verbKey, mediaType, activityDetails, result);
3311
+ // Context includes lesson info; parent course activity added by buildXylemeContext
3312
+ var additionalContext = {
3313
+ extensions: {
3314
+ lessonId: lessonInfo.id,
3315
+ lessonName: lessonInfo.name,
3316
+ sectionName: lessonInfo.sectionName
3317
+ }
3318
+ };
3319
+
3320
+ var statement = buildStatementXyleme(verbKey, mediaObject, result, additionalContext);
3196
3321
  sendStatement(statement);
3197
3322
  };
3198
3323
 
@@ -3324,27 +3449,35 @@ function generateLrsBridgeCode(options) {
3324
3449
  LRS.assessmentEnded(data);
3325
3450
  };
3326
3451
 
3327
- // Interactions (tabs, accordions, etc.)
3452
+ // Interactions (tabs, accordions, etc.) - uses activity-specific object
3453
+ // Object name shows the interaction type and label, e.g., "Tab: Overview"
3454
+ // Parent context ensures these appear in document search results
3328
3455
  LRS.interacted = function(data) {
3329
3456
  if (!TRACK_INTERACTIONS) return;
3330
3457
 
3331
3458
  // Get current lesson context
3332
3459
  var lessonInfo = getCachedLessonInfo();
3333
3460
 
3334
- // Activity type is interaction, details include interaction ID and type
3335
- var statement = buildStatement(
3336
- 'interacted',
3337
- ACTIVITY_TYPES.interaction,
3338
- {
3461
+ // Build activity-specific object with human-readable name
3462
+ // e.g., "Tab: Getting Started", "Accordion: FAQ"
3463
+ var interactionObject = buildInteractionActivityObject({
3464
+ type: data.type || data.interactionType,
3465
+ id: data.id,
3466
+ name: data.name,
3467
+ label: data.name || data.type
3468
+ });
3469
+
3470
+ // Context includes lesson info; parent course activity added by buildXylemeContext
3471
+ var additionalContext = {
3472
+ extensions: {
3339
3473
  interactionId: data.id || 'interaction-' + Date.now(),
3340
- interactionName: data.name || data.type || 'Interaction',
3341
- interactionType: data.interactionType || data.type || 'other',
3342
- // Include lesson/section context
3343
3474
  lessonId: lessonInfo.id,
3344
3475
  lessonName: lessonInfo.name,
3345
3476
  sectionName: lessonInfo.sectionName
3346
3477
  }
3347
- );
3478
+ };
3479
+
3480
+ var statement = buildStatementXyleme('interacted', interactionObject, null, additionalContext);
3348
3481
  sendStatement(statement);
3349
3482
  };
3350
3483