@lookit/record 3.0.1 → 4.1.0

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
@@ -8,7 +8,7 @@ var Handlebars = require('handlebars');
8
8
 
9
9
  var _package = {
10
10
  name: "@lookit/record",
11
- version: "3.0.1",
11
+ version: "4.1.0",
12
12
  description: "Recording extensions and plugins for CHS studies.",
13
13
  homepage: "https://github.com/lookit/lookit-jspsych#readme",
14
14
  bugs: {
@@ -50,7 +50,7 @@ var _package = {
50
50
  },
51
51
  peerDependencies: {
52
52
  "@lookit/data": "^0.2.0",
53
- "@lookit/templates": "^2.0.0",
53
+ "@lookit/templates": "^2.1.0",
54
54
  jspsych: "^8.0.3"
55
55
  }
56
56
  };
@@ -143,21 +143,10 @@ class CreateURLError extends Error {
143
143
  this.name = "CreateURLError";
144
144
  }
145
145
  }
146
- class VideoContainerNotFoundError extends Error {
147
- constructor() {
148
- super("Video Container could not be found.");
149
- this.name = "VideoContainerError";
150
- }
151
- }
152
- class ButtonNotFoundError extends Error {
153
- constructor(id) {
154
- super(`"${id}" button not found.`);
155
- this.name = "ButtonNotFoundError";
156
- }
157
- }
158
- class ImageNotFoundError extends Error {
159
- constructor(id) {
160
- super(`"${id}" image not found.`);
146
+ class ElementNotFoundError extends Error {
147
+ constructor(id, tag) {
148
+ super(`"${id}" ${tag} not found.`);
149
+ this.name = "ElementNotFoundError";
161
150
  }
162
151
  }
163
152
 
@@ -270,9 +259,9 @@ class Recorder {
270
259
  this.recorder.stop();
271
260
  this.stream.getTracks().map((t) => t.stop());
272
261
  }
273
- stop() {
262
+ stop(maintain_container_size = false) {
263
+ this.clearWebcamFeed(maintain_container_size);
274
264
  this.stopTracks();
275
- this.clearWebcamFeed();
276
265
  if (!this.stopPromise) {
277
266
  throw new NoStopPromiseError();
278
267
  }
@@ -300,6 +289,7 @@ class Recorder {
300
289
  } else {
301
290
  await this.s3.completeUpload();
302
291
  }
292
+ this.reset();
303
293
  resolve();
304
294
  };
305
295
  }
@@ -317,11 +307,20 @@ class Recorder {
317
307
  link.click();
318
308
  }
319
309
  }
320
- clearWebcamFeed() {
310
+ clearWebcamFeed(maintain_container_size) {
321
311
  const webcam_feed_element = document.querySelector(
322
312
  `#${this.webcam_element_id}`
323
313
  );
324
314
  if (webcam_feed_element) {
315
+ if (maintain_container_size) {
316
+ const parent_div = webcam_feed_element.parentElement;
317
+ if (parent_div) {
318
+ const width = webcam_feed_element.offsetWidth;
319
+ const height = webcam_feed_element.offsetHeight;
320
+ parent_div.style.height = `${height}px`;
321
+ parent_div.style.width = `${width}px`;
322
+ }
323
+ }
325
324
  webcam_feed_element.remove();
326
325
  }
327
326
  }
@@ -385,12 +384,22 @@ const info$3 = {
385
384
  prompt_only_adults: { type: jspsych.ParameterType.BOOL, default: false },
386
385
  consent_statement_text: { type: jspsych.ParameterType.STRING, default: "" },
387
386
  omit_injury_phrase: { type: jspsych.ParameterType.BOOL, default: false }
387
+ },
388
+ data: {
389
+ chs_type: {
390
+ type: jspsych.ParameterType.STRING
391
+ }
388
392
  }
389
393
  };
390
394
  const _VideoConsentPlugin = class {
391
395
  constructor(jsPsych) {
392
396
  this.jsPsych = jsPsych;
393
397
  this.video_container_id = "lookit-jspsych-video-container";
398
+ this.msg_container_id = "lookit-jspsych-video-msg-container";
399
+ this.uploadingMsg = null;
400
+ this.startingMsg = null;
401
+ this.recordingMsg = null;
402
+ this.notRecordingMsg = null;
394
403
  this.jsPsych = jsPsych;
395
404
  this.recorder = new Recorder(this.jsPsych);
396
405
  }
@@ -402,13 +411,25 @@ const _VideoConsentPlugin = class {
402
411
  this.stopButton(display);
403
412
  this.playButton(display);
404
413
  this.nextButton(display);
414
+ this.uploadingMsg = chsTemplates.translateString(
415
+ "exp-lookit-video-consent.Stopping-and-uploading"
416
+ );
417
+ this.startingMsg = chsTemplates.translateString(
418
+ "exp-lookit-video-consent.Starting-recorder"
419
+ );
420
+ this.recordingMsg = chsTemplates.translateString(
421
+ "exp-lookit-video-consent.Recording"
422
+ );
423
+ this.notRecordingMsg = chsTemplates.translateString(
424
+ "exp-lookit-video-consent.Not-recording"
425
+ );
405
426
  }
406
427
  getVideoContainer(display) {
407
428
  const videoContainer = display.querySelector(
408
429
  `div#${this.video_container_id}`
409
430
  );
410
431
  if (!videoContainer) {
411
- throw new VideoContainerNotFoundError();
432
+ throw new ElementNotFoundError(this.video_container_id, "div");
412
433
  }
413
434
  return videoContainer;
414
435
  }
@@ -419,14 +440,31 @@ const _VideoConsentPlugin = class {
419
440
  }
420
441
  playbackFeed(display) {
421
442
  const videoContainer = this.getVideoContainer(display);
422
- this.recorder.insertPlaybackFeed(videoContainer, this.onEnded(display));
443
+ this.recorder.insertPlaybackFeed(
444
+ videoContainer,
445
+ this.onPlaybackEnded(display)
446
+ );
447
+ }
448
+ getMessageContainer(display) {
449
+ const msgContainer = display.querySelector(
450
+ `div#${this.msg_container_id}`
451
+ );
452
+ if (!msgContainer) {
453
+ throw new ElementNotFoundError(this.msg_container_id, "div");
454
+ }
455
+ return msgContainer;
456
+ }
457
+ addMessage(display, message) {
458
+ const msgContainer = this.getMessageContainer(display);
459
+ msgContainer.innerHTML = message;
423
460
  }
424
- onEnded(display) {
461
+ onPlaybackEnded(display) {
425
462
  return () => {
426
463
  const next = this.getButton(display, "next");
427
464
  const play = this.getButton(display, "play");
428
465
  const record = this.getButton(display, "record");
429
466
  this.recordFeed(display);
467
+ this.addMessage(display, this.notRecordingMsg);
430
468
  next.disabled = false;
431
469
  play.disabled = false;
432
470
  record.disabled = false;
@@ -435,14 +473,14 @@ const _VideoConsentPlugin = class {
435
473
  getButton(display, id) {
436
474
  const btn = display.querySelector(`button#${id}`);
437
475
  if (!btn) {
438
- throw new ButtonNotFoundError(id);
476
+ throw new ElementNotFoundError(id, "button");
439
477
  }
440
478
  return btn;
441
479
  }
442
480
  getImg(display, id) {
443
481
  const img = display.querySelector(`img#${id}`);
444
482
  if (!img) {
445
- throw new ImageNotFoundError(id);
483
+ throw new ElementNotFoundError(id, "img");
446
484
  }
447
485
  return img;
448
486
  }
@@ -452,12 +490,14 @@ const _VideoConsentPlugin = class {
452
490
  const play = this.getButton(display, "play");
453
491
  const next = this.getButton(display, "next");
454
492
  record.addEventListener("click", async () => {
493
+ this.addMessage(display, this.startingMsg);
455
494
  record.disabled = true;
456
- stop.disabled = false;
457
495
  play.disabled = true;
458
496
  next.disabled = true;
459
- this.getImg(display, "record-icon").style.visibility = "visible";
460
497
  await this.recorder.start(true, _VideoConsentPlugin.info.name);
498
+ this.getImg(display, "record-icon").style.visibility = "visible";
499
+ this.addMessage(display, this.recordingMsg);
500
+ stop.disabled = false;
461
501
  });
462
502
  }
463
503
  playButton(display) {
@@ -475,11 +515,13 @@ const _VideoConsentPlugin = class {
475
515
  const play = this.getButton(display, "play");
476
516
  stop.addEventListener("click", async () => {
477
517
  stop.disabled = true;
478
- record.disabled = false;
479
- play.disabled = false;
480
- await this.recorder.stop();
481
- this.recorder.reset();
518
+ this.addMessage(display, this.uploadingMsg);
519
+ await this.recorder.stop(true);
482
520
  this.recordFeed(display);
521
+ this.getImg(display, "record-icon").style.visibility = "hidden";
522
+ this.addMessage(display, this.notRecordingMsg);
523
+ play.disabled = false;
524
+ record.disabled = false;
483
525
  });
484
526
  }
485
527
  nextButton(display) {
@@ -499,7 +541,12 @@ const _VideoConsentPlugin = class {
499
541
  let VideoConsentPlugin = _VideoConsentPlugin;
500
542
  VideoConsentPlugin.info = info$3;
501
543
 
502
- const info$2 = { name: "start-record-plugin", parameters: {} };
544
+ const info$2 = {
545
+ name: "start-record-plugin",
546
+ version: _package.version,
547
+ parameters: {},
548
+ data: {}
549
+ };
503
550
  const _StartRecordPlugin = class {
504
551
  constructor(jsPsych) {
505
552
  this.jsPsych = jsPsych;
@@ -521,9 +568,18 @@ StartRecordPlugin.info = info$2;
521
568
 
522
569
  const info$1 = {
523
570
  name: "stop-record-plugin",
571
+ version: _package.version,
524
572
  parameters: {
525
- locale: { type: jspsych.ParameterType.STRING, default: "en-us" }
526
- }
573
+ wait_for_upload_message: {
574
+ type: jspsych.ParameterType.HTML_STRING,
575
+ default: null
576
+ },
577
+ locale: {
578
+ type: jspsych.ParameterType.STRING,
579
+ default: "en-us"
580
+ }
581
+ },
582
+ data: {}
527
583
  };
528
584
  class StopRecordPlugin {
529
585
  constructor(jsPsych) {
@@ -535,11 +591,17 @@ class StopRecordPlugin {
535
591
  }
536
592
  }
537
593
  trial(display_element, trial) {
538
- display_element.innerHTML = chsTemplates.uploadingVideo(trial);
594
+ if (trial.wait_for_upload_message == null) {
595
+ display_element.innerHTML = chsTemplates.uploadingVideo(trial);
596
+ } else {
597
+ display_element.innerHTML = trial.wait_for_upload_message;
598
+ }
539
599
  this.recorder.stop().then(() => {
540
600
  window.chs.sessionRecorder = null;
541
601
  display_element.innerHTML = "";
542
602
  this.jsPsych.finishTrial();
603
+ }).catch((err) => {
604
+ console.error("StopRecordPlugin: recorder stop/upload failed.", err);
543
605
  });
544
606
  }
545
607
  }
@@ -548,19 +610,50 @@ StopRecordPlugin.info = info$1;
548
610
  class TrialRecordExtension {
549
611
  constructor(jsPsych) {
550
612
  this.jsPsych = jsPsych;
613
+ this.uploadMsg = null;
614
+ this.locale = "en-us";
551
615
  autoBind(this);
552
616
  }
553
- async initialize() {
617
+ async initialize(params) {
618
+ await new Promise((resolve) => {
619
+ this.uploadMsg = params?.wait_for_upload_message ? params.wait_for_upload_message : null;
620
+ this.locale = params?.locale ? params.locale : "en-us";
621
+ console.log(this.uploadMsg);
622
+ console.log(this.locale);
623
+ resolve();
624
+ });
554
625
  }
555
- on_start() {
626
+ on_start(startParams) {
627
+ if (startParams?.wait_for_upload_message) {
628
+ this.uploadMsg = startParams.wait_for_upload_message;
629
+ }
630
+ if (startParams?.locale) {
631
+ this.locale = startParams.locale;
632
+ }
633
+ console.log(this.uploadMsg);
634
+ console.log(this.locale);
556
635
  this.recorder = new Recorder(this.jsPsych);
557
636
  }
558
637
  on_load() {
559
638
  this.pluginName = this.getCurrentPluginName();
560
639
  this.recorder?.start(false, `${this.pluginName}`);
561
640
  }
562
- on_finish() {
563
- this.recorder?.stop();
641
+ async on_finish() {
642
+ const displayEl = this.jsPsych.getDisplayElement();
643
+ if (this.uploadMsg == null) {
644
+ displayEl.innerHTML = chsTemplates.uploadingVideo({
645
+ type: this.jsPsych.getCurrentTrial().type,
646
+ locale: this.locale
647
+ });
648
+ } else {
649
+ displayEl.innerHTML = this.uploadMsg;
650
+ }
651
+ try {
652
+ await this.recorder?.stop();
653
+ displayEl.innerHTML = "";
654
+ } catch (err) {
655
+ console.error("TrialRecordExtension: recorder stop/upload failed.", err);
656
+ }
564
657
  return {};
565
658
  }
566
659
  getCurrentPluginName() {
@@ -569,7 +662,9 @@ class TrialRecordExtension {
569
662
  }
570
663
  }
571
664
  TrialRecordExtension.info = {
572
- name: "chs-trial-record-extension"
665
+ name: "chs-trial-record-extension",
666
+ version: _package.version,
667
+ data: {}
573
668
  };
574
669
 
575
670
  var img$6 = "data:image/png;base64,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";