@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/cli.js CHANGED
@@ -2862,6 +2862,15 @@ function generateLrsBridgeCode(options) {
2862
2862
  ctx.extensions['http://xyleme.com/bravais/extensions/statement-schema'] = 'xyleme_10';
2863
2863
  ctx.extensions['http://xyleme.com/bravais/extensions/protect_pii'] = false;
2864
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
+
2865
2874
  return ctx;
2866
2875
  }
2867
2876
 
@@ -2906,18 +2915,110 @@ function generateLrsBridgeCode(options) {
2906
2915
 
2907
2916
  /**
2908
2917
  * Build activity object for questions in Xyleme format
2918
+ * Name format: "Assessment Name - Q#: Question text..."
2909
2919
  */
2910
2920
  function buildQuestionActivityObject(questionInfo) {
2911
2921
  var questionGuid = questionInfo.questionGuid || questionInfo.id || generateUUID();
2912
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
+
2913
2935
  return {
2914
2936
  objectType: 'Activity',
2915
2937
  id: 'http://xyleme.com/bravais/question/' + questionGuid,
2916
2938
  definition: {
2917
2939
  type: XYLEME_ACTIVITY_TYPES.question,
2918
- name: { 'en-US': questionInfo.text || questionInfo.questionText || 'Question' },
2940
+ name: { 'en-US': displayName },
2941
+ description: { 'en-US': questionText || 'Question' },
2919
2942
  extensions: {
2920
- resourceType: 'Question'
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 },
3019
+ extensions: {
3020
+ resourceType: 'Interaction',
3021
+ interactionType: interactionType
2921
3022
  }
2922
3023
  }
2923
3024
  };
@@ -3172,35 +3273,34 @@ function generateLrsBridgeCode(options) {
3172
3273
  sendStatement(statement);
3173
3274
  };
3174
3275
 
3175
- // Media events
3276
+ // Media events - uses activity-specific object with human-readable name
3277
+ // Parent context (added by buildXylemeContext) ensures document aggregation
3176
3278
  LRS.mediaPlayed = function(data) {
3177
3279
  if (!TRACK_MEDIA) return;
3178
3280
 
3179
3281
  // Get current lesson context
3180
3282
  var lessonInfo = getCachedLessonInfo();
3181
3283
 
3182
- var mediaType = data.type === 'audio' ? ACTIVITY_TYPES.audio : ACTIVITY_TYPES.video;
3183
3284
  var verbKey = data.action === 'play' ? 'played' :
3184
3285
  data.action === 'pause' ? 'paused' :
3185
3286
  data.action === 'completed' ? 'completed' : 'played';
3186
3287
 
3187
- // Activity type is video/audio, details include media info
3188
- var activityDetails = {
3189
- mediaSrc: data.src || 'media-' + Date.now(),
3190
- mediaName: data.name || (data.type || 'Media'),
3191
- mediaType: data.type || 'video',
3192
- 'https://w3id.org/xapi/video/extensions/length': data.duration || 0,
3193
- // Include lesson/section context
3194
- lessonId: lessonInfo.id,
3195
- lessonName: lessonInfo.name,
3196
- sectionName: lessonInfo.sectionName
3197
- };
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
+ });
3198
3297
 
3199
3298
  var result = {
3200
3299
  extensions: {
3201
3300
  'https://w3id.org/xapi/video/extensions/time': data.currentTime || 0,
3202
3301
  'https://w3id.org/xapi/video/extensions/progress': data.duration > 0 ?
3203
- 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
3204
3304
  }
3205
3305
  };
3206
3306
 
@@ -3208,7 +3308,16 @@ function generateLrsBridgeCode(options) {
3208
3308
  result.completion = true;
3209
3309
  }
3210
3310
 
3211
- 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);
3212
3321
  sendStatement(statement);
3213
3322
  };
3214
3323
 
@@ -3340,27 +3449,35 @@ function generateLrsBridgeCode(options) {
3340
3449
  LRS.assessmentEnded(data);
3341
3450
  };
3342
3451
 
3343
- // 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
3344
3455
  LRS.interacted = function(data) {
3345
3456
  if (!TRACK_INTERACTIONS) return;
3346
3457
 
3347
3458
  // Get current lesson context
3348
3459
  var lessonInfo = getCachedLessonInfo();
3349
3460
 
3350
- // Activity type is interaction, details include interaction ID and type
3351
- var statement = buildStatement(
3352
- 'interacted',
3353
- ACTIVITY_TYPES.interaction,
3354
- {
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: {
3355
3473
  interactionId: data.id || 'interaction-' + Date.now(),
3356
- interactionName: data.name || data.type || 'Interaction',
3357
- interactionType: data.interactionType || data.type || 'other',
3358
- // Include lesson/section context
3359
3474
  lessonId: lessonInfo.id,
3360
3475
  lessonName: lessonInfo.name,
3361
3476
  sectionName: lessonInfo.sectionName
3362
3477
  }
3363
- );
3478
+ };
3479
+
3480
+ var statement = buildStatementXyleme('interacted', interactionObject, null, additionalContext);
3364
3481
  sendStatement(statement);
3365
3482
  };
3366
3483