UNPKG

@lookit/lookit-initjspsych

Version:

This package overloads jsPsych's init function.

114 lines (104 loc) 3.73 kB
import Api from "@lookit/data"; import { JsPsychExpData, LookitWindow } from "@lookit/data/dist/types"; import chsTemplates from "@lookit/templates"; import { DataCollection, JsPsych } from "jspsych"; import { NoJsPsychInstanceError } from "./errors"; import { UserFuncOnDataUpdate, UserFuncOnFinish } from "./types"; declare let window: LookitWindow; /** * Function that returns a function to be used in place of jsPsych's option * "on_data_update". "userFunc" should be the user's implementation of * "on_data_update". Since this is the data that is returned from each trial, * this function will get the collected trial data and append the current data * point. * * @param jsPsychInstance - JsPsych instance * @param responseUuid - Response UUID. * @param userFunc - "on data update" function provided by researcher. * @returns On data update function. */ export const on_data_update = ( jsPsychInstance: JsPsych | undefined | null, responseUuid: string, userFunc?: UserFuncOnDataUpdate, ) => { return async function (data: JsPsychExpData) { if (!jsPsychInstance || !jsPsychInstance.data) { throw new NoJsPsychInstanceError(); } await Api.updateResponse(responseUuid, { exp_data: jsPsychInstance.data.get().values() as JsPsychExpData[], }); await Api.finish(); // Don't call the function if not defined by user. if (typeof userFunc === "function") { userFunc(data); } }; }; /** * Function that returns a function to be used in place of jsPsych's option * "on_finish". "userFunc" should be the user's implementation of "on_finish". * Since this is point where the experiment has ended, the function will set * "completed" to true and overwrites all experiment data with the full set of * collected data. Once the user function has been ran, this will redirect to * the study's exit url. * * @param jsPsychInstance - JsPsych instance * @param responseUuid - Response UUID. * @param userFunc - "on finish" function provided by the researcher. * @returns On finish function. */ export const on_finish = ( jsPsychInstance: JsPsych | undefined | null, responseUuid: string, userFunc?: UserFuncOnFinish, ) => { return async function (data: DataCollection) { // add loading animation while data/video saving finishes if (!jsPsychInstance || !jsPsychInstance.getDisplayElement) { throw new NoJsPsychInstanceError(); } jsPsychInstance.getDisplayElement().innerHTML = chsTemplates.loadingAnimation(); const exp_data: JsPsychExpData[] = data.values(); const { exit_url } = window.chs.study.attributes; // Don't call the function if not defined by user. if (typeof userFunc === "function") { userFunc(data); } try { await Api.updateResponse(responseUuid, { exp_data, completed: true, }); await Api.finish(); if (window.chs.pendingUploads) { await Promise.allSettled( window.chs.pendingUploads.map((u) => u.promise), ); } if (exit_url) { let url: URL; try { url = new URL(exit_url); } catch { try { url = new URL(`https://${exit_url}`); } catch { url = new URL(window.location.origin); } } const hash_child_id = window.chs.response.attributes.hash_child_id; if (hash_child_id) url.searchParams.set("child", hash_child_id); url.searchParams.set("response", window.chs.response.id); window.location.replace(url.toString()); } } catch (err) { console.error( "Error while finishing the experiment and saving data/video: ", err, ); } }; };