From 3f3d984a4cc51a14c2a6bd499009e0620f95088c Mon Sep 17 00:00:00 2001 From: jade <101148768+jadeddelta@users.noreply.github.com> Date: Mon, 4 Nov 2024 11:58:44 -0500 Subject: [PATCH 01/15] fix up formatting errors --- docs/overview/browser-device-support.md | 11 ++++++----- docs/reference/jspsych.md | 2 ++ docs/support/migration-v8.md | 2 +- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/docs/overview/browser-device-support.md b/docs/overview/browser-device-support.md index 891e0c42ab..7de505a487 100644 --- a/docs/overview/browser-device-support.md +++ b/docs/overview/browser-device-support.md @@ -22,11 +22,12 @@ There are many other web browsers that are available, but that are not commonly In general, jsPsych experiments can be run on mobile devices (smartphones and tablets). However, certain plugins will not work on mobile. For instance, any plugin that requires a keyboard response without a text input box, such as the *-keyboard-response plugins, will not work. Even plugins that do work on mobile might work differently than they do on desktop and laptop computers. For instance, on mobile devices, a text input box will cause an on-screen keyboard to pop up, which affects the visible content on the screen. If you plan to run an experiment that allows people to use mobile devices, we recommend doing some extra testing to make sure that everything works as expected. In particular, you may want to check that: -* Font sizes are readable on smaller screens -* Stimuli sizes are large enough and appropriate for the task -* Page is laid out as intended (e.g. elements are centered and do not overlap) -* Response options are touchscreen-friendly (e.g. buttons rather than key presses) -* Response options (e.g. buttons, text boxes, radio buttons) are large enough and far enough apart to be easily selected with a finger tap + + * Font sizes are readable on smaller screens + * Stimuli sizes are large enough and appropriate for the task + * Page is laid out as intended (e.g. elements are centered and do not overlap) + * Response options are touchscreen-friendly (e.g. buttons rather than key presses) + * Response options (e.g. buttons, text boxes, radio buttons) are large enough and far enough apart to be easily selected with a finger tap It's possible to use your browser's developer tools to emulate mobile devices ([this page shows how to do it in Chrome](https://developers.google.com/web/tools/chrome-devtools/device-mode)), which is useful for getting a sense of how your experiment will look on mobile devices. Just be aware that there are limitations to emulator tools, and there are some aspects of mobile devices/browsers that a desktop browser will not be able to simulate. diff --git a/docs/reference/jspsych.md b/docs/reference/jspsych.md index 906241fc73..da29234b76 100644 --- a/docs/reference/jspsych.md +++ b/docs/reference/jspsych.md @@ -400,6 +400,8 @@ var el = jsPsych.getDisplayElement(); // hide the jsPsych display el.style.visibility = 'hidden'; ``` + + --- ## jsPsych.getInitSettings diff --git a/docs/support/migration-v8.md b/docs/support/migration-v8.md index b0651a1009..16a6049545 100644 --- a/docs/support/migration-v8.md +++ b/docs/support/migration-v8.md @@ -83,7 +83,7 @@ const trial = { ``` The `button_html` parameter can also support different HTML for each button. -See the [plugin documentation](https://www.jspsych.org/plugins/jspsych-html-button-response/) for more details. +See the [plugin documentation](https://www.jspsych.org/latest/plugins/html-button-response/index.html) for more details. ## Plugin parameter handling From 4b14995d4ac2fdb276806a909fb9a406d06913cb Mon Sep 17 00:00:00 2001 From: jade <101148768+jadeddelta@users.noreply.github.com> Date: Mon, 4 Nov 2024 13:39:32 -0500 Subject: [PATCH 02/15] fix audio stop description --- docs/reference/jspsych-pluginAPI.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/docs/reference/jspsych-pluginAPI.md b/docs/reference/jspsych-pluginAPI.md index 46c782ea4c..ffc7da3b58 100644 --- a/docs/reference/jspsych-pluginAPI.md +++ b/docs/reference/jspsych-pluginAPI.md @@ -289,7 +289,7 @@ See the `audio-keyboard-response` plugin for an example in a fuller context. ```javascript const audio = jsPsych.pluginAPI.getAudioPlayer(filepath); -audio.play(); +audio.stop(); ``` #### Return value @@ -298,7 +298,7 @@ Returns nothing. #### Description -Method that belongs to the AudioPlayer class. Stops the audio loaded into the audio buffer of the AudioPlayer instance for a particular file. If the audio is an HTML5 audio object it pauses it. If the audio is a Webaudio API object it stops it. +Method that belongs to the AudioPlayer class. Stops the audio loaded into the audio buffer of the AudioPlayer instance for a particular file. If the audio is an HTML5 audio object it pauses it. If the audio is a Webaudio API object it stops it. This will regenerate the audio player, allowing you to call the `play()` method upon it again. #### Example @@ -310,7 +310,6 @@ const audio = await jsPsych.pluginAPI.getAudioPlayer('my-sound.mp3'); audio.play(); audio.stop(); - ``` See the `audio-keyboard-response` plugin for an example in a fuller context. From f8398601c31fa4c1a27db46a4e5388a6b22a13ad Mon Sep 17 00:00:00 2001 From: jade <101148768+jadeddelta@users.noreply.github.com> Date: Mon, 4 Nov 2024 14:11:41 -0500 Subject: [PATCH 03/15] add AudioPlayer v8 migration info --- docs/support/migration-v8.md | 49 +++++++++++++++++++++++++++++++++++- 1 file changed, 48 insertions(+), 1 deletion(-) diff --git a/docs/support/migration-v8.md b/docs/support/migration-v8.md index 16a6049545..b5cd6071b4 100644 --- a/docs/support/migration-v8.md +++ b/docs/support/migration-v8.md @@ -2,7 +2,8 @@ Version 8.x of jsPsych focused on a complete rewrite of the core library to enable new features and make it easier to maintain. Most of the changes in version 8.x are behind the scenes. -However, there are some breaking changes that you will need to address in your experiment code in order to upgrade to v8.x. +However, there are some breaking changes that you will need to address in your experiment code in order to upgrade to v8.x. +If you are a plugin developer, there are also some special considerations below to factor in when developing your plugins or modifying existing ones. This guide is aimed at upgrades from version 7.x to 8.x. If you are using version 6.x or earlier, please follow the [migration guide for v7.x](./migration-v7.md) before trying to upgrade to v8.x. @@ -85,6 +86,9 @@ const trial = { The `button_html` parameter can also support different HTML for each button. See the [plugin documentation](https://www.jspsych.org/latest/plugins/html-button-response/index.html) for more details. +For plugin developers: if you are writing a plugin and updating parameters to use functions, +make sure to mock these functions in Jest to ensure tests can still run. + ## Plugin parameter handling In version 7.x, a plugin could omit parameters from the `info` object and jsPsych would still evaluate these parameters appropriately in most cases. @@ -104,6 +108,49 @@ Including these properties is not *required* for a plugin to work, but it is rec In version 8.x, jsPsych will throw a warning if a plugin is used that does not have a `version` or `data` property in the `info` object. In version 9.x, we plan to make this a requirement. +## Changes to the `AudioPlayer` class + +In version 7.x, jsPsych's `pluginAPI` class exposed WebAudio and HTML5 audio APIs through `getAudioBuffer()`. However, this required different implementations done by the developer to account for each API. +In version 8.x, we've removed this in favor of `getAudioPlayer()`, which handles both API choices under the hood. + +This change only effects plugin developers. If you want to update to use the new `getAudioPlayer()`, it is recommend that you call this new method using the `await` syntax, which requires an asyncrhonous `trial` function: +```js +const audio = await jsPsych.pluginAPI.getAudioPlayer('my-sound.mp3'); +``` + +If you'd like to still use the `.then()` syntax to resolve the Promise generated, you may update it as such: + +Version 7.x: +```js +this.jsPsych.pluginAPI + .getAudioBuffer('my-audio.mp3') + .then((audio) => { + // call play on audio if HTML5 audio API, create and connect buffer if WebAudio API + }) + .catch((err) =>{ + // handle error + }); +``` + +Version 8.x: +```js +this.jsPsych.pluginAPI + .getAudioPlayer('my-audio.mp3') + .then((player) => { + // no need to create and connect buffer, can just directly call functions on player + }) + .catch((err) => { + // handle error + }) +``` + +Along with this, the `start()` and `pause()` functions were removed from the `AudioPlayer` class. +You can still call `stop()` upon an audio ending in order to regenerate the `AudioPlayer`, and be able +to call `play()` on it again. + +For a general guide on implementation, the `audio-button-response` plugin uses the `await` syntax +to handle playing audio. + ## Changes to `finishTrial()` When a plugin calls `finishTrial()` or ends via a `return` statement, jsPsych will now automatically clear the display and clear any timeouts that are still pending. This change should only affect plugin developers. If you are using built-in plugins you should not notice any difference. From 0fc1bf0e6c6fe61a0e4c5da1bc9d378498721915 Mon Sep 17 00:00:00 2001 From: jade <101148768+jadeddelta@users.noreply.github.com> Date: Wed, 6 Nov 2024 14:13:06 -0500 Subject: [PATCH 04/15] more typo fixes --- docs/plugins/initialize-camera.md | 2 +- docs/plugins/initialize-microphone.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/plugins/initialize-camera.md b/docs/plugins/initialize-camera.md index 3c07f0d011..9123253fc9 100644 --- a/docs/plugins/initialize-camera.md +++ b/docs/plugins/initialize-camera.md @@ -18,7 +18,7 @@ In addition to the [parameters available in all plugins](../overview/plugins.md# Parameter | Type | Default Value | Description ----------|------|---------------|------------ device_select_message | html string | `
Please select the camera you would like to use.
` | The message to display when the user is presented with a dropdown list of available devices. -button_label | sting | 'Use this camera.' | The label for the select button. +button_label | string | 'Use this camera.' | The label for the select button. include_audio | bool | false | Set to `true` to include an audio track in the recordings. width | int | null | Request a specific width for the recording. This is not a guarantee that this width will be used, as it depends on the capabilities of the participant's device. Learn more about `MediaRecorder` constraints [here](https://developer.mozilla.org/en-US/docs/Web/API/Media_Streams_API/Constraints#requesting_a_specific_value_for_a_setting). height | int | null | Request a specific height for the recording. This is not a guarantee that this height will be used, as it depends on the capabilities of the participant's device. Learn more about `MediaRecorder` constraints [here](https://developer.mozilla.org/en-US/docs/Web/API/Media_Streams_API/Constraints#requesting_a_specific_value_for_a_setting). diff --git a/docs/plugins/initialize-microphone.md b/docs/plugins/initialize-microphone.md index d3fabd0d62..a3e71ffc05 100644 --- a/docs/plugins/initialize-microphone.md +++ b/docs/plugins/initialize-microphone.md @@ -18,7 +18,7 @@ In addition to the [parameters available in all plugins](../overview/plugins.md# Parameter | Type | Default Value | Description ----------|------|---------------|------------ device_select_message | html string | `Please select the microphone you would like to use.
` | The message to display when the user is presented with a dropdown list of available devices. -button_label | sting | 'Use this microphone.' | The label for the select button. +button_label | string | 'Use this microphone.' | The label for the select button. ## Data Generated From 36f75cc46a1a068335e80f3c918fc73e4091ea1f Mon Sep 17 00:00:00 2001 From: jade <101148768+jadeddelta@users.noreply.github.com> Date: Thu, 7 Nov 2024 17:12:54 -0500 Subject: [PATCH 05/15] add parametertype and build environment docs --- docs/developers/plugin-development.md | 104 ++++++++++++++++++++++++++ 1 file changed, 104 insertions(+) diff --git a/docs/developers/plugin-development.md b/docs/developers/plugin-development.md index a6487e40d9..1eae9ae62f 100644 --- a/docs/developers/plugin-development.md +++ b/docs/developers/plugin-development.md @@ -61,6 +61,10 @@ const info = { } ``` +??? info "Custom Build Environments" + + If you are using a custom build environment that imports its own `tsconfig.json` file that does not extend jsPsych's, but you want to use this syntax, you must add `"resolveJsonModule": true` to the config's `compilerOptions` object. + If you are not using a build environment that supports `import` and `package.json` (such as writing a plain JS file), you can manually enter the `version` as a string. ```javascript @@ -163,6 +167,106 @@ class MyAwesomePlugin { MyAwesomePlugin.info = info; ``` +#### Parameter Types + +jsPsych currently has support for the following parameters: + +| Type Name | Description | Example | +| --------- | ----------- | ------- | +| BOOL | A simple truth value. | `true` or `false` | +| STRING | A set of characters. | "Continue" | +| INT | A value that supports whole numbers. | 12 | +| FLOAT | A value that supports decimal numbers. | 5.55 | +| FUNCTION | A Javascript function, tends to process multiple objects in an array from other parameters. | `function(tries) { return "You have " + tries + " tries left." }` | +| KEY | A single key, with support for function keys like arrows and spacebars. | `"j"`, `"n"`, `"ArrowLeft"` | +| KEYS | Either an array of keys, or the string `"ALL_KEYS"` or `"NO_KEYS"`, indicating their respective inclusion/exclusion criterea. | `["f", "j"]` | +| SELECT | A list of strings that a developer can choose between as a parameter. | `["cm", "px", "em"]` | +| HTML_STRING | A string with HTML markup. | `"
This is the prompt.
"` | +| IMAGE | A string that contains the path to an image file. | `"my_image.jpg"` | +| AUDIO | A string that contains the path to an audio file. | `"my_sound.mp3"` | +| VIDEO | A string that contains the path to a video file. | `"my_video.mp4"` | +| OBJECT | A general JSON object (key-value pairs). | `{ rt: 350, response: "hello!", correct: true }` | +| COMPLEX | A JSON object that one can specify nested parameters for. | `{ rt: 350, response: "hello!", correct: true }` | +| TIMELINE | A jsPsych timeline object with trials. | `[{ type: jsPsychKeyboardResponse, stimulus: 'my_image.jpg }]` | + +Within each parameter, you may also specify if it is an array of the specific type. For example, a parameter that requires a list of button labels would be described as: + +```js +const info = { + // ... + parameters: { + /** The labels to be displayed on each button. */ + labels: { + type: ParameterType.STRING, + array: true, + default: ["Pause", "Play", "Continue"] + } + }, + // ... +} +``` + +Specific parameter types also have their own special markup. For `ParameterType.SELECT`, you specify the options one can choose with an `options` field, and then the `default` field must be within that field. + +```js +const info = { + // ... + parameters: { + /** The units of measure used to display the length and width of the stimulus. */ + units: { + type: ParameterType.SELECT, + options: ["em", "px", "vh", "vw"], + default: "px" + } + }, + // ... +} +``` + +For `ParameterType.COMPLEX`, we may specify the underlying fields in the object with the `nested` field. This acts in the same way as us defining parameters regularly, only we are now just delineating the fields within the object itself. + +```js +const info = { + // ... + parameters: { + /** Where to display the location of the stimuli. */ + locations: { + type: ParameterType.COMPLEX, + array: true, + default: undefined, + nested: { + /** The x-coordinate of the stimulus, in the units from the `units` field. */ + x: { + type: ParameterType.INT + }, + /** The y-coordinate of the stimulus. */ + y: { + type: ParameterType.INT + } + } + } + }, + // ... +} +``` + +For more complicated scenarios, typically when handling data generated from an arbitrary function or user input, where we have a general idea of what data type it could produce, we may also specify multiple types of data. As an example, if we know we'll get either some number (integer or float) or a string from a field, we can specify it as such: + +```js +const info = { + // ... + data: { + /** The response given by the user. */ + response: { + type: + ParameterType.INT | + ParameterType.FLOAT | + ParameterType.STRING + } + } +} +``` + ## Plugin functionality Inside the `.trial()` method you can do pretty much anything that you want, including modifying the DOM, setting up event listeners, and making asynchronous requests. In this section we'll highlight a few common things that you might want to do as examples. From 96c70920425fef3b06c4bfa5873a496dbc108b1d Mon Sep 17 00:00:00 2001 From: jade <101148768+jadeddelta@users.noreply.github.com> Date: Thu, 7 Nov 2024 17:29:05 -0500 Subject: [PATCH 06/15] fix typo --- docs/support/migration-v8.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/support/migration-v8.md b/docs/support/migration-v8.md index b5cd6071b4..05911fd21f 100644 --- a/docs/support/migration-v8.md +++ b/docs/support/migration-v8.md @@ -113,7 +113,7 @@ In version 9.x, we plan to make this a requirement. In version 7.x, jsPsych's `pluginAPI` class exposed WebAudio and HTML5 audio APIs through `getAudioBuffer()`. However, this required different implementations done by the developer to account for each API. In version 8.x, we've removed this in favor of `getAudioPlayer()`, which handles both API choices under the hood. -This change only effects plugin developers. If you want to update to use the new `getAudioPlayer()`, it is recommend that you call this new method using the `await` syntax, which requires an asyncrhonous `trial` function: +This change only effects plugin developers. If you want to update to use the new `getAudioPlayer()`, it is recommend that you call this new method using the `await` syntax, which requires an asynchronous `trial` function: ```js const audio = await jsPsych.pluginAPI.getAudioPlayer('my-sound.mp3'); ``` From 8d40c445b49ea4df6d305da5a4ca00cf0b1e8ced Mon Sep 17 00:00:00 2001 From: jade <101148768+jadeddelta@users.noreply.github.com> Date: Thu, 7 Nov 2024 17:49:18 -0500 Subject: [PATCH 07/15] flesh out extension description and fix minor details --- docs/developers/extension-development.md | 10 ++++++---- docs/overview/extensions.md | 12 +++--------- 2 files changed, 9 insertions(+), 13 deletions(-) diff --git a/docs/developers/extension-development.md b/docs/developers/extension-development.md index cdfec7245f..1407c77983 100644 --- a/docs/developers/extension-development.md +++ b/docs/developers/extension-development.md @@ -66,7 +66,7 @@ let trial = { extensions: [ {type: myAwesomeExtension, params: {demo: 'value'}} ] -}); +}; //... extension code ...// class MyAwesomeExtension { @@ -91,7 +91,7 @@ let trial = { extensions: [ {type: myAwesomeExtension, params: {demo: 'value'}} ] -}); +}; //... extension code ...// class MyAwesomeExtension { @@ -122,7 +122,7 @@ let trial = { on_finish: (data) => { console.log(data.awesome); // will output 'value'. } -}); +}; //... extension code ...// class MyAwesomeExtension { @@ -168,9 +168,11 @@ The `version` field describes the version of the extension used and then durin t The `data` field is an object containing all of the `data` generated for the plugin. Each 'data' object has a `type` and `default` property. Additionally, this should be only used for data you choose to generate. Any jsdoc (comments included in the /** */ tags) you include will be scraped as metadata if you are choosing to generate metadata. This scraped metadata will also be used to create the JsPsych documentation. +For more information on the various types of parameters one can include in their data field, see [here](./plugin-development.md#parameter-types). + ### Optional methods -The extension can also include any additional methods that are necessary for interacting with it. See the [webgazer extension](../extensions/webgazer.md) for an example. +The extension can also include any additional methods that are necessary for interacting with it. See the [WebGazer extension](../extensions/webgazer.md) for an example. ## Advice for writing extensions diff --git a/docs/overview/extensions.md b/docs/overview/extensions.md index bf69628fbc..dd4a0972c0 100644 --- a/docs/overview/extensions.md +++ b/docs/overview/extensions.md @@ -1,6 +1,6 @@ # Extensions -Extensions are jsPsych modules that can interface with any plugin to extend the functionality of the plugin. A canonical example of an extension is eye tracking. An eye tracking extension allows a plugin to gather gaze data and add it to the plugin's data object. +In jsPsych, extensions allow one to extend the functionality of various plugins, giving individual plugins the ability to collect more data, display additional stimuli, and more. A canonical example of an extension is [eye tracking](../extensions/webgazer.md), which allow plugins to gather gaze data and add it to the their respective data objects. For a full list of extensions directly included in the jsPsych release, see [here](../extensions/list-of-extensions.md). ## Using an Extension @@ -16,7 +16,7 @@ To use an extension in an experiment, you'll load the extension file via a `