From 5f718ba61cb19268d8ff71fd30aea60479a6312e Mon Sep 17 00:00:00 2001 From: Seth Bashford Date: Tue, 25 Jan 2022 10:45:59 -0600 Subject: [PATCH] accomodate version 7 --- jspsych/main.js | 517 +++++++++++++++++++++++----------------------- jspsych/plugin.js | 155 +++++++++----- 2 files changed, 366 insertions(+), 306 deletions(-) diff --git a/jspsych/main.js b/jspsych/main.js index b51413b..31b7e1b 100644 --- a/jspsych/main.js +++ b/jspsych/main.js @@ -1,12 +1,14 @@ import { trialsWithProgress } from "../lib/progress.js"; import { plugin, twoSizesPlugin } from "./plugin.js"; -const tokenTestPluginId = "token-test"; -const twoSizesTokenTestPluginId = "two-sizes-token-test"; -jsPsych.plugins[tokenTestPluginId] = plugin(tokenTestPluginId); -jsPsych.plugins[twoSizesTokenTestPluginId] = twoSizesPlugin( - twoSizesTokenTestPluginId -); +const jsPsych = initJsPsych({ + on_finish() { + window.close(); + }, +}); + +const tokenPlugin = plugin(jsPsychModule); +const sizedTokenPlugin = twoSizesPlugin(jsPsychModule); function audioResourcePath(stem) { return `${tokenResourcePath}/${stem}.wav`; @@ -30,273 +32,268 @@ function commonTokenTrialWithFeedback(sentenceNumber, sentence, commandString) { function sizedTokenTrialWithFeedback(sentenceNumber, sentence, commandString) { return { - type: twoSizesTokenTestPluginId, + type: sizedTokenPlugin, ...commonTokenTrialWithFeedback(sentenceNumber, sentence, commandString), }; } function tokenTrialWithFeedback(sentenceNumber, sentence, commandString) { return { - type: tokenTestPluginId, + type: tokenPlugin, ...commonTokenTrialWithFeedback(sentenceNumber, sentence, commandString), boxUrl: `${tokenResourcePath}/box.jpg`, }; } -jsPsych.init({ - timeline: [ - { - type: "preload", - auto_preload: true, - }, - { - type: "survey-text", - questions: [ - { - prompt: "If the ID displayed is not correct, please enter it now.", - placeholder: jsPsych.data.urlVariables().subjectID, - }, - ], - preamble: "", - button_label: "Click to enter ID", - }, - { - type: "html-button-response", - stimulus: - "This task requires you to listen to a sentence and then do the actions given in the sentence. You will see squares and circles of different colors and sizes. Use your mouse to follow the directions the best you can. Some of the trials will be easy and some may be hard.", - choices: ["Start"], - }, - { - timeline: trialsWithProgress([ - sizedTokenTrialWithFeedback( - 1, - "Click on the large white circle and the small orange square.", - "touch large white circle, touch small orange square" - ), - sizedTokenTrialWithFeedback( - 2, - "Click on the small blue circle and the large brown square.", - "touch small blue circle, touch large brown square" - ), - sizedTokenTrialWithFeedback( - 3, - "Click on the large orange square and the large red square.", - "touch large orange square, touch large red square" - ), - sizedTokenTrialWithFeedback( - 4, - "Click on the large white square and the small orange circle.", - "touch large white square, touch small orange circle" - ), - tokenTrialWithFeedback( - 5, - "Put the red circle on the orange square.", - "use red circle to touch orange square" - ), - tokenTrialWithFeedback( - 6, - "Touch the blue circle with the red square.", - "use red square to touch blue circle" - ), - tokenTrialWithFeedback( - 7, - "Click on the blue circle and the red square.", - "touch blue circle, touch red square" - ), - tokenTrialWithFeedback( - 8, - "Drag the blue circle or the red square to the box.", - "pick up blue circle or pick up red square" - ), - tokenTrialWithFeedback( - 9, - "Move the orange square away from the brown square.", - "move orange square away from brown square" - ), - tokenTrialWithFeedback( - 10, - "If there is a black circle, drag the red square to the box", - "nothing" - ), +jsPsych.run([ + { + type: jsPsychPreload, + auto_preload: true, + }, + { + type: jsPsychSurveyText, + questions: [ + { + prompt: "If the ID displayed is not correct, please enter it now.", + placeholder: jsPsych.data.urlVariables().subjectID, + }, + ], + preamble: "", + button_label: "Click to enter ID", + }, + { + type: jsPsychHtmlButtonResponse, + stimulus: + "This task requires you to listen to a sentence and then do the actions given in the sentence. You will see squares and circles of different colors and sizes. Use your mouse to follow the directions the best you can. Some of the trials will be easy and some may be hard.", + choices: ["Start"], + }, + { + timeline: trialsWithProgress([ + sizedTokenTrialWithFeedback( + 1, + "Click on the large white circle and the small orange square.", + "touch large white circle, touch small orange square" + ), + sizedTokenTrialWithFeedback( + 2, + "Click on the small blue circle and the large brown square.", + "touch small blue circle, touch large brown square" + ), + sizedTokenTrialWithFeedback( + 3, + "Click on the large orange square and the large red square.", + "touch large orange square, touch large red square" + ), + sizedTokenTrialWithFeedback( + 4, + "Click on the large white square and the small orange circle.", + "touch large white square, touch small orange circle" + ), + tokenTrialWithFeedback( + 5, + "Put the red circle on the orange square.", + "use red circle to touch orange square" + ), + tokenTrialWithFeedback( + 6, + "Touch the blue circle with the red square.", + "use red square to touch blue circle" + ), + tokenTrialWithFeedback( + 7, + "Click on the blue circle and the red square.", + "touch blue circle, touch red square" + ), + tokenTrialWithFeedback( + 8, + "Drag the blue circle or the red square to the box.", + "pick up blue circle or pick up red square" + ), + tokenTrialWithFeedback( + 9, + "Move the orange square away from the brown square.", + "move orange square away from brown square" + ), + tokenTrialWithFeedback( + 10, + "If there is a black circle, drag the red square to the box", + "nothing" + ), - // beside? - tokenTrialWithFeedback( - 11, - "Put the orange square beside the red circle", - "put orange square left of red circle" - ), + // beside? + tokenTrialWithFeedback( + 11, + "Put the orange square beside the red circle", + "put orange square left of red circle" + ), - tokenTrialWithFeedback( - 12, - "Click on the squares first and the circles second", - "touch red square, touch blue square, touch white square, touch brown square, touch orange square\ntouch red circle, touch blue circle, touch white circle, touch brown circle, touch orange circle" - ), - tokenTrialWithFeedback( - 13, - "Put the red circle between the brown square and the orange square.", - "put red circle between brown square and orange square" - ), - tokenTrialWithFeedback( - 14, - "Click on all circles, except the orange one.", - "touch blue circle, touch red circle, touch brown circle, touch white circle" - ), - tokenTrialWithFeedback( - 15, - "Drag the red circle - no - the white square to the box.", - "pick up white square" - ), - tokenTrialWithFeedback( - 16, - "Instead of the white square, drag the brown circle to the box.", - "pick up brown circle" - ), - tokenTrialWithFeedback( - 17, - "Click on the square that is next to the square that is below the red circle", - "touch red square" - ), - tokenTrialWithFeedback( - 18, - "Using the circle that is above the white square, touch the blue circle.", - "use brown circle to touch blue circle" - ), - tokenTrialWithFeedback( - 19, - "Drag the blue circle and the red circle and the white square to the box.", - "pick up blue circle, pick up red circle, pick up white square" - ), - tokenTrialWithFeedback( - 20, - "Click on the red square and the orange square and drag the white circle and the brown square to the box.", - "touch red square, touch orange square, pick up white circle, pick up brown square" - ), - tokenTrialWithFeedback( - 21, - "Click on the blue circle and the white square and the orange square and the red circle.", - "touch blue circle, touch white square, touch orange square, touch red circle" - ), - tokenTrialWithFeedback( - 22, - "Click on the square below the circle next to the red circle.", - "touch red square" - ), - tokenTrialWithFeedback( - 23, - "Click on the red circle and the orange circle and drag the brown square to the box.", - "touch red circle, touch orange circle, pick up brown square" - ), - tokenTrialWithFeedback( - 24, - "Before clicking on the brown circle, drag the circle above the square that is next to the brown square to the box.", - "pick up white circle\ntouch brown circle" - ), - tokenTrialWithFeedback( - 25, - "Drag the brown circle and the square that is below the blue circle to the box.", - "pick up brown circle, pick up red square" - ), - tokenTrialWithFeedback( - 26, - "Using the square that is below the orange circle, touch the red square.", - "use brown square to touch red square" - ), - tokenTrialWithFeedback( - 27, - "Click on the circle that is next to the circle that is above the brown square.", - "touch white circle" - ), - tokenTrialWithFeedback( - 28, - "Drag the white square and the square that is below the red circle to the box.", - "pick up white square, pick up blue square" - ), - tokenTrialWithFeedback( - 29, - "Click on the red square and the orange square and the white circle and the brown circle.", - "touch red square, touch orange square, touch white circle, touch brown circle" - ), - tokenTrialWithFeedback( - 30, - "Drag the brown circle and the blue square and the white circle to the box.", - "pick up brown circle, pick up blue square, pick up white circle" - ), - tokenTrialWithFeedback( - 31, - "Click on the brown circle and the orange square and drag the red circle and the white square to the box.", - "touch brown circle, touch orange square, pick up red circle, pick up white square" - ), - tokenTrialWithFeedback( - 32, - "Before clicking on the red square, drag the square next to the square that is below the white circle to the box.", - "pick up brown square or pick up white square\ntouch red square" - ), - tokenTrialWithFeedback( - 33, - "Click on the circle next to the circle above the blue square.", - "touch blue circle" - ), - tokenTrialWithFeedback( - 34, - "Drag the orange square and the red circle to the box and click on the blue square.", - "pick up orange square, pick up red circle, touch blue square" - ), - tokenTrialWithFeedback( - 35, - "Using the circle that is above the orange square, touch the blue square.", - "use white circle to touch blue square" - ), - tokenTrialWithFeedback( - 36, - "Click on the square next to the square below the orange circle.", - "touch orange square" - ), - tokenTrialWithFeedback( - 37, - "Click on the square that is below the circle that is next to the orange circle.", - "touch orange square" - ), - tokenTrialWithFeedback( - 38, - "Drag the brown circle and the blue square to the box and click on the white circle.", - "pick up brown circle, pick up blue square, touch white circle" - ), + tokenTrialWithFeedback( + 12, + "Click on the squares first and the circles second", + "touch red square, touch blue square, touch white square, touch brown square, touch orange square\ntouch red circle, touch blue circle, touch white circle, touch brown circle, touch orange circle" + ), + tokenTrialWithFeedback( + 13, + "Put the red circle between the brown square and the orange square.", + "put red circle between brown square and orange square" + ), + tokenTrialWithFeedback( + 14, + "Click on all circles, except the orange one.", + "touch blue circle, touch red circle, touch brown circle, touch white circle" + ), + tokenTrialWithFeedback( + 15, + "Drag the red circle - no - the white square to the box.", + "pick up white square" + ), + tokenTrialWithFeedback( + 16, + "Instead of the white square, drag the brown circle to the box.", + "pick up brown circle" + ), + tokenTrialWithFeedback( + 17, + "Click on the square that is next to the square that is below the red circle", + "touch red square" + ), + tokenTrialWithFeedback( + 18, + "Using the circle that is above the white square, touch the blue circle.", + "use brown circle to touch blue circle" + ), + tokenTrialWithFeedback( + 19, + "Drag the blue circle and the red circle and the white square to the box.", + "pick up blue circle, pick up red circle, pick up white square" + ), + tokenTrialWithFeedback( + 20, + "Click on the red square and the orange square and drag the white circle and the brown square to the box.", + "touch red square, touch orange square, pick up white circle, pick up brown square" + ), + tokenTrialWithFeedback( + 21, + "Click on the blue circle and the white square and the orange square and the red circle.", + "touch blue circle, touch white square, touch orange square, touch red circle" + ), + tokenTrialWithFeedback( + 22, + "Click on the square below the circle next to the red circle.", + "touch red square" + ), + tokenTrialWithFeedback( + 23, + "Click on the red circle and the orange circle and drag the brown square to the box.", + "touch red circle, touch orange circle, pick up brown square" + ), + tokenTrialWithFeedback( + 24, + "Before clicking on the brown circle, drag the circle above the square that is next to the brown square to the box.", + "pick up white circle\ntouch brown circle" + ), + tokenTrialWithFeedback( + 25, + "Drag the brown circle and the square that is below the blue circle to the box.", + "pick up brown circle, pick up red square" + ), + tokenTrialWithFeedback( + 26, + "Using the square that is below the orange circle, touch the red square.", + "use brown square to touch red square" + ), + tokenTrialWithFeedback( + 27, + "Click on the circle that is next to the circle that is above the brown square.", + "touch white circle" + ), + tokenTrialWithFeedback( + 28, + "Drag the white square and the square that is below the red circle to the box.", + "pick up white square, pick up blue square" + ), + tokenTrialWithFeedback( + 29, + "Click on the red square and the orange square and the white circle and the brown circle.", + "touch red square, touch orange square, touch white circle, touch brown circle" + ), + tokenTrialWithFeedback( + 30, + "Drag the brown circle and the blue square and the white circle to the box.", + "pick up brown circle, pick up blue square, pick up white circle" + ), + tokenTrialWithFeedback( + 31, + "Click on the brown circle and the orange square and drag the red circle and the white square to the box.", + "touch brown circle, touch orange square, pick up red circle, pick up white square" + ), + tokenTrialWithFeedback( + 32, + "Before clicking on the red square, drag the square next to the square that is below the white circle to the box.", + "pick up brown square or pick up white square\ntouch red square" + ), + tokenTrialWithFeedback( + 33, + "Click on the circle next to the circle above the blue square.", + "touch blue circle" + ), + tokenTrialWithFeedback( + 34, + "Drag the orange square and the red circle to the box and click on the blue square.", + "pick up orange square, pick up red circle, touch blue square" + ), + tokenTrialWithFeedback( + 35, + "Using the circle that is above the orange square, touch the blue square.", + "use white circle to touch blue square" + ), + tokenTrialWithFeedback( + 36, + "Click on the square next to the square below the orange circle.", + "touch orange square" + ), + tokenTrialWithFeedback( + 37, + "Click on the square that is below the circle that is next to the orange circle.", + "touch orange square" + ), + tokenTrialWithFeedback( + 38, + "Drag the brown circle and the blue square to the box and click on the white circle.", + "pick up brown circle, pick up blue square, touch white circle" + ), - tokenTrialWithFeedback( - 39, - "Drag the orange square and the circle that is above the brown square to the box.", - "pick up orange square, pick up orange circle" - ), + tokenTrialWithFeedback( + 39, + "Drag the orange square and the circle that is above the brown square to the box.", + "pick up orange square, pick up orange circle" + ), - tokenTrialWithFeedback( - 40, - "Click on the blue square and the white square and drag the orange circle and the red circle to the box.", - "touch blue square, touch white square, pick up orange circle, pick up red circle" - ), - tokenTrialWithFeedback( - 41, - "Click on the orange circle and the white circle and the red square and the brown circle.", - "touch orange circle, touch white circle, touch red square, touch brown circle" - ), - tokenTrialWithFeedback( - 42, - "Drag the white square and the brown square and the blue circle to the box.", - "pick up white square, pick up brown square, pick up blue circle" - ), - tokenTrialWithFeedback( - 43, - "Before clicking on the blue square, drag the circle next to the circle that is above the brown square to the box.", - "pick up white circle\ntouch blue square" - ), - ]), - }, - { - type: "html-button-response", - stimulus: "Thanks for participating! Press Done to finish.", - choices: ["Done"], - }, - ], - on_finish() { - window.close(); + tokenTrialWithFeedback( + 40, + "Click on the blue square and the white square and drag the orange circle and the red circle to the box.", + "touch blue square, touch white square, pick up orange circle, pick up red circle" + ), + tokenTrialWithFeedback( + 41, + "Click on the orange circle and the white circle and the red square and the brown circle.", + "touch orange circle, touch white circle, touch red square, touch brown circle" + ), + tokenTrialWithFeedback( + 42, + "Drag the white square and the brown square and the blue circle to the box.", + "pick up white square, pick up brown square, pick up blue circle" + ), + tokenTrialWithFeedback( + 43, + "Before clicking on the blue square, drag the circle next to the circle that is above the brown square to the box.", + "pick up white circle\ntouch blue square" + ), + ]), }, -}); + { + type: jsPsychHtmlButtonResponse, + stimulus: "Thanks for participating! Press Done to finish.", + choices: ["Done"], + }, +]); diff --git a/jspsych/plugin.js b/jspsych/plugin.js index 3a0ab57..5f752ec 100644 --- a/jspsych/plugin.js +++ b/jspsych/plugin.js @@ -191,7 +191,7 @@ function tokenGridWithRows(n) { return grid; } -function audioBufferSource(url) { +function audioBufferSource(jsPsych, url) { const AudioContext = window.AudioContext || window.webkitAudioContext; const audioContext = new AudioContext(); return jsPsych.pluginAPI.getAudioBuffer(url).then((buffer) => { @@ -208,11 +208,13 @@ function addProgressElement(parent, trialParameters) { adopt(parent, progressElement); } -function onTokenReleased(control, token) { +function onTokenReleased(jsPsych, control, token) { control.tokenReleased = token; - audioBufferSource(control.trialParameters.tokenDropUrl).then((source) => { - source.start(); - }); + audioBufferSource(jsPsych, control.trialParameters.tokenDropUrl).then( + (source) => { + source.start(); + } + ); control.observer.notifyThatTokenHasBeenReleased(); } @@ -227,7 +229,8 @@ function onTokenDroppedOnto(control, token) { } class TokenControl { - constructor(parent, trial, trialParameters, tokenRows) { + constructor(jsPsych, parent, trial, trialParameters, tokenRows) { + this.jsPsych = jsPsych; this.trial = trial; this.trialParameters = trialParameters; this.elementFromToken = new Map(); @@ -272,7 +275,7 @@ class TokenControl { : squareElementWithColor(token.color), this.elementFromToken, (token) => { - onTokenReleased(this, token); + onTokenReleased(this.jsPsych, this, token); }, (token) => { onTokenDragged(this, token); @@ -328,7 +331,8 @@ class TokenControl { } class SizedTokenControl { - constructor(parent, trial, trialParameters, tokenRows) { + constructor(jsPsych, parent, trial, trialParameters, tokenRows) { + this.jsPsych = jsPsych; this.trial = trial; this.trialParameters = trialParameters; this.elementFromToken = new Map(); @@ -356,7 +360,7 @@ class SizedTokenControl { : smallSquareElementWithColor(token.color), this.elementFromToken, (token) => { - onTokenReleased(this, token); + onTokenReleased(this.jsPsych, this, token); }, (token) => { onTokenDragged(this, token); @@ -412,7 +416,8 @@ class SizedTokenControl { } class JsPsychTrial { - constructor(sentenceNumber, sentenceUrl, sentence) { + constructor(jsPsych, sentenceNumber, sentenceUrl, sentence) { + this.jsPsych = jsPsych; this.tokenDragPaths = []; this.sentenceNumber = sentenceNumber; this.sentenceUrl = sentenceUrl; @@ -420,7 +425,7 @@ class JsPsychTrial { } conclude(result) { - jsPsych.finishTrial({ + this.jsPsych.finishTrial({ ...result, tokenDragPaths: this.tokenDragPaths, sentenceNumber: this.sentenceNumber, @@ -458,14 +463,16 @@ class PerformanceTimer { } } -function pluginUsingControllerAndControlFactories( - TokenControllerType, - createTokenControl -) { - return { +function pluginClass(TokenControllerType, createTokenControl) { + class Plugin { + constructor(jsPsych) { + this.jsPsych = jsPsych; + } + trial(display_element, trialParameters) { clear(display_element); const jsPsychTrial = new JsPsychTrial( + this.jsPsych, trialParameters.sentenceNumber, trialParameters.sentenceUrl, trialParameters.sentence @@ -476,36 +483,85 @@ function pluginUsingControllerAndControlFactories( parseTokenInteractionRule(trialParameters.commandString) ); const controller = new TokenControllerType( - createTokenControl(display_element, jsPsychTrial, trialParameters), + createTokenControl( + this.jsPsych, + display_element, + jsPsychTrial, + trialParameters + ), model ); - audioBufferSource(trialParameters.sentenceUrl).then((sentenceSource) => { - sentenceSource.onended = () => { - audioBufferSource(trialParameters.beepUrl).then((beepSource) => { - beepSource.start(); - jsPsych.pluginAPI.setTimeout(() => { - model.concludeTrial(); - }, trialParameters.timeoutMilliseconds); - }); - }; - sentenceSource.start(); - }); - }, - info: { - parameters: {}, + audioBufferSource(this.jsPsych, trialParameters.sentenceUrl).then( + (sentenceSource) => { + sentenceSource.onended = () => { + audioBufferSource(this.jsPsych, trialParameters.beepUrl).then( + (beepSource) => { + beepSource.start(); + this.jsPsych.pluginAPI.setTimeout(() => { + model.concludeTrial(); + }, trialParameters.timeoutMilliseconds); + } + ); + }; + sentenceSource.start(); + } + ); + } + } + return Plugin; +} + +function pluginUsingControllerAndControlFactories( + TokenControllerType, + createTokenControl, + name, + jsPsychModule, + additionalParameters = {} +) { + const Plugin = pluginClass(TokenControllerType, createTokenControl); + Plugin.info = { + name, + parameters: { + sentenceNumber: { + type: jsPsychModule.ParameterType.INT, + default: 1, + }, + sentenceUrl: { + type: jsPsychModule.ParameterType.AUDIO, + default: undefined, + }, + sentence: { + type: jsPsychModule.ParameterType.STRING, + default: "", + }, + commandString: { + type: jsPsychModule.ParameterType.STRING, + default: "nothing", + }, + timeoutMilliseconds: { + type: jsPsychModule.ParameterType.INT, + default: 10000, + }, + beepUrl: { + type: jsPsychModule.ParameterType.AUDIO, + default: undefined, + }, + tokenDropUrl: { + type: jsPsychModule.ParameterType.AUDIO, + default: undefined, + }, + ...additionalParameters, }, }; -} -export function plugin(id) { - jsPsych.pluginAPI.registerPreload(id, "sentenceUrl", "audio"); - jsPsych.pluginAPI.registerPreload(id, "beepUrl", "audio"); - jsPsych.pluginAPI.registerPreload(id, "boxUrl", "image"); + return Plugin; +} +export function plugin(jsPsychModule) { return pluginUsingControllerAndControlFactories( TokenController, - (parent, trial, trialParameters) => - new TokenControl(parent, trial, trialParameters, [ + (jsPsych, parent, trial, trialParameters) => + new TokenControl(jsPsych, parent, trial, trialParameters, [ [ { color: Color.red, shape: Shape.circle }, { color: Color.blue, shape: Shape.circle }, @@ -520,18 +576,23 @@ export function plugin(id) { { color: Color.orange, shape: Shape.square }, { color: Color.brown, shape: Shape.square }, ], - ]) + ]), + "Token", + jsPsychModule, + { + boxUrl: { + type: jsPsychModule.ParameterType.IMAGE, + default: undefined, + }, + } ); } -export function twoSizesPlugin(id) { - jsPsych.pluginAPI.registerPreload(id, "sentenceUrl", "audio"); - jsPsych.pluginAPI.registerPreload(id, "beepUrl", "audio"); - +export function twoSizesPlugin(jsPsychModule) { return pluginUsingControllerAndControlFactories( SizedTokenController, - (parent, trial, trialParameters) => - new SizedTokenControl(parent, trial, trialParameters, [ + (jsPsych, parent, trial, trialParameters) => + new SizedTokenControl(jsPsych, parent, trial, trialParameters, [ [ { color: Color.red, shape: Shape.circle, size: Size.large }, { color: Color.blue, shape: Shape.circle, size: Size.large }, @@ -560,6 +621,8 @@ export function twoSizesPlugin(id) { { color: Color.blue, shape: Shape.square, size: Size.small }, { color: Color.white, shape: Shape.square, size: Size.small }, ], - ]) + ]), + "Sized Token", + jsPsychModule ); }