@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.cjs CHANGED
@@ -2655,6 +2655,22 @@ function generateLrsBridgeCode(options) {
2655
2655
  // This allows filtering by type (video, assessment, interaction) in Analytics
2656
2656
  if (activityType) {
2657
2657
  courseObj.definition.type = activityType;
2658
+
2659
+ // Also update resourceType extension to human-readable form for Bravais Type column
2660
+ courseObj.definition.extensions = courseObj.definition.extensions || {};
2661
+ var resourceTypeMap = {
2662
+ 'https://w3id.org/xapi/video/activity-type/video': 'Video',
2663
+ 'https://w3id.org/xapi/audio/activity-type/audio': 'Audio',
2664
+ 'http://adlnet.gov/expapi/activities/media': 'Media',
2665
+ 'http://adlnet.gov/expapi/activities/assessment': 'Assessment',
2666
+ 'http://adlnet.gov/expapi/activities/question': 'Question',
2667
+ 'http://adlnet.gov/expapi/activities/interaction': 'Interaction',
2668
+ 'http://adlnet.gov/expapi/activities/lesson': 'Lesson',
2669
+ 'http://adlnet.gov/expapi/activities/module': 'Module',
2670
+ 'http://adlnet.gov/expapi/activities/course': 'Course',
2671
+ 'http://xyleme.com/bravais/activities/document': 'Course'
2672
+ };
2673
+ courseObj.definition.extensions['resourceType'] = resourceTypeMap[activityType] || 'Course';
2658
2674
  }
2659
2675
 
2660
2676
  // Add activity-specific details to extensions
@@ -2855,6 +2871,15 @@ function generateLrsBridgeCode(options) {
2855
2871
  ctx.extensions['http://xyleme.com/bravais/extensions/statement-schema'] = 'xyleme_10';
2856
2872
  ctx.extensions['http://xyleme.com/bravais/extensions/protect_pii'] = false;
2857
2873
 
2874
+ // Add parent course activity for document-level aggregation in Bravais
2875
+ // This allows statements with activity-specific objects to still be found
2876
+ // when searching by document name in Analytics
2877
+ var parentActivity = buildParentCourseActivity();
2878
+ if (parentActivity) {
2879
+ ctx.contextActivities = ctx.contextActivities || {};
2880
+ ctx.contextActivities.parent = [parentActivity];
2881
+ }
2882
+
2858
2883
  return ctx;
2859
2884
  }
2860
2885
 
@@ -2899,18 +2924,110 @@ function generateLrsBridgeCode(options) {
2899
2924
 
2900
2925
  /**
2901
2926
  * Build activity object for questions in Xyleme format
2927
+ * Name format: "Assessment Name - Q#: Question text..."
2902
2928
  */
2903
2929
  function buildQuestionActivityObject(questionInfo) {
2904
2930
  var questionGuid = questionInfo.questionGuid || questionInfo.id || generateUUID();
2905
2931
 
2932
+ // Build human-readable display name
2933
+ var displayName = (questionInfo.assessmentName || 'Knowledge Check');
2934
+ if (questionInfo.questionNumber) {
2935
+ displayName += ' - Q' + questionInfo.questionNumber;
2936
+ }
2937
+ var questionText = questionInfo.text || questionInfo.questionText || '';
2938
+ if (questionText.length > 50) {
2939
+ displayName += ': ' + questionText.substring(0, 47) + '...';
2940
+ } else if (questionText.length > 0) {
2941
+ displayName += ': ' + questionText;
2942
+ }
2943
+
2906
2944
  return {
2907
2945
  objectType: 'Activity',
2908
2946
  id: 'http://xyleme.com/bravais/question/' + questionGuid,
2909
2947
  definition: {
2910
2948
  type: XYLEME_ACTIVITY_TYPES.question,
2911
- name: { 'en-US': questionInfo.text || questionInfo.questionText || 'Question' },
2949
+ name: { 'en-US': displayName },
2950
+ description: { 'en-US': questionText || 'Question' },
2951
+ extensions: {
2952
+ resourceType: 'Question',
2953
+ questionNumber: questionInfo.questionNumber || null
2954
+ }
2955
+ }
2956
+ };
2957
+ }
2958
+
2959
+ /**
2960
+ * Build activity object for media (video/audio) with human-readable name
2961
+ * Name format: "Video: Title" or "Audio: Title"
2962
+ */
2963
+ function buildMediaActivityObject(mediaInfo) {
2964
+ var mediaGuid = mediaInfo.mediaGuid || generateUUID();
2965
+ var mediaType = mediaInfo.type === 'audio' ? ACTIVITY_TYPES.audio : ACTIVITY_TYPES.video;
2966
+ var resourceType = mediaInfo.type === 'audio' ? 'Audio' : 'Video';
2967
+
2968
+ // Build human-readable display name
2969
+ var displayName = mediaInfo.name || '';
2970
+ if (!displayName || displayName === 'video' || displayName === 'audio' || displayName === 'Media') {
2971
+ displayName = resourceType + ': ' + (mediaInfo.lessonName || 'Media');
2972
+ } else {
2973
+ displayName = resourceType + ': ' + displayName;
2974
+ }
2975
+
2976
+ return {
2977
+ objectType: 'Activity',
2978
+ id: 'http://xyleme.com/bravais/media/' + mediaGuid,
2979
+ definition: {
2980
+ type: mediaType,
2981
+ name: { 'en-US': displayName },
2982
+ extensions: {
2983
+ resourceType: resourceType,
2984
+ mediaSrc: mediaInfo.src || '',
2985
+ mediaType: mediaInfo.type || 'video',
2986
+ duration: mediaInfo.duration || 0
2987
+ }
2988
+ }
2989
+ };
2990
+ }
2991
+
2992
+ /**
2993
+ * Build activity object for interactions (tabs, accordions, flashcards, etc.)
2994
+ * Name format: "Tab: Label" or "Accordion: Label"
2995
+ */
2996
+ function buildInteractionActivityObject(interactionInfo) {
2997
+ var typeLabels = {
2998
+ 'tab': 'Tab',
2999
+ 'accordion': 'Accordion',
3000
+ 'flashcard': 'Flashcard',
3001
+ 'hotspot': 'Hotspot',
3002
+ 'process-step': 'Process Step',
3003
+ 'process': 'Process Step',
3004
+ 'sorting': 'Sorting Activity',
3005
+ 'button': 'Button',
3006
+ 'labeled-graphic': 'Labeled Graphic',
3007
+ 'timeline': 'Timeline',
3008
+ 'scenario': 'Scenario',
3009
+ 'checklist': 'Checklist',
3010
+ 'marker': 'Marker'
3011
+ };
3012
+
3013
+ var interactionType = interactionInfo.type || interactionInfo.interactionType || 'interaction';
3014
+ var typeLabel = typeLabels[interactionType] || 'Interaction';
3015
+
3016
+ // Build human-readable display name
3017
+ var displayName = interactionInfo.name;
3018
+ if (!displayName) {
3019
+ displayName = typeLabel + ': ' + (interactionInfo.label || interactionInfo.id || 'Item');
3020
+ }
3021
+
3022
+ return {
3023
+ objectType: 'Activity',
3024
+ id: 'http://xyleme.com/bravais/interaction/' + (interactionInfo.id || generateUUID()),
3025
+ definition: {
3026
+ type: ACTIVITY_TYPES.interaction,
3027
+ name: { 'en-US': displayName },
2912
3028
  extensions: {
2913
- resourceType: 'Question'
3029
+ resourceType: 'Interaction',
3030
+ interactionType: interactionType
2914
3031
  }
2915
3032
  }
2916
3033
  };
@@ -3165,35 +3282,34 @@ function generateLrsBridgeCode(options) {
3165
3282
  sendStatement(statement);
3166
3283
  };
3167
3284
 
3168
- // Media events
3285
+ // Media events - uses activity-specific object with human-readable name
3286
+ // Parent context (added by buildXylemeContext) ensures document aggregation
3169
3287
  LRS.mediaPlayed = function(data) {
3170
3288
  if (!TRACK_MEDIA) return;
3171
3289
 
3172
3290
  // Get current lesson context
3173
3291
  var lessonInfo = getCachedLessonInfo();
3174
3292
 
3175
- var mediaType = data.type === 'audio' ? ACTIVITY_TYPES.audio : ACTIVITY_TYPES.video;
3176
3293
  var verbKey = data.action === 'play' ? 'played' :
3177
3294
  data.action === 'pause' ? 'paused' :
3178
3295
  data.action === 'completed' ? 'completed' : 'played';
3179
3296
 
3180
- // Activity type is video/audio, details include media info
3181
- var activityDetails = {
3182
- mediaSrc: data.src || 'media-' + Date.now(),
3183
- mediaName: data.name || (data.type || 'Media'),
3184
- mediaType: data.type || 'video',
3185
- 'https://w3id.org/xapi/video/extensions/length': data.duration || 0,
3186
- // Include lesson/section context
3187
- lessonId: lessonInfo.id,
3188
- lessonName: lessonInfo.name,
3189
- sectionName: lessonInfo.sectionName
3190
- };
3297
+ // Build activity-specific object with human-readable name
3298
+ // e.g., "Video: Introduction" or "Audio: Podcast Episode 1"
3299
+ var mediaObject = buildMediaActivityObject({
3300
+ type: data.type,
3301
+ src: data.src,
3302
+ name: data.name,
3303
+ duration: data.duration,
3304
+ lessonName: lessonInfo.name
3305
+ });
3191
3306
 
3192
3307
  var result = {
3193
3308
  extensions: {
3194
3309
  'https://w3id.org/xapi/video/extensions/time': data.currentTime || 0,
3195
3310
  'https://w3id.org/xapi/video/extensions/progress': data.duration > 0 ?
3196
- Math.round((data.currentTime / data.duration) * 100) / 100 : 0
3311
+ Math.round((data.currentTime / data.duration) * 100) / 100 : 0,
3312
+ 'https://w3id.org/xapi/video/extensions/length': data.duration || 0
3197
3313
  }
3198
3314
  };
3199
3315
 
@@ -3201,7 +3317,16 @@ function generateLrsBridgeCode(options) {
3201
3317
  result.completion = true;
3202
3318
  }
3203
3319
 
3204
- var statement = buildStatement(verbKey, mediaType, activityDetails, result);
3320
+ // Context includes lesson info; parent course activity added by buildXylemeContext
3321
+ var additionalContext = {
3322
+ extensions: {
3323
+ lessonId: lessonInfo.id,
3324
+ lessonName: lessonInfo.name,
3325
+ sectionName: lessonInfo.sectionName
3326
+ }
3327
+ };
3328
+
3329
+ var statement = buildStatementXyleme(verbKey, mediaObject, result, additionalContext);
3205
3330
  sendStatement(statement);
3206
3331
  };
3207
3332
 
@@ -3333,27 +3458,35 @@ function generateLrsBridgeCode(options) {
3333
3458
  LRS.assessmentEnded(data);
3334
3459
  };
3335
3460
 
3336
- // Interactions (tabs, accordions, etc.)
3461
+ // Interactions (tabs, accordions, etc.) - uses activity-specific object
3462
+ // Object name shows the interaction type and label, e.g., "Tab: Overview"
3463
+ // Parent context ensures these appear in document search results
3337
3464
  LRS.interacted = function(data) {
3338
3465
  if (!TRACK_INTERACTIONS) return;
3339
3466
 
3340
3467
  // Get current lesson context
3341
3468
  var lessonInfo = getCachedLessonInfo();
3342
3469
 
3343
- // Activity type is interaction, details include interaction ID and type
3344
- var statement = buildStatement(
3345
- 'interacted',
3346
- ACTIVITY_TYPES.interaction,
3347
- {
3470
+ // Build activity-specific object with human-readable name
3471
+ // e.g., "Tab: Getting Started", "Accordion: FAQ"
3472
+ var interactionObject = buildInteractionActivityObject({
3473
+ type: data.type || data.interactionType,
3474
+ id: data.id,
3475
+ name: data.name,
3476
+ label: data.name || data.type
3477
+ });
3478
+
3479
+ // Context includes lesson info; parent course activity added by buildXylemeContext
3480
+ var additionalContext = {
3481
+ extensions: {
3348
3482
  interactionId: data.id || 'interaction-' + Date.now(),
3349
- interactionName: data.name || data.type || 'Interaction',
3350
- interactionType: data.interactionType || data.type || 'other',
3351
- // Include lesson/section context
3352
3483
  lessonId: lessonInfo.id,
3353
3484
  lessonName: lessonInfo.name,
3354
3485
  sectionName: lessonInfo.sectionName
3355
3486
  }
3356
- );
3487
+ };
3488
+
3489
+ var statement = buildStatementXyleme('interacted', interactionObject, null, additionalContext);
3357
3490
  sendStatement(statement);
3358
3491
  };
3359
3492