@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.cjs CHANGED
@@ -2871,6 +2871,15 @@ function generateLrsBridgeCode(options) {
2871
2871
  ctx.extensions['http://xyleme.com/bravais/extensions/statement-schema'] = 'xyleme_10';
2872
2872
  ctx.extensions['http://xyleme.com/bravais/extensions/protect_pii'] = false;
2873
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
+
2874
2883
  return ctx;
2875
2884
  }
2876
2885
 
@@ -2915,18 +2924,110 @@ function generateLrsBridgeCode(options) {
2915
2924
 
2916
2925
  /**
2917
2926
  * Build activity object for questions in Xyleme format
2927
+ * Name format: "Assessment Name - Q#: Question text..."
2918
2928
  */
2919
2929
  function buildQuestionActivityObject(questionInfo) {
2920
2930
  var questionGuid = questionInfo.questionGuid || questionInfo.id || generateUUID();
2921
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
+
2922
2944
  return {
2923
2945
  objectType: 'Activity',
2924
2946
  id: 'http://xyleme.com/bravais/question/' + questionGuid,
2925
2947
  definition: {
2926
2948
  type: XYLEME_ACTIVITY_TYPES.question,
2927
- name: { 'en-US': questionInfo.text || questionInfo.questionText || 'Question' },
2949
+ name: { 'en-US': displayName },
2950
+ description: { 'en-US': questionText || 'Question' },
2928
2951
  extensions: {
2929
- resourceType: 'Question'
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 },
3028
+ extensions: {
3029
+ resourceType: 'Interaction',
3030
+ interactionType: interactionType
2930
3031
  }
2931
3032
  }
2932
3033
  };
@@ -3181,35 +3282,34 @@ function generateLrsBridgeCode(options) {
3181
3282
  sendStatement(statement);
3182
3283
  };
3183
3284
 
3184
- // Media events
3285
+ // Media events - uses activity-specific object with human-readable name
3286
+ // Parent context (added by buildXylemeContext) ensures document aggregation
3185
3287
  LRS.mediaPlayed = function(data) {
3186
3288
  if (!TRACK_MEDIA) return;
3187
3289
 
3188
3290
  // Get current lesson context
3189
3291
  var lessonInfo = getCachedLessonInfo();
3190
3292
 
3191
- var mediaType = data.type === 'audio' ? ACTIVITY_TYPES.audio : ACTIVITY_TYPES.video;
3192
3293
  var verbKey = data.action === 'play' ? 'played' :
3193
3294
  data.action === 'pause' ? 'paused' :
3194
3295
  data.action === 'completed' ? 'completed' : 'played';
3195
3296
 
3196
- // Activity type is video/audio, details include media info
3197
- var activityDetails = {
3198
- mediaSrc: data.src || 'media-' + Date.now(),
3199
- mediaName: data.name || (data.type || 'Media'),
3200
- mediaType: data.type || 'video',
3201
- 'https://w3id.org/xapi/video/extensions/length': data.duration || 0,
3202
- // Include lesson/section context
3203
- lessonId: lessonInfo.id,
3204
- lessonName: lessonInfo.name,
3205
- sectionName: lessonInfo.sectionName
3206
- };
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
+ });
3207
3306
 
3208
3307
  var result = {
3209
3308
  extensions: {
3210
3309
  'https://w3id.org/xapi/video/extensions/time': data.currentTime || 0,
3211
3310
  'https://w3id.org/xapi/video/extensions/progress': data.duration > 0 ?
3212
- 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
3213
3313
  }
3214
3314
  };
3215
3315
 
@@ -3217,7 +3317,16 @@ function generateLrsBridgeCode(options) {
3217
3317
  result.completion = true;
3218
3318
  }
3219
3319
 
3220
- 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);
3221
3330
  sendStatement(statement);
3222
3331
  };
3223
3332
 
@@ -3349,27 +3458,35 @@ function generateLrsBridgeCode(options) {
3349
3458
  LRS.assessmentEnded(data);
3350
3459
  };
3351
3460
 
3352
- // 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
3353
3464
  LRS.interacted = function(data) {
3354
3465
  if (!TRACK_INTERACTIONS) return;
3355
3466
 
3356
3467
  // Get current lesson context
3357
3468
  var lessonInfo = getCachedLessonInfo();
3358
3469
 
3359
- // Activity type is interaction, details include interaction ID and type
3360
- var statement = buildStatement(
3361
- 'interacted',
3362
- ACTIVITY_TYPES.interaction,
3363
- {
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: {
3364
3482
  interactionId: data.id || 'interaction-' + Date.now(),
3365
- interactionName: data.name || data.type || 'Interaction',
3366
- interactionType: data.interactionType || data.type || 'other',
3367
- // Include lesson/section context
3368
3483
  lessonId: lessonInfo.id,
3369
3484
  lessonName: lessonInfo.name,
3370
3485
  sectionName: lessonInfo.sectionName
3371
3486
  }
3372
- );
3487
+ };
3488
+
3489
+ var statement = buildStatementXyleme('interacted', interactionObject, null, additionalContext);
3373
3490
  sendStatement(statement);
3374
3491
  };
3375
3492