init
python
This commit is contained in:
154
PCSurvey/PCstatic/js/plugins/jspsych-animation.js
Normal file
154
PCSurvey/PCstatic/js/plugins/jspsych-animation.js
Normal file
@@ -0,0 +1,154 @@
|
||||
/**
|
||||
* jsPsych plugin for showing animations and recording keyboard responses
|
||||
* Josh de Leeuw
|
||||
*
|
||||
* documentation: docs.jspsych.org
|
||||
*/
|
||||
|
||||
jsPsych.plugins.animation = (function() {
|
||||
|
||||
var plugin = {};
|
||||
|
||||
jsPsych.pluginAPI.registerPreload('animation', 'stimuli', 'image');
|
||||
|
||||
plugin.info = {
|
||||
name: 'animation',
|
||||
description: '',
|
||||
parameters: {
|
||||
stimuli: {
|
||||
type: jsPsych.plugins.parameterType.STRING,
|
||||
pretty_name: 'Stimuli',
|
||||
default: undefined,
|
||||
array: true,
|
||||
description: 'The images to be displayed.'
|
||||
},
|
||||
frame_time: {
|
||||
type: jsPsych.plugins.parameterType.INT,
|
||||
pretty_name: 'Frame time',
|
||||
default: 250,
|
||||
description: 'Duration to display each image.'
|
||||
},
|
||||
frame_isi: {
|
||||
type: jsPsych.plugins.parameterType.INT,
|
||||
pretty_name: 'Frame gap',
|
||||
default: 0,
|
||||
description: 'Length of gap to be shown between each image.'
|
||||
},
|
||||
sequence_reps: {
|
||||
type: jsPsych.plugins.parameterType.INT,
|
||||
pretty_name: 'Sequence repetitions',
|
||||
default: 1,
|
||||
description: 'Number of times to show entire sequence.'
|
||||
},
|
||||
choices: {
|
||||
type: jsPsych.plugins.parameterType.KEYCODE,
|
||||
pretty_name: 'Choices',
|
||||
default: jsPsych.ALL_KEYS,
|
||||
array: true,
|
||||
description: 'Keys subject uses to respond to stimuli.'
|
||||
},
|
||||
prompt: {
|
||||
type: jsPsych.plugins.parameterType.STRING,
|
||||
pretty_name: 'Prompt',
|
||||
default: null,
|
||||
description: 'Any content here will be displayed below stimulus.'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
plugin.trial = function(display_element, trial) {
|
||||
|
||||
var interval_time = trial.frame_time + trial.frame_isi;
|
||||
var animate_frame = -1;
|
||||
var reps = 0;
|
||||
var startTime = performance.now();
|
||||
var animation_sequence = [];
|
||||
var responses = [];
|
||||
var current_stim = "";
|
||||
|
||||
var animate_interval = setInterval(function() {
|
||||
var showImage = true;
|
||||
display_element.innerHTML = ''; // clear everything
|
||||
animate_frame++;
|
||||
if (animate_frame == trial.stimuli.length) {
|
||||
animate_frame = 0;
|
||||
reps++;
|
||||
if (reps >= trial.sequence_reps) {
|
||||
endTrial();
|
||||
clearInterval(animate_interval);
|
||||
showImage = false;
|
||||
}
|
||||
}
|
||||
if (showImage) {
|
||||
show_next_frame();
|
||||
}
|
||||
}, interval_time);
|
||||
|
||||
function show_next_frame() {
|
||||
// show image
|
||||
display_element.innerHTML = '<img src="'+trial.stimuli[animate_frame]+'" id="jspsych-animation-image"></img>';
|
||||
|
||||
current_stim = trial.stimuli[animate_frame];
|
||||
|
||||
// record when image was shown
|
||||
animation_sequence.push({
|
||||
"stimulus": trial.stimuli[animate_frame],
|
||||
"time": performance.now() - startTime
|
||||
});
|
||||
|
||||
if (trial.prompt !== null) {
|
||||
display_element.innerHTML += trial.prompt;
|
||||
}
|
||||
|
||||
if (trial.frame_isi > 0) {
|
||||
jsPsych.pluginAPI.setTimeout(function() {
|
||||
display_element.querySelector('#jspsych-animation-image').style.visibility = 'hidden';
|
||||
current_stim = 'blank';
|
||||
// record when blank image was shown
|
||||
animation_sequence.push({
|
||||
"stimulus": 'blank',
|
||||
"time": performance.now() - startTime
|
||||
});
|
||||
}, trial.frame_time);
|
||||
}
|
||||
}
|
||||
|
||||
var after_response = function(info) {
|
||||
|
||||
responses.push({
|
||||
key_press: info.key,
|
||||
rt: info.rt,
|
||||
stimulus: current_stim
|
||||
});
|
||||
|
||||
// after a valid response, the stimulus will have the CSS class 'responded'
|
||||
// which can be used to provide visual feedback that a response was recorded
|
||||
display_element.querySelector('#jspsych-animation-image').className += ' responded';
|
||||
}
|
||||
|
||||
// hold the jspsych response listener object in memory
|
||||
// so that we can turn off the response collection when
|
||||
// the trial ends
|
||||
var response_listener = jsPsych.pluginAPI.getKeyboardResponse({
|
||||
callback_function: after_response,
|
||||
valid_responses: trial.choices,
|
||||
rt_method: 'performance',
|
||||
persist: true,
|
||||
allow_held_key: false
|
||||
});
|
||||
|
||||
function endTrial() {
|
||||
|
||||
jsPsych.pluginAPI.cancelKeyboardResponse(response_listener);
|
||||
|
||||
var trial_data = {
|
||||
"animation_sequence": JSON.stringify(animation_sequence),
|
||||
"responses": JSON.stringify(responses)
|
||||
};
|
||||
|
||||
jsPsych.finishTrial(trial_data);
|
||||
}
|
||||
};
|
||||
|
||||
return plugin;
|
||||
})();
|
||||
216
PCSurvey/PCstatic/js/plugins/jspsych-audio-button-response.js
Normal file
216
PCSurvey/PCstatic/js/plugins/jspsych-audio-button-response.js
Normal file
@@ -0,0 +1,216 @@
|
||||
/**
|
||||
* jspsych-audio-button-response
|
||||
* Kristin Diep
|
||||
*
|
||||
* plugin for playing an audio file and getting a keyboard response
|
||||
*
|
||||
* documentation: docs.jspsych.org
|
||||
*
|
||||
**/
|
||||
|
||||
jsPsych.plugins["audio-button-response"] = (function() {
|
||||
var plugin = {};
|
||||
|
||||
jsPsych.pluginAPI.registerPreload('audio-button-response', 'stimulus', 'audio');
|
||||
|
||||
plugin.info = {
|
||||
name: 'audio-button-response',
|
||||
description: '',
|
||||
parameters: {
|
||||
stimulus: {
|
||||
type: jsPsych.plugins.parameterType.AUDIO,
|
||||
pretty_name: 'Stimulus',
|
||||
default: undefined,
|
||||
description: 'The audio to be played.'
|
||||
},
|
||||
choices: {
|
||||
type: jsPsych.plugins.parameterType.STRING,
|
||||
pretty_name: 'Choices',
|
||||
default: undefined,
|
||||
array: true,
|
||||
description: 'The button labels.'
|
||||
},
|
||||
button_html: {
|
||||
type: jsPsych.plugins.parameterType.HTML_STRING,
|
||||
pretty_name: 'Button HTML',
|
||||
default: '<button class="jspsych-btn">%choice%</button>',
|
||||
array: true,
|
||||
description: 'Custom button. Can make your own style.'
|
||||
},
|
||||
prompt: {
|
||||
type: jsPsych.plugins.parameterType.STRING,
|
||||
pretty_name: 'Prompt',
|
||||
default: null,
|
||||
description: 'Any content here will be displayed below the stimulus.'
|
||||
},
|
||||
trial_duration: {
|
||||
type: jsPsych.plugins.parameterType.INT,
|
||||
pretty_name: 'Trial duration',
|
||||
default: null,
|
||||
description: 'The maximum duration to wait for a response.'
|
||||
},
|
||||
margin_vertical: {
|
||||
type: jsPsych.plugins.parameterType.STRING,
|
||||
pretty_name: 'Margin vertical',
|
||||
default: '0px',
|
||||
description: 'Vertical margin of button.'
|
||||
},
|
||||
margin_horizontal: {
|
||||
type: jsPsych.plugins.parameterType.STRING,
|
||||
pretty_name: 'Margin horizontal',
|
||||
default: '8px',
|
||||
description: 'Horizontal margin of button.'
|
||||
},
|
||||
response_ends_trial: {
|
||||
type: jsPsych.plugins.parameterType.BOOL,
|
||||
pretty_name: 'Response ends trial',
|
||||
default: true,
|
||||
description: 'If true, the trial will end when user makes a response.'
|
||||
},
|
||||
trial_ends_after_audio: {
|
||||
type: jsPsych.plugins.parameterType.BOOL,
|
||||
pretty_name: 'Trial ends after audio',
|
||||
default: false,
|
||||
description: 'If true, then the trial will end as soon as the audio file finishes playing.'
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
plugin.trial = function(display_element, trial) {
|
||||
|
||||
// setup stimulus
|
||||
var context = jsPsych.pluginAPI.audioContext();
|
||||
if(context !== null){
|
||||
var source = context.createBufferSource();
|
||||
source.buffer = jsPsych.pluginAPI.getAudioBuffer(trial.stimulus);
|
||||
source.connect(context.destination);
|
||||
} else {
|
||||
var audio = jsPsych.pluginAPI.getAudioBuffer(trial.stimulus);
|
||||
audio.currentTime = 0;
|
||||
}
|
||||
|
||||
// set up end event if trial needs it
|
||||
if(trial.trial_ends_after_audio){
|
||||
if(context !== null){
|
||||
source.onended = function() {
|
||||
end_trial();
|
||||
}
|
||||
} else {
|
||||
audio.addEventListener('ended', end_trial);
|
||||
}
|
||||
}
|
||||
|
||||
//display buttons
|
||||
var buttons = [];
|
||||
if (Array.isArray(trial.button_html)) {
|
||||
if (trial.button_html.length == trial.choices.length) {
|
||||
buttons = trial.button_html;
|
||||
} else {
|
||||
console.error('Error in image-button-response plugin. The length of the button_html array does not equal the length of the choices array');
|
||||
}
|
||||
} else {
|
||||
for (var i = 0; i < trial.choices.length; i++) {
|
||||
buttons.push(trial.button_html);
|
||||
}
|
||||
}
|
||||
|
||||
var html = '<div id="jspsych-audio-button-response-btngroup">';
|
||||
for (var i = 0; i < trial.choices.length; i++) {
|
||||
var str = buttons[i].replace(/%choice%/g, trial.choices[i]);
|
||||
html += '<div class="jspsych-audio-button-response-button" style="cursor: pointer; display: inline-block; margin:'+trial.margin_vertical+' '+trial.margin_horizontal+'" id="jspsych-audio-button-response-button-' + i +'" data-choice="'+i+'">'+str+'</div>';
|
||||
}
|
||||
html += '</div>';
|
||||
|
||||
//show prompt if there is one
|
||||
if (trial.prompt !== null) {
|
||||
html += trial.prompt;
|
||||
}
|
||||
|
||||
display_element.innerHTML = html;
|
||||
|
||||
for (var i = 0; i < trial.choices.length; i++) {
|
||||
display_element.querySelector('#jspsych-audio-button-response-button-' + i).addEventListener('click', function(e){
|
||||
var choice = e.currentTarget.getAttribute('data-choice'); // don't use dataset for jsdom compatibility
|
||||
after_response(choice);
|
||||
});
|
||||
}
|
||||
|
||||
// store response
|
||||
var response = {
|
||||
rt: null,
|
||||
button: null
|
||||
};
|
||||
|
||||
// function to handle responses by the subject
|
||||
function after_response(choice) {
|
||||
|
||||
// measure rt
|
||||
var end_time = performance.now();
|
||||
var rt = end_time - start_time;
|
||||
response.button = choice;
|
||||
response.rt = rt;
|
||||
|
||||
// disable all the buttons after a response
|
||||
var btns = document.querySelectorAll('.jspsych-audio-button-response-button button');
|
||||
for(var i=0; i<btns.length; i++){
|
||||
//btns[i].removeEventListener('click');
|
||||
btns[i].setAttribute('disabled', 'disabled');
|
||||
}
|
||||
|
||||
if (trial.response_ends_trial) {
|
||||
end_trial();
|
||||
}
|
||||
};
|
||||
|
||||
// function to end trial when it is time
|
||||
function end_trial() {
|
||||
|
||||
// stop the audio file if it is playing
|
||||
// remove end event listeners if they exist
|
||||
if(context !== null){
|
||||
source.stop();
|
||||
source.onended = function() { }
|
||||
} else {
|
||||
audio.pause();
|
||||
audio.removeEventListener('ended', end_trial);
|
||||
}
|
||||
|
||||
// kill any remaining setTimeout handlers
|
||||
jsPsych.pluginAPI.clearAllTimeouts();
|
||||
|
||||
// gather the data to store for the trial
|
||||
var trial_data = {
|
||||
"rt": response.rt,
|
||||
"stimulus": trial.stimulus,
|
||||
"button_pressed": response.button
|
||||
};
|
||||
|
||||
// clear the display
|
||||
display_element.innerHTML = '';
|
||||
|
||||
// move on to the next trial
|
||||
jsPsych.finishTrial(trial_data);
|
||||
};
|
||||
|
||||
// start time
|
||||
var start_time = performance.now();
|
||||
|
||||
// start audio
|
||||
if(context !== null){
|
||||
startTime = context.currentTime;
|
||||
source.start(startTime);
|
||||
} else {
|
||||
audio.play();
|
||||
}
|
||||
|
||||
// end trial if time limit is set
|
||||
if (trial.trial_duration !== null) {
|
||||
jsPsych.pluginAPI.setTimeout(function() {
|
||||
end_trial();
|
||||
}, trial.trial_duration);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
return plugin;
|
||||
})();
|
||||
185
PCSurvey/PCstatic/js/plugins/jspsych-audio-keyboard-response.js
Normal file
185
PCSurvey/PCstatic/js/plugins/jspsych-audio-keyboard-response.js
Normal file
@@ -0,0 +1,185 @@
|
||||
/**
|
||||
* jspsych-audio-keyboard-response
|
||||
* Josh de Leeuw
|
||||
*
|
||||
* plugin for playing an audio file and getting a keyboard response
|
||||
*
|
||||
* documentation: docs.jspsych.org
|
||||
*
|
||||
**/
|
||||
|
||||
jsPsych.plugins["audio-keyboard-response"] = (function() {
|
||||
|
||||
var plugin = {};
|
||||
|
||||
jsPsych.pluginAPI.registerPreload('audio-keyboard-response', 'stimulus', 'audio');
|
||||
|
||||
plugin.info = {
|
||||
name: 'audio-keyboard-response',
|
||||
description: '',
|
||||
parameters: {
|
||||
stimulus: {
|
||||
type: jsPsych.plugins.parameterType.AUDIO,
|
||||
pretty_name: 'Stimulus',
|
||||
default: undefined,
|
||||
description: 'The audio to be played.'
|
||||
},
|
||||
choices: {
|
||||
type: jsPsych.plugins.parameterType.KEYCODE,
|
||||
pretty_name: 'Choices',
|
||||
array: true,
|
||||
default: jsPsych.ALL_KEYS,
|
||||
description: 'The keys the subject is allowed to press to respond to the stimulus.'
|
||||
},
|
||||
prompt: {
|
||||
type: jsPsych.plugins.parameterType.STRING,
|
||||
pretty_name: 'Prompt',
|
||||
default: null,
|
||||
description: 'Any content here will be displayed below the stimulus.'
|
||||
},
|
||||
trial_duration: {
|
||||
type: jsPsych.plugins.parameterType.INT,
|
||||
pretty_name: 'Trial duration',
|
||||
default: null,
|
||||
description: 'The maximum duration to wait for a response.'
|
||||
},
|
||||
response_ends_trial: {
|
||||
type: jsPsych.plugins.parameterType.BOOL,
|
||||
pretty_name: 'Response ends trial',
|
||||
default: true,
|
||||
description: 'If true, the trial will end when user makes a response.'
|
||||
},
|
||||
trial_ends_after_audio: {
|
||||
type: jsPsych.plugins.parameterType.BOOL,
|
||||
pretty_name: 'Trial ends after audio',
|
||||
default: false,
|
||||
description: 'If true, then the trial will end as soon as the audio file finishes playing.'
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
plugin.trial = function(display_element, trial) {
|
||||
|
||||
// setup stimulus
|
||||
var context = jsPsych.pluginAPI.audioContext();
|
||||
if(context !== null){
|
||||
var source = context.createBufferSource();
|
||||
source.buffer = jsPsych.pluginAPI.getAudioBuffer(trial.stimulus);
|
||||
source.connect(context.destination);
|
||||
} else {
|
||||
var audio = jsPsych.pluginAPI.getAudioBuffer(trial.stimulus);
|
||||
audio.currentTime = 0;
|
||||
}
|
||||
|
||||
// set up end event if trial needs it
|
||||
|
||||
if(trial.trial_ends_after_audio){
|
||||
if(context !== null){
|
||||
source.onended = function() {
|
||||
end_trial();
|
||||
}
|
||||
} else {
|
||||
audio.addEventListener('ended', end_trial);
|
||||
}
|
||||
}
|
||||
|
||||
// show prompt if there is one
|
||||
if (trial.prompt !== null) {
|
||||
display_element.innerHTML = trial.prompt;
|
||||
}
|
||||
|
||||
// store response
|
||||
var response = {
|
||||
rt: null,
|
||||
key: null
|
||||
};
|
||||
|
||||
// function to end trial when it is time
|
||||
function end_trial() {
|
||||
|
||||
// kill any remaining setTimeout handlers
|
||||
jsPsych.pluginAPI.clearAllTimeouts();
|
||||
|
||||
// stop the audio file if it is playing
|
||||
// remove end event listeners if they exist
|
||||
if(context !== null){
|
||||
source.stop();
|
||||
source.onended = function() { }
|
||||
} else {
|
||||
audio.pause();
|
||||
audio.removeEventListener('ended', end_trial);
|
||||
}
|
||||
|
||||
// kill keyboard listeners
|
||||
jsPsych.pluginAPI.cancelAllKeyboardResponses();
|
||||
|
||||
// gather the data to store for the trial
|
||||
if(context !== null && response.rt !== null){
|
||||
response.rt = Math.round(response.rt * 1000);
|
||||
}
|
||||
var trial_data = {
|
||||
"rt": response.rt,
|
||||
"stimulus": trial.stimulus,
|
||||
"key_press": response.key
|
||||
};
|
||||
|
||||
// clear the display
|
||||
display_element.innerHTML = '';
|
||||
|
||||
// move on to the next trial
|
||||
jsPsych.finishTrial(trial_data);
|
||||
};
|
||||
|
||||
// function to handle responses by the subject
|
||||
var after_response = function(info) {
|
||||
|
||||
// only record the first response
|
||||
if (response.key == null) {
|
||||
response = info;
|
||||
}
|
||||
|
||||
if (trial.response_ends_trial) {
|
||||
end_trial();
|
||||
}
|
||||
};
|
||||
|
||||
// start audio
|
||||
if(context !== null){
|
||||
startTime = context.currentTime;
|
||||
source.start(startTime);
|
||||
} else {
|
||||
audio.play();
|
||||
}
|
||||
|
||||
// start the response listener
|
||||
if(context !== null) {
|
||||
var keyboardListener = jsPsych.pluginAPI.getKeyboardResponse({
|
||||
callback_function: after_response,
|
||||
valid_responses: trial.choices,
|
||||
rt_method: 'audio',
|
||||
persist: false,
|
||||
allow_held_key: false,
|
||||
audio_context: context,
|
||||
audio_context_start_time: startTime
|
||||
});
|
||||
} else {
|
||||
var keyboardListener = jsPsych.pluginAPI.getKeyboardResponse({
|
||||
callback_function: after_response,
|
||||
valid_responses: trial.choices,
|
||||
rt_method: 'performance',
|
||||
persist: false,
|
||||
allow_held_key: false
|
||||
});
|
||||
}
|
||||
|
||||
// end trial if time limit is set
|
||||
if (trial.trial_duration !== null) {
|
||||
jsPsych.pluginAPI.setTimeout(function() {
|
||||
end_trial();
|
||||
}, trial.trial_duration);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
return plugin;
|
||||
})();
|
||||
214
PCSurvey/PCstatic/js/plugins/jspsych-audio-slider-response.js
Normal file
214
PCSurvey/PCstatic/js/plugins/jspsych-audio-slider-response.js
Normal file
@@ -0,0 +1,214 @@
|
||||
jsPsych.plugins['audio-slider-response'] = (function() {
|
||||
var plugin = {};
|
||||
|
||||
jsPsych.pluginAPI.registerPreload('audio-slider-response', 'stimulus', 'audio');
|
||||
|
||||
plugin.info = {
|
||||
name: 'audio-slider-response',
|
||||
description: '',
|
||||
parameters: {
|
||||
stimulus: {
|
||||
type: jsPsych.plugins.parameterType.AUDIO,
|
||||
pretty_name: 'Stimulus',
|
||||
default: undefined,
|
||||
description: 'The image to be displayed'
|
||||
},
|
||||
min: {
|
||||
type: jsPsych.plugins.parameterType.INT,
|
||||
pretty_name: 'Min slider',
|
||||
default: 0,
|
||||
description: 'Sets the minimum value of the slider.'
|
||||
},
|
||||
max: {
|
||||
type: jsPsych.plugins.parameterType.INT,
|
||||
pretty_name: 'Max slider',
|
||||
default: 100,
|
||||
description: 'Sets the maximum value of the slider',
|
||||
},
|
||||
start: {
|
||||
type: jsPsych.plugins.parameterType.INT,
|
||||
pretty_name: 'Slider starting value',
|
||||
default: 50,
|
||||
description: 'Sets the starting value of the slider',
|
||||
},
|
||||
step: {
|
||||
type: jsPsych.plugins.parameterType.INT,
|
||||
pretty_name: 'Step',
|
||||
default: 1,
|
||||
description: 'Sets the step of the slider'
|
||||
},
|
||||
labels: {
|
||||
type: jsPsych.plugins.parameterType.HTML_STRING,
|
||||
pretty_name:'Labels',
|
||||
default: [],
|
||||
array: true,
|
||||
description: 'Labels of the slider.',
|
||||
},
|
||||
slider_width: {
|
||||
type: jsPsych.plugins.parameterType.INT,
|
||||
pretty_name:'Slider width',
|
||||
default: null,
|
||||
description: 'Width of the slider in pixels.'
|
||||
},
|
||||
button_label: {
|
||||
type: jsPsych.plugins.parameterType.STRING,
|
||||
pretty_name: 'Button label',
|
||||
default: 'Continue',
|
||||
array: false,
|
||||
description: 'Label of the button to advance.'
|
||||
},
|
||||
require_movement: {
|
||||
type: jsPsych.plugins.parameterType.BOOL,
|
||||
pretty_name: 'Require movement',
|
||||
default: false,
|
||||
description: 'If true, the participant will have to move the slider before continuing.'
|
||||
},
|
||||
prompt: {
|
||||
type: jsPsych.plugins.parameterType.STRING,
|
||||
pretty_name: 'Prompt',
|
||||
default: null,
|
||||
description: 'Any content here will be displayed below the slider.'
|
||||
},
|
||||
trial_duration: {
|
||||
type: jsPsych.plugins.parameterType.INT,
|
||||
pretty_name: 'Trial duration',
|
||||
default: null,
|
||||
description: 'How long to show the trial.'
|
||||
},
|
||||
response_ends_trial: {
|
||||
type: jsPsych.plugins.parameterType.BOOL,
|
||||
pretty_name: 'Response ends trial',
|
||||
default: true,
|
||||
description: 'If true, trial will end when user makes a response.'
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
plugin.trial = function(display_element, trial) {
|
||||
|
||||
// setup stimulus
|
||||
var context = jsPsych.pluginAPI.audioContext();
|
||||
if(context !== null){
|
||||
var source = context.createBufferSource();
|
||||
source.buffer = jsPsych.pluginAPI.getAudioBuffer(trial.stimulus);
|
||||
source.connect(context.destination);
|
||||
} else {
|
||||
var audio = jsPsych.pluginAPI.getAudioBuffer(trial.stimulus);
|
||||
audio.currentTime = 0;
|
||||
}
|
||||
|
||||
// set up end event if trial needs it
|
||||
if(trial.trial_ends_after_audio){
|
||||
if(context !== null){
|
||||
source.onended = function() {
|
||||
end_trial();
|
||||
}
|
||||
} else {
|
||||
audio.addEventListener('ended', end_trial);
|
||||
}
|
||||
}
|
||||
|
||||
var html = '<div id="jspsych-audio-slider-response-wrapper" style="margin: 100px 0px;">';
|
||||
html += '<div class="jspsych-audio-slider-response-container" style="position:relative; margin: 0 auto 3em auto; ';
|
||||
if(trial.slider_width !== null){
|
||||
html += 'width:'+trial.slider_width+'px;';
|
||||
}
|
||||
html += '">';
|
||||
html += '<input type="range" value="'+trial.start+'" min="'+trial.min+'" max="'+trial.max+'" step="'+trial.step+'" style="width: 100%;" id="jspsych-audio-slider-response-response"></input>';
|
||||
html += '<div>'
|
||||
for(var j=0; j < trial.labels.length; j++){
|
||||
var width = 100/(trial.labels.length-1);
|
||||
var left_offset = (j * (100 /(trial.labels.length - 1))) - (width/2);
|
||||
html += '<div style="display: inline-block; position: absolute; left:'+left_offset+'%; text-align: center; width: '+width+'%;">';
|
||||
html += '<span style="text-align: center; font-size: 80%;">'+trial.labels[j]+'</span>';
|
||||
html += '</div>'
|
||||
}
|
||||
html += '</div>';
|
||||
html += '</div>';
|
||||
html += '</div>';
|
||||
|
||||
if (trial.prompt !== null){
|
||||
html += trial.prompt;
|
||||
}
|
||||
|
||||
// add submit button
|
||||
html += '<button id="jspsych-audio-slider-response-next" class="jspsych-btn" '+ (trial.require_movement ? "disabled" : "") + '>'+trial.button_label+'</button>';
|
||||
|
||||
display_element.innerHTML = html;
|
||||
|
||||
var response = {
|
||||
rt: null,
|
||||
response: null
|
||||
};
|
||||
|
||||
if(trial.require_movement){
|
||||
display_element.querySelector('#jspsych-audio-slider-response-response').addEventListener('change', function(){
|
||||
display_element.querySelector('#jspsych-audio-slider-response-next').disabled = false;
|
||||
})
|
||||
}
|
||||
|
||||
display_element.querySelector('#jspsych-audio-slider-response-next').addEventListener('click', function() {
|
||||
// measure response time
|
||||
var endTime = performance.now();
|
||||
var rt = endTime - startTime;
|
||||
if(context !== null){
|
||||
endTime = context.currentTime;
|
||||
rt = Math.round((endTime - startTime) * 1000);
|
||||
}
|
||||
response.rt = rt;
|
||||
response.response = display_element.querySelector('#jspsych-audio-slider-response-response').value;
|
||||
|
||||
if(trial.response_ends_trial){
|
||||
end_trial();
|
||||
} else {
|
||||
display_element.querySelector('#jspsych-audio-slider-response-next').disabled = true;
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
function end_trial(){
|
||||
|
||||
jsPsych.pluginAPI.clearAllTimeouts();
|
||||
|
||||
if(context !== null){
|
||||
source.stop();
|
||||
source.onended = function() { }
|
||||
} else {
|
||||
audio.pause();
|
||||
audio.removeEventListener('ended', end_trial);
|
||||
}
|
||||
|
||||
// save data
|
||||
var trialdata = {
|
||||
"rt": response.rt,
|
||||
"stimulus": trial.stimulus,
|
||||
"response": response.response
|
||||
};
|
||||
|
||||
display_element.innerHTML = '';
|
||||
|
||||
// next trial
|
||||
jsPsych.finishTrial(trialdata);
|
||||
}
|
||||
|
||||
var startTime = performance.now();
|
||||
// start audio
|
||||
if(context !== null){
|
||||
startTime = context.currentTime;
|
||||
source.start(startTime);
|
||||
} else {
|
||||
audio.play();
|
||||
}
|
||||
|
||||
// end trial if trial_duration is set
|
||||
if (trial.trial_duration !== null) {
|
||||
jsPsych.pluginAPI.setTimeout(function() {
|
||||
end_trial();
|
||||
}, trial.trial_duration);
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
return plugin;
|
||||
})();
|
||||
58
PCSurvey/PCstatic/js/plugins/jspsych-call-function.js
Normal file
58
PCSurvey/PCstatic/js/plugins/jspsych-call-function.js
Normal file
@@ -0,0 +1,58 @@
|
||||
/**
|
||||
* jspsych-call-function
|
||||
* plugin for calling an arbitrary function during a jspsych experiment
|
||||
* Josh de Leeuw
|
||||
*
|
||||
* documentation: docs.jspsych.org
|
||||
*
|
||||
**/
|
||||
|
||||
jsPsych.plugins['call-function'] = (function() {
|
||||
|
||||
var plugin = {};
|
||||
|
||||
plugin.info = {
|
||||
name: 'call-function',
|
||||
description: '',
|
||||
parameters: {
|
||||
func: {
|
||||
type: jsPsych.plugins.parameterType.FUNCTION,
|
||||
pretty_name: 'Function',
|
||||
default: undefined,
|
||||
description: 'Function to call'
|
||||
},
|
||||
async: {
|
||||
type: jsPsych.plugins.parameterType.BOOL,
|
||||
pretty_name: 'Asynchronous',
|
||||
default: false,
|
||||
description: 'Is the function call asynchronous?'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
plugin.trial = function(display_element, trial) {
|
||||
trial.post_trial_gap = 0;
|
||||
var return_val;
|
||||
|
||||
if(trial.async){
|
||||
var done = function(data){
|
||||
return_val = data;
|
||||
end_trial();
|
||||
}
|
||||
trial.func(done);
|
||||
} else {
|
||||
return_val = trial.func();
|
||||
end_trial();
|
||||
}
|
||||
|
||||
function end_trial(){
|
||||
var trial_data = {
|
||||
value: return_val
|
||||
};
|
||||
|
||||
jsPsych.finishTrial(trial_data);
|
||||
}
|
||||
};
|
||||
|
||||
return plugin;
|
||||
})();
|
||||
200
PCSurvey/PCstatic/js/plugins/jspsych-categorize-animation.js
Normal file
200
PCSurvey/PCstatic/js/plugins/jspsych-categorize-animation.js
Normal file
@@ -0,0 +1,200 @@
|
||||
/**
|
||||
* jspsych plugin for categorization trials with feedback and animated stimuli
|
||||
* Josh de Leeuw
|
||||
*
|
||||
* documentation: docs.jspsych.org
|
||||
**/
|
||||
|
||||
|
||||
jsPsych.plugins["categorize-animation"] = (function() {
|
||||
|
||||
var plugin = {};
|
||||
|
||||
jsPsych.pluginAPI.registerPreload('categorize-animation', 'stimuli', 'image');
|
||||
|
||||
plugin.info = {
|
||||
name: 'categorize-animation',
|
||||
description: '',
|
||||
parameters: {
|
||||
stimuli: {
|
||||
type: jsPsych.plugins.parameterType.IMAGE,
|
||||
pretty_name: 'Stimuli',
|
||||
default: undefined,
|
||||
description: 'Array of paths to image files.'
|
||||
},
|
||||
key_answer: {
|
||||
type: jsPsych.plugins.parameterType.KEYCODE,
|
||||
pretty_name: 'Key answer',
|
||||
default: undefined,
|
||||
description: 'The key to indicate correct response'
|
||||
},
|
||||
choices: {
|
||||
type: jsPsych.plugins.parameterType.KEYCODE,
|
||||
pretty_name: 'Choices',
|
||||
default: jsPsych.ALL_KEYS,
|
||||
array: true,
|
||||
description: 'The keys subject is allowed to press to respond to stimuli.'
|
||||
},
|
||||
text_answer: {
|
||||
type: jsPsych.plugins.parameterType.STRING,
|
||||
pretty_name: 'Text answer',
|
||||
default: null,
|
||||
description: 'Text to describe correct answer.'
|
||||
},
|
||||
correct_text: {
|
||||
type: jsPsych.plugins.parameterType.STRING,
|
||||
pretty_name: 'Correct text',
|
||||
default: 'Correct.',
|
||||
description: 'String to show when subject gives correct answer'
|
||||
},
|
||||
incorrect_text: {
|
||||
type: jsPsych.plugins.parameterType.STRING,
|
||||
pretty_name: 'Incorrect text',
|
||||
default: 'Wrong.',
|
||||
description: 'String to show when subject gives incorrect answer.'
|
||||
},
|
||||
frame_time: {
|
||||
type: jsPsych.plugins.parameterType.INT,
|
||||
pretty_name: 'Frame time',
|
||||
default: 500,
|
||||
description: 'Duration to display each image.'
|
||||
},
|
||||
sequence_reps: {
|
||||
type: jsPsych.plugins.parameterType.INT,
|
||||
pretty_name: 'Sequence repetitions',
|
||||
default: 1,
|
||||
description: 'How many times to display entire sequence.'
|
||||
},
|
||||
allow_response_before_complete: {
|
||||
type: jsPsych.plugins.parameterType.BOOL,
|
||||
pretty_name: 'Allow response before complete',
|
||||
default: false,
|
||||
description: 'If true, subject can response before the animation sequence finishes'
|
||||
},
|
||||
feedback_duration: {
|
||||
type: jsPsych.plugins.parameterType.INT,
|
||||
pretty_name: 'Feedback duration',
|
||||
default: 2000,
|
||||
description: 'How long to show feedback'
|
||||
},
|
||||
prompt: {
|
||||
type: jsPsych.plugins.parameterType.STRING,
|
||||
pretty_name: 'Prompt',
|
||||
default: null,
|
||||
description: 'Any content here will be displayed below the stimulus.'
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
plugin.trial = function(display_element, trial) {
|
||||
|
||||
var animate_frame = -1;
|
||||
var reps = 0;
|
||||
|
||||
var showAnimation = true;
|
||||
|
||||
var responded = false;
|
||||
var timeoutSet = false;
|
||||
var correct;
|
||||
|
||||
// show animation
|
||||
var animate_interval = setInterval(function() {
|
||||
display_element.innerHTML = ''; // clear everything
|
||||
animate_frame++;
|
||||
if (animate_frame == trial.stimuli.length) {
|
||||
animate_frame = 0;
|
||||
reps++;
|
||||
// check if reps complete //
|
||||
if (trial.sequence_reps != -1 && reps >= trial.sequence_reps) {
|
||||
// done with animation
|
||||
showAnimation = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (showAnimation) {
|
||||
display_element.innerHTML += '<img src="'+trial.stimuli[animate_frame]+'" class="jspsych-categorize-animation-stimulus"></img>';
|
||||
}
|
||||
|
||||
if (!responded && trial.allow_response_before_complete) {
|
||||
// in here if the user can respond before the animation is done
|
||||
if (trial.prompt !== null) {
|
||||
display_element.innerHTML += trial.prompt;
|
||||
}
|
||||
} else if (!responded) {
|
||||
// in here if the user has to wait to respond until animation is done.
|
||||
// if this is the case, don't show the prompt until the animation is over.
|
||||
if (!showAnimation) {
|
||||
if (trial.prompt !== null) {
|
||||
display_element.innerHTML += trial.prompt;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// user has responded if we get here.
|
||||
|
||||
// show feedback
|
||||
var feedback_text = "";
|
||||
if (correct) {
|
||||
feedback_text = trial.correct_text.replace("%ANS%", trial.text_answer);
|
||||
} else {
|
||||
feedback_text = trial.incorrect_text.replace("%ANS%", trial.text_answer);
|
||||
}
|
||||
display_element.innerHTML += feedback_text;
|
||||
|
||||
// set timeout to clear feedback
|
||||
if (!timeoutSet) {
|
||||
timeoutSet = true;
|
||||
jsPsych.pluginAPI.setTimeout(function() {
|
||||
endTrial();
|
||||
}, trial.feedback_duration);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}, trial.frame_time);
|
||||
|
||||
|
||||
var keyboard_listener;
|
||||
var trial_data = {};
|
||||
|
||||
var after_response = function(info) {
|
||||
// ignore the response if animation is playing and subject
|
||||
// not allowed to respond before it is complete
|
||||
if (!trial.allow_response_before_complete && showAnimation) {
|
||||
return false;
|
||||
}
|
||||
|
||||
correct = false;
|
||||
if (trial.key_answer == info.key) {
|
||||
correct = true;
|
||||
}
|
||||
|
||||
responded = true;
|
||||
|
||||
trial_data = {
|
||||
"stimulus": JSON.stringify(trial.stimuli),
|
||||
"rt": info.rt,
|
||||
"correct": correct,
|
||||
"key_press": info.key
|
||||
};
|
||||
|
||||
jsPsych.pluginAPI.cancelKeyboardResponse(keyboard_listener);
|
||||
|
||||
}
|
||||
|
||||
keyboard_listener = jsPsych.pluginAPI.getKeyboardResponse({
|
||||
callback_function: after_response,
|
||||
valid_responses: trial.choices,
|
||||
rt_method: 'performance',
|
||||
persist: true,
|
||||
allow_held_key: false
|
||||
});
|
||||
|
||||
function endTrial() {
|
||||
clearInterval(animate_interval); // stop animation!
|
||||
display_element.innerHTML = ''; // clear everything
|
||||
jsPsych.finishTrial(trial_data);
|
||||
}
|
||||
};
|
||||
|
||||
return plugin;
|
||||
})();
|
||||
220
PCSurvey/PCstatic/js/plugins/jspsych-categorize-html.js
Normal file
220
PCSurvey/PCstatic/js/plugins/jspsych-categorize-html.js
Normal file
@@ -0,0 +1,220 @@
|
||||
/**
|
||||
* jspsych plugin for categorization trials with feedback
|
||||
* Josh de Leeuw
|
||||
*
|
||||
* documentation: docs.jspsych.org
|
||||
**/
|
||||
|
||||
|
||||
jsPsych.plugins['categorize-html'] = (function() {
|
||||
|
||||
var plugin = {};
|
||||
|
||||
plugin.info = {
|
||||
name: 'categorize-html',
|
||||
description: '',
|
||||
parameters: {
|
||||
stimulus: {
|
||||
type: jsPsych.plugins.parameterType.HTML_STRING,
|
||||
pretty_name: 'Stimulus',
|
||||
default: undefined,
|
||||
description: 'The HTML content to be displayed.'
|
||||
},
|
||||
key_answer: {
|
||||
type: jsPsych.plugins.parameterType.KEYCODE,
|
||||
pretty_name: 'Key answer',
|
||||
default: undefined,
|
||||
description: 'The key to indicate the correct response.'
|
||||
},
|
||||
choices: {
|
||||
type: jsPsych.plugins.parameterType.KEYCODE,
|
||||
pretty_name: 'Choices',
|
||||
default: jsPsych.ALL_KEYS,
|
||||
array: true,
|
||||
description: 'The keys the subject is allowed to press to respond to the stimulus.'
|
||||
},
|
||||
text_answer: {
|
||||
type: jsPsych.plugins.parameterType.STRING,
|
||||
pretty_name: 'Text answer',
|
||||
default: null,
|
||||
description: 'Label that is associated with the correct answer.'
|
||||
},
|
||||
correct_text: {
|
||||
type: jsPsych.plugins.parameterType.STRING,
|
||||
pretty_name: 'Correct text',
|
||||
default: "<p class='feedback'>Correct</p>",
|
||||
description: 'String to show when correct answer is given.'
|
||||
},
|
||||
incorrect_text: {
|
||||
type: jsPsych.plugins.parameterType.STRING,
|
||||
pretty_name: 'Incorrect text',
|
||||
default: "<p class='feedback'>Incorrect</p>",
|
||||
description: 'String to show when incorrect answer is given.'
|
||||
},
|
||||
prompt: {
|
||||
type: jsPsych.plugins.parameterType.STRING,
|
||||
pretty_name: 'Prompt',
|
||||
default: null,
|
||||
description: 'Any content here will be displayed below the stimulus.'
|
||||
},
|
||||
force_correct_button_press: {
|
||||
type: jsPsych.plugins.parameterType.BOOL,
|
||||
pretty_name: 'Force correct button press',
|
||||
default: false,
|
||||
description: 'If set to true, then the subject must press the correct response key after feedback in order to advance to next trial.'
|
||||
},
|
||||
show_stim_with_feedback: {
|
||||
type: jsPsych.plugins.parameterType.BOOL,
|
||||
default: true,
|
||||
no_function: false,
|
||||
description: ''
|
||||
},
|
||||
show_feedback_on_timeout: {
|
||||
type: jsPsych.plugins.parameterType.BOOL,
|
||||
pretty_name: 'Show feedback on timeout',
|
||||
default: false,
|
||||
description: 'If true, stimulus will be shown during feedback. If false, only the text feedback will be displayed during feedback.'
|
||||
},
|
||||
timeout_message: {
|
||||
type: jsPsych.plugins.parameterType.STRING,
|
||||
pretty_name: 'Timeout message',
|
||||
default: "<p>Please respond faster.</p>",
|
||||
description: 'The message displayed on a timeout non-response.'
|
||||
},
|
||||
stimulus_duration: {
|
||||
type: jsPsych.plugins.parameterType.INT,
|
||||
pretty_name: 'Stimulus duration',
|
||||
default: null,
|
||||
description: 'How long to hide stimulus.'
|
||||
},
|
||||
trial_duration: {
|
||||
type: jsPsych.plugins.parameterType.INT,
|
||||
pretty_name: 'Trial duration',
|
||||
default: null,
|
||||
description: 'How long to show trial'
|
||||
},
|
||||
feedback_duration: {
|
||||
type: jsPsych.plugins.parameterType.INT,
|
||||
pretty_name: 'Feedback duration',
|
||||
default: 2000,
|
||||
description: 'How long to show feedback.'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
plugin.trial = function(display_element, trial) {
|
||||
|
||||
display_element.innerHTML = '<div id="jspsych-categorize-html-stimulus" class="jspsych-categorize-html-stimulus">'+trial.stimulus+'</div>';
|
||||
|
||||
// hide image after time if the timing parameter is set
|
||||
if (trial.stimulus_duration !== null) {
|
||||
jsPsych.pluginAPI.setTimeout(function() {
|
||||
display_element.querySelector('#jspsych-categorize-html-stimulus').style.visibility = 'hidden';
|
||||
}, trial.stimulus_duration);
|
||||
}
|
||||
|
||||
// if prompt is set, show prompt
|
||||
if (trial.prompt !== null) {
|
||||
display_element.innerHTML += trial.prompt;
|
||||
}
|
||||
|
||||
var trial_data = {};
|
||||
|
||||
// create response function
|
||||
var after_response = function(info) {
|
||||
|
||||
// kill any remaining setTimeout handlers
|
||||
jsPsych.pluginAPI.clearAllTimeouts();
|
||||
|
||||
// clear keyboard listener
|
||||
jsPsych.pluginAPI.cancelAllKeyboardResponses();
|
||||
|
||||
var correct = false;
|
||||
if (trial.key_answer == info.key) {
|
||||
correct = true;
|
||||
}
|
||||
|
||||
// save data
|
||||
trial_data = {
|
||||
"rt": info.rt,
|
||||
"correct": correct,
|
||||
"stimulus": trial.stimulus,
|
||||
"key_press": info.key
|
||||
};
|
||||
|
||||
display_element.innerHTML = '';
|
||||
|
||||
var timeout = info.rt == null;
|
||||
doFeedback(correct, timeout);
|
||||
}
|
||||
|
||||
jsPsych.pluginAPI.getKeyboardResponse({
|
||||
callback_function: after_response,
|
||||
valid_responses: trial.choices,
|
||||
rt_method: 'performance',
|
||||
persist: false,
|
||||
allow_held_key: false
|
||||
});
|
||||
|
||||
if (trial.trial_duration !== null) {
|
||||
jsPsych.pluginAPI.setTimeout(function() {
|
||||
after_response({
|
||||
key: null,
|
||||
rt: null
|
||||
});
|
||||
}, trial.trial_duration);
|
||||
}
|
||||
|
||||
function doFeedback(correct, timeout) {
|
||||
|
||||
if (timeout && !trial.show_feedback_on_timeout) {
|
||||
display_element.innerHTML += trial.timeout_message;
|
||||
} else {
|
||||
// show image during feedback if flag is set
|
||||
if (trial.show_stim_with_feedback) {
|
||||
display_element.innerHTML = '<div id="jspsych-categorize-html-stimulus" class="jspsych-categorize-html-stimulus">'+trial.stimulus+'</div>';
|
||||
}
|
||||
|
||||
// substitute answer in feedback string.
|
||||
var atext = "";
|
||||
if (correct) {
|
||||
atext = trial.correct_text.replace("%ANS%", trial.text_answer);
|
||||
} else {
|
||||
atext = trial.incorrect_text.replace("%ANS%", trial.text_answer);
|
||||
}
|
||||
|
||||
// show the feedback
|
||||
display_element.innerHTML += atext;
|
||||
}
|
||||
// check if force correct button press is set
|
||||
if (trial.force_correct_button_press && correct === false && ((timeout && trial.show_feedback_on_timeout) || !timeout)) {
|
||||
|
||||
var after_forced_response = function(info) {
|
||||
endTrial();
|
||||
}
|
||||
|
||||
jsPsych.pluginAPI.getKeyboardResponse({
|
||||
callback_function: after_forced_response,
|
||||
valid_responses: [trial.key_answer],
|
||||
rt_method: 'performance',
|
||||
persist: false,
|
||||
allow_held_key: false
|
||||
});
|
||||
|
||||
} else {
|
||||
jsPsych.pluginAPI.setTimeout(function() {
|
||||
endTrial();
|
||||
}, trial.feedback_duration);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function endTrial() {
|
||||
display_element.innerHTML = '';
|
||||
jsPsych.finishTrial(trial_data);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
return plugin;
|
||||
})();
|
||||
222
PCSurvey/PCstatic/js/plugins/jspsych-categorize-image.js
Normal file
222
PCSurvey/PCstatic/js/plugins/jspsych-categorize-image.js
Normal file
@@ -0,0 +1,222 @@
|
||||
/**
|
||||
* jspsych plugin for categorization trials with feedback
|
||||
* Josh de Leeuw
|
||||
*
|
||||
* documentation: docs.jspsych.org
|
||||
**/
|
||||
|
||||
|
||||
jsPsych.plugins['categorize-image'] = (function() {
|
||||
|
||||
var plugin = {};
|
||||
|
||||
jsPsych.pluginAPI.registerPreload('categorize-image', 'stimulus', 'image');
|
||||
|
||||
plugin.info = {
|
||||
name: 'categorize-image',
|
||||
description: '',
|
||||
parameters: {
|
||||
stimulus: {
|
||||
type: jsPsych.plugins.parameterType.IMAGE,
|
||||
pretty_name: 'Stimulus',
|
||||
default: undefined,
|
||||
description: 'The image content to be displayed.'
|
||||
},
|
||||
key_answer: {
|
||||
type: jsPsych.plugins.parameterType.KEYCODE,
|
||||
pretty_name: 'Key answer',
|
||||
default: undefined,
|
||||
description: 'The key to indicate the correct response.'
|
||||
},
|
||||
choices: {
|
||||
type: jsPsych.plugins.parameterType.KEYCODE,
|
||||
pretty_name: 'Choices',
|
||||
default: jsPsych.ALL_KEYS,
|
||||
array: true,
|
||||
description: 'The keys the subject is allowed to press to respond to the stimulus.'
|
||||
},
|
||||
text_answer: {
|
||||
type: jsPsych.plugins.parameterType.STRING,
|
||||
pretty_name: 'Text answer',
|
||||
default: null,
|
||||
description: 'Label that is associated with the correct answer.'
|
||||
},
|
||||
correct_text: {
|
||||
type: jsPsych.plugins.parameterType.STRING,
|
||||
pretty_name: 'Correct text',
|
||||
default: "<p class='feedback'>Correct</p>",
|
||||
description: 'String to show when correct answer is given.'
|
||||
},
|
||||
incorrect_text: {
|
||||
type: jsPsych.plugins.parameterType.STRING,
|
||||
pretty_name: 'Incorrect text',
|
||||
default: "<p class='feedback'>Incorrect</p>",
|
||||
description: 'String to show when incorrect answer is given.'
|
||||
},
|
||||
prompt: {
|
||||
type: jsPsych.plugins.parameterType.STRING,
|
||||
pretty_name: 'Prompt',
|
||||
default: null,
|
||||
description: 'Any content here will be displayed below the stimulus.'
|
||||
},
|
||||
force_correct_button_press: {
|
||||
type: jsPsych.plugins.parameterType.BOOL,
|
||||
pretty_name: 'Force correct button press',
|
||||
default: false,
|
||||
description: 'If set to true, then the subject must press the correct response key after feedback in order to advance to next trial.'
|
||||
},
|
||||
show_stim_with_feedback: {
|
||||
type: jsPsych.plugins.parameterType.BOOL,
|
||||
default: true,
|
||||
no_function: false,
|
||||
description: ''
|
||||
},
|
||||
show_feedback_on_timeout: {
|
||||
type: jsPsych.plugins.parameterType.BOOL,
|
||||
pretty_name: 'Show feedback on timeout',
|
||||
default: false,
|
||||
description: 'If true, stimulus will be shown during feedback. If false, only the text feedback will be displayed during feedback.'
|
||||
},
|
||||
timeout_message: {
|
||||
type: jsPsych.plugins.parameterType.STRING,
|
||||
pretty_name: 'Timeout message',
|
||||
default: "<p>Please respond faster.</p>",
|
||||
description: 'The message displayed on a timeout non-response.'
|
||||
},
|
||||
stimulus_duration: {
|
||||
type: jsPsych.plugins.parameterType.INT,
|
||||
pretty_name: 'Stimulus duration',
|
||||
default: null,
|
||||
description: 'How long to hide stimulus.'
|
||||
},
|
||||
trial_duration: {
|
||||
type: jsPsych.plugins.parameterType.INT,
|
||||
pretty_name: 'Trial duration',
|
||||
default: null,
|
||||
description: 'How long to show trial'
|
||||
},
|
||||
feedback_duration: {
|
||||
type: jsPsych.plugins.parameterType.INT,
|
||||
pretty_name: 'Feedback duration',
|
||||
default: 2000,
|
||||
description: 'How long to show feedback.'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
plugin.trial = function(display_element, trial) {
|
||||
|
||||
display_element.innerHTML = '<img id="jspsych-categorize-image-stimulus" class="jspsych-categorize-image-stimulus" src="'+trial.stimulus+'"></img>';
|
||||
|
||||
// hide image after time if the timing parameter is set
|
||||
if (trial.stimulus_duration !== null) {
|
||||
jsPsych.pluginAPI.setTimeout(function() {
|
||||
display_element.querySelector('#jspsych-categorize-image-stimulus').style.visibility = 'hidden';
|
||||
}, trial.stimulus_duration);
|
||||
}
|
||||
|
||||
// if prompt is set, show prompt
|
||||
if (trial.prompt !== null) {
|
||||
display_element.innerHTML += trial.prompt;
|
||||
}
|
||||
|
||||
var trial_data = {};
|
||||
|
||||
// create response function
|
||||
var after_response = function(info) {
|
||||
|
||||
// kill any remaining setTimeout handlers
|
||||
jsPsych.pluginAPI.clearAllTimeouts();
|
||||
|
||||
// clear keyboard listener
|
||||
jsPsych.pluginAPI.cancelAllKeyboardResponses();
|
||||
|
||||
var correct = false;
|
||||
if (trial.key_answer == info.key) {
|
||||
correct = true;
|
||||
}
|
||||
|
||||
// save data
|
||||
trial_data = {
|
||||
"rt": info.rt,
|
||||
"correct": correct,
|
||||
"stimulus": trial.stimulus,
|
||||
"key_press": info.key
|
||||
};
|
||||
|
||||
display_element.innerHTML = '';
|
||||
|
||||
var timeout = info.rt == null;
|
||||
doFeedback(correct, timeout);
|
||||
}
|
||||
|
||||
jsPsych.pluginAPI.getKeyboardResponse({
|
||||
callback_function: after_response,
|
||||
valid_responses: trial.choices,
|
||||
rt_method: 'performance',
|
||||
persist: false,
|
||||
allow_held_key: false
|
||||
});
|
||||
|
||||
if (trial.trial_duration !== null) {
|
||||
jsPsych.pluginAPI.setTimeout(function() {
|
||||
after_response({
|
||||
key: null,
|
||||
rt: null
|
||||
});
|
||||
}, trial.trial_duration);
|
||||
}
|
||||
|
||||
function doFeedback(correct, timeout) {
|
||||
|
||||
if (timeout && !trial.show_feedback_on_timeout) {
|
||||
display_element.innerHTML += trial.timeout_message;
|
||||
} else {
|
||||
// show image during feedback if flag is set
|
||||
if (trial.show_stim_with_feedback) {
|
||||
display_element.innerHTML = '<img id="jspsych-categorize-image-stimulus" class="jspsych-categorize-image-stimulus" src="'+trial.stimulus+'"></img>';
|
||||
}
|
||||
|
||||
// substitute answer in feedback string.
|
||||
var atext = "";
|
||||
if (correct) {
|
||||
atext = trial.correct_text.replace("%ANS%", trial.text_answer);
|
||||
} else {
|
||||
atext = trial.incorrect_text.replace("%ANS%", trial.text_answer);
|
||||
}
|
||||
|
||||
// show the feedback
|
||||
display_element.innerHTML += atext;
|
||||
}
|
||||
// check if force correct button press is set
|
||||
if (trial.force_correct_button_press && correct === false && ((timeout && trial.show_feedback_on_timeout) || !timeout)) {
|
||||
|
||||
var after_forced_response = function(info) {
|
||||
endTrial();
|
||||
}
|
||||
|
||||
jsPsych.pluginAPI.getKeyboardResponse({
|
||||
callback_function: after_forced_response,
|
||||
valid_responses: [trial.key_answer],
|
||||
rt_method: 'performance',
|
||||
persist: false,
|
||||
allow_held_key: false
|
||||
});
|
||||
|
||||
} else {
|
||||
jsPsych.pluginAPI.setTimeout(function() {
|
||||
endTrial();
|
||||
}, trial.feedback_duration);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function endTrial() {
|
||||
display_element.innerHTML = '';
|
||||
jsPsych.finishTrial(trial_data);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
return plugin;
|
||||
})();
|
||||
112
PCSurvey/PCstatic/js/plugins/jspsych-cloze.js
Normal file
112
PCSurvey/PCstatic/js/plugins/jspsych-cloze.js
Normal file
@@ -0,0 +1,112 @@
|
||||
/**
|
||||
* jspsych-cloze
|
||||
* Philipp Sprengholz
|
||||
*
|
||||
* Plugin for displaying a cloze test and checking participants answers against a correct solution.
|
||||
*
|
||||
* documentation: docs.jspsych.org
|
||||
**/
|
||||
|
||||
jsPsych.plugins['cloze'] = (function () {
|
||||
|
||||
var plugin = {};
|
||||
|
||||
plugin.info = {
|
||||
name: 'cloze',
|
||||
description: '',
|
||||
parameters: {
|
||||
text: {
|
||||
type: jsPsych.plugins.parameterType.STRING,
|
||||
pretty_name: 'Cloze text',
|
||||
default: undefined,
|
||||
description: 'The cloze text to be displayed. Blanks are indicated by %% signs and automatically replaced by input fields. If there is a correct answer you want the system to check against, it must be typed between the two percentage signs (i.e. %solution%).'
|
||||
},
|
||||
button_text: {
|
||||
type: jsPsych.plugins.parameterType.STRING,
|
||||
pretty_name: 'Button text',
|
||||
default: 'OK',
|
||||
description: 'Text of the button participants have to press for finishing the cloze test.'
|
||||
},
|
||||
check_answers: {
|
||||
type: jsPsych.plugins.parameterType.BOOL,
|
||||
pretty_name: 'Check answers',
|
||||
default: false,
|
||||
description: 'Boolean value indicating if the answers given by participants should be compared against a correct solution given in the text (between % signs) after the button was clicked.'
|
||||
},
|
||||
mistake_fn: {
|
||||
type: jsPsych.plugins.parameterType.FUNCTION,
|
||||
pretty_name: 'Mistake function',
|
||||
default: function () {},
|
||||
description: 'Function called if check_answers is set to TRUE and there is a difference between the participants answers and the correct solution provided in the text.'
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
plugin.trial = function (display_element, trial) {
|
||||
|
||||
var html = '<div class="cloze">';
|
||||
var elements = trial.text.split('%');
|
||||
var solutions = [];
|
||||
|
||||
for (i=0; i<elements.length; i++)
|
||||
{
|
||||
if (i%2 === 0)
|
||||
{
|
||||
html += elements[i];
|
||||
}
|
||||
else
|
||||
{
|
||||
solutions.push(elements[i].trim());
|
||||
html += '<input type="text" id="input'+(solutions.length-1)+'" value="">';
|
||||
}
|
||||
}
|
||||
html += '</div>';
|
||||
|
||||
display_element.innerHTML = html;
|
||||
|
||||
var check = function() {
|
||||
|
||||
var answers = [];
|
||||
var answers_correct = true;
|
||||
|
||||
for (i=0; i<solutions.length; i++)
|
||||
{
|
||||
var field = document.getElementById('input'+i);
|
||||
answers.push(field.value.trim());
|
||||
|
||||
if (trial.check_answers)
|
||||
{
|
||||
if (answers[i] !== solutions[i])
|
||||
{
|
||||
field.style.color = 'red';
|
||||
answers_correct = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
field.style.color = 'black';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!trial.check_answers || (trial.check_answers && answers_correct))
|
||||
{
|
||||
var trial_data = {
|
||||
'answers' : answers
|
||||
};
|
||||
|
||||
display_element.innerHTML = '';
|
||||
jsPsych.finishTrial(trial_data);
|
||||
}
|
||||
else
|
||||
{
|
||||
trial.mistake_fn();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
display_element.innerHTML += '<br><button class="jspsych-html-button-response-button" type="button" id="finish_cloze_button">'+trial.button_text+'</button>';
|
||||
display_element.querySelector('#finish_cloze_button').addEventListener('click', check);
|
||||
};
|
||||
|
||||
return plugin;
|
||||
})();
|
||||
108
PCSurvey/PCstatic/js/plugins/jspsych-external-html.js
Normal file
108
PCSurvey/PCstatic/js/plugins/jspsych-external-html.js
Normal file
@@ -0,0 +1,108 @@
|
||||
/** (July 2012, Erik Weitnauer)
|
||||
The html-plugin will load and display an external html pages. To proceed to the next, the
|
||||
user might either press a button on the page or a specific key. Afterwards, the page get hidden and
|
||||
the plugin will wait of a specified time before it proceeds.
|
||||
|
||||
documentation: docs.jspsych.org
|
||||
*/
|
||||
|
||||
jsPsych.plugins['external-html'] = (function() {
|
||||
|
||||
var plugin = {};
|
||||
|
||||
plugin.info = {
|
||||
name: 'external-html',
|
||||
description: '',
|
||||
parameters: {
|
||||
url: {
|
||||
type: jsPsych.plugins.parameterType.STRING,
|
||||
pretty_name: 'URL',
|
||||
default: undefined,
|
||||
description: 'The url of the external html page'
|
||||
},
|
||||
cont_key: {
|
||||
type: jsPsych.plugins.parameterType.KEYCODE,
|
||||
pretty_name: 'Continue key',
|
||||
default: null,
|
||||
description: 'The key to continue to the next page.'
|
||||
},
|
||||
cont_btn: {
|
||||
type: jsPsych.plugins.parameterType.STRING,
|
||||
pretty_name: 'Continue button',
|
||||
default: null,
|
||||
description: 'The button to continue to the next page.'
|
||||
},
|
||||
check_fn: {
|
||||
type: jsPsych.plugins.parameterType.FUNCTION,
|
||||
pretty_name: 'Check function',
|
||||
default: function() { return true; },
|
||||
description: ''
|
||||
},
|
||||
force_refresh: {
|
||||
type: jsPsych.plugins.parameterType.BOOL,
|
||||
pretty_name: 'Force refresh',
|
||||
default: false,
|
||||
description: 'Refresh page.'
|
||||
},
|
||||
executeScript: {
|
||||
type: jsPsych.plugins.parameterType.BOOL,
|
||||
pretty_name: 'Execute scripts',
|
||||
default: false,
|
||||
description: 'If true, execute scripts on the external html file.'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
plugin.trial = function(display_element, trial) {
|
||||
|
||||
var url = trial.url;
|
||||
if (trial.force_refresh) {
|
||||
url = trial.url + "?time=" + (new Date().getTime());
|
||||
}
|
||||
|
||||
load(display_element, url, function() {
|
||||
var t0 = (new Date()).getTime();
|
||||
var finish = function() {
|
||||
if (trial.check_fn && !trial.check_fn(display_element)) { return };
|
||||
if (trial.cont_key) { document.removeEventListener('keydown', key_listener); }
|
||||
var trial_data = {
|
||||
rt: (new Date()).getTime() - t0,
|
||||
url: trial.url
|
||||
};
|
||||
display_element.innerHTML = '';
|
||||
jsPsych.finishTrial(trial_data);
|
||||
};
|
||||
|
||||
if (trial.executeScript) {
|
||||
for (const scriptEl of display_element.getElementsByTagName("script")) {
|
||||
const relocatedScript = document.createElement("script");
|
||||
relocatedScript.text = scriptEl.text;
|
||||
scriptEl.parentNode.replaceChild(relocatedScript, scriptEl);
|
||||
};
|
||||
}
|
||||
|
||||
if (trial.cont_btn) { display_element.querySelector('#'+trial.cont_btn).addEventListener('click', finish); }
|
||||
if (trial.cont_key) {
|
||||
var key_listener = function(e) {
|
||||
if (e.which == trial.cont_key) finish();
|
||||
};
|
||||
display_element.addEventListener('keydown', key_listener);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// helper to load via XMLHttpRequest
|
||||
function load(element, file, callback){
|
||||
var xmlhttp = new XMLHttpRequest();
|
||||
xmlhttp.open("GET", file, true);
|
||||
xmlhttp.onload = function(){
|
||||
if(xmlhttp.status == 200 || xmlhttp.status == 0){ //Check if loaded
|
||||
element.innerHTML = xmlhttp.responseText;
|
||||
callback();
|
||||
}
|
||||
}
|
||||
xmlhttp.send();
|
||||
}
|
||||
|
||||
return plugin;
|
||||
})();
|
||||
194
PCSurvey/PCstatic/js/plugins/jspsych-free-sort.js
Normal file
194
PCSurvey/PCstatic/js/plugins/jspsych-free-sort.js
Normal file
@@ -0,0 +1,194 @@
|
||||
/**
|
||||
* jspsych-free-sort
|
||||
* plugin for drag-and-drop sorting of a collection of images
|
||||
* Josh de Leeuw
|
||||
*
|
||||
* documentation: docs.jspsych.org
|
||||
*/
|
||||
|
||||
|
||||
jsPsych.plugins['free-sort'] = (function() {
|
||||
|
||||
var plugin = {};
|
||||
|
||||
jsPsych.pluginAPI.registerPreload('free-sort', 'stimuli', 'image');
|
||||
|
||||
plugin.info = {
|
||||
name: 'free-sort',
|
||||
description: '',
|
||||
parameters: {
|
||||
stimuli: {
|
||||
type: jsPsych.plugins.parameterType.STRING,
|
||||
pretty_name: 'Stimuli',
|
||||
default: undefined,
|
||||
array: true,
|
||||
description: 'Images to be displayed.'
|
||||
},
|
||||
stim_height: {
|
||||
type: jsPsych.plugins.parameterType.INT,
|
||||
pretty_name: 'Stimulus height',
|
||||
default: 100,
|
||||
description: 'Height of images in pixels.'
|
||||
},
|
||||
stim_width: {
|
||||
type: jsPsych.plugins.parameterType.INT,
|
||||
pretty_name: 'Stimulus width',
|
||||
default: 100,
|
||||
description: 'Width of images in pixels'
|
||||
},
|
||||
sort_area_height: {
|
||||
type: jsPsych.plugins.parameterType.INT,
|
||||
pretty_name: 'Sort area height',
|
||||
default: 800,
|
||||
description: 'The height of the container that subjects can move the stimuli in.'
|
||||
},
|
||||
sort_area_width: {
|
||||
type: jsPsych.plugins.parameterType.INT,
|
||||
pretty_name: 'Sort area width',
|
||||
default: 800,
|
||||
description: 'The width of the container that subjects can move the stimuli in.'
|
||||
},
|
||||
prompt: {
|
||||
type: jsPsych.plugins.parameterType.STRING,
|
||||
pretty_name: 'Prompt',
|
||||
default: null,
|
||||
description: 'It can be used to provide a reminder about the action the subject is supposed to take.'
|
||||
},
|
||||
prompt_location: {
|
||||
type: jsPsych.plugins.parameterType.SELECT,
|
||||
pretty_name: 'Prompt location',
|
||||
options: ['above','below'],
|
||||
default: 'above',
|
||||
description: 'Indicates whether to show prompt "above" or "below" the sorting area.'
|
||||
},
|
||||
button_label: {
|
||||
type: jsPsych.plugins.parameterType.STRING,
|
||||
pretty_name: 'Button label',
|
||||
default: 'Continue',
|
||||
description: 'The text that appears on the button to continue to the next trial.'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
plugin.trial = function(display_element, trial) {
|
||||
|
||||
var start_time = performance.now();
|
||||
|
||||
var html = "";
|
||||
// check if there is a prompt and if it is shown above
|
||||
if (trial.prompt !== null && trial.prompt_location == "above") {
|
||||
html += trial.prompt;
|
||||
}
|
||||
|
||||
html += '<div '+
|
||||
'id="jspsych-free-sort-arena" '+
|
||||
'class="jspsych-free-sort-arena" '+
|
||||
'style="position: relative; width:'+trial.sort_area_width+'px; height:'+trial.sort_area_height+'px; border:2px solid #444;"'+
|
||||
'></div>';
|
||||
|
||||
// check if prompt exists and if it is shown below
|
||||
if (trial.prompt !== null && trial.prompt_location == "below") {
|
||||
html += trial.prompt;
|
||||
}
|
||||
|
||||
display_element.innerHTML = html;
|
||||
|
||||
// store initial location data
|
||||
var init_locations = [];
|
||||
|
||||
for (var i = 0; i < trial.stimuli.length; i++) {
|
||||
var coords = random_coordinate(trial.sort_area_width - trial.stim_width, trial.sort_area_height - trial.stim_height);
|
||||
|
||||
display_element.querySelector("#jspsych-free-sort-arena").innerHTML += '<img '+
|
||||
'src="'+trial.stimuli[i]+'" '+
|
||||
'data-src="'+trial.stimuli[i]+'" '+
|
||||
'class="jspsych-free-sort-draggable" '+
|
||||
'draggable="false" '+
|
||||
'style="position: absolute; cursor: move; width:'+trial.stim_width+'px; height:'+trial.stim_height+'px; top:'+coords.y+'px; left:'+coords.x+'px;">'+
|
||||
'</img>';
|
||||
|
||||
init_locations.push({
|
||||
"src": trial.stimuli[i],
|
||||
"x": coords.x,
|
||||
"y": coords.y
|
||||
});
|
||||
}
|
||||
|
||||
display_element.innerHTML += '<button id="jspsych-free-sort-done-btn" class="jspsych-btn">'+trial.button_label+'</button>';
|
||||
|
||||
var maxz = 1;
|
||||
|
||||
var moves = [];
|
||||
|
||||
var draggables = display_element.querySelectorAll('.jspsych-free-sort-draggable');
|
||||
|
||||
for(var i=0;i<draggables.length; i++){
|
||||
draggables[i].addEventListener('mousedown', function(event){
|
||||
var x = event.pageX - event.currentTarget.offsetLeft;
|
||||
var y = event.pageY - event.currentTarget.offsetTop - window.scrollY;
|
||||
var elem = event.currentTarget;
|
||||
elem.style.zIndex = ++maxz;
|
||||
|
||||
var mousemoveevent = function(e){
|
||||
elem.style.top = Math.min(trial.sort_area_height - trial.stim_height, Math.max(0,(e.clientY - y))) + 'px';
|
||||
elem.style.left = Math.min(trial.sort_area_width - trial.stim_width, Math.max(0,(e.clientX - x))) + 'px';
|
||||
}
|
||||
document.addEventListener('mousemove', mousemoveevent);
|
||||
|
||||
var mouseupevent = function(e){
|
||||
document.removeEventListener('mousemove', mousemoveevent);
|
||||
moves.push({
|
||||
"src": elem.dataset.src,
|
||||
"x": elem.offsetLeft,
|
||||
"y": elem.offsetTop
|
||||
});
|
||||
document.removeEventListener('mouseup', mouseupevent);
|
||||
}
|
||||
document.addEventListener('mouseup', mouseupevent);
|
||||
});
|
||||
}
|
||||
|
||||
display_element.querySelector('#jspsych-free-sort-done-btn').addEventListener('click', function(){
|
||||
|
||||
var end_time = performance.now();
|
||||
var rt = end_time - start_time;
|
||||
// gather data
|
||||
// get final position of all objects
|
||||
var final_locations = [];
|
||||
var matches = display_element.querySelectorAll('.jspsych-free-sort-draggable');
|
||||
for(var i=0; i<matches.length; i++){
|
||||
final_locations.push({
|
||||
"src": matches[i].dataset.src,
|
||||
"x": parseInt(matches[i].style.left),
|
||||
"y": parseInt(matches[i].style.top)
|
||||
});
|
||||
}
|
||||
|
||||
var trial_data = {
|
||||
"init_locations": JSON.stringify(init_locations),
|
||||
"moves": JSON.stringify(moves),
|
||||
"final_locations": JSON.stringify(final_locations),
|
||||
"rt": rt
|
||||
};
|
||||
|
||||
// advance to next part
|
||||
display_element.innerHTML = '';
|
||||
jsPsych.finishTrial(trial_data);
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
// helper functions
|
||||
|
||||
function random_coordinate(max_width, max_height) {
|
||||
var rnd_x = Math.floor(Math.random() * (max_width - 1));
|
||||
var rnd_y = Math.floor(Math.random() * (max_height - 1));
|
||||
|
||||
return {
|
||||
x: rnd_x,
|
||||
y: rnd_y
|
||||
};
|
||||
}
|
||||
|
||||
return plugin;
|
||||
})();
|
||||
104
PCSurvey/PCstatic/js/plugins/jspsych-fullscreen.js
Normal file
104
PCSurvey/PCstatic/js/plugins/jspsych-fullscreen.js
Normal file
@@ -0,0 +1,104 @@
|
||||
/* jspsych-fullscreen.js
|
||||
* Josh de Leeuw
|
||||
*
|
||||
* toggle fullscreen mode in the browser
|
||||
*
|
||||
*/
|
||||
|
||||
jsPsych.plugins.fullscreen = (function() {
|
||||
|
||||
var plugin = {};
|
||||
|
||||
plugin.info = {
|
||||
name: 'fullscreen',
|
||||
description: '',
|
||||
parameters: {
|
||||
fullscreen_mode: {
|
||||
type: jsPsych.plugins.parameterType.BOOL,
|
||||
pretty_name: 'Fullscreen mode',
|
||||
default: true,
|
||||
array: false,
|
||||
description: 'If true, experiment will enter fullscreen mode. If false, the browser will exit fullscreen mode.'
|
||||
},
|
||||
message: {
|
||||
type: jsPsych.plugins.parameterType.STRING,
|
||||
pretty_name: 'Message',
|
||||
default: '<p>The experiment will switch to full screen mode when you press the button below</p>',
|
||||
array: false,
|
||||
description: 'HTML content to display above the button to enter fullscreen mode.'
|
||||
},
|
||||
button_label: {
|
||||
type: jsPsych.plugins.parameterType.STRING,
|
||||
pretty_name: 'Button label',
|
||||
default: 'Continue',
|
||||
array: false,
|
||||
description: 'The text that appears on the button to enter fullscreen.'
|
||||
},
|
||||
delay_after: {
|
||||
type: jsPsych.plugins.parameterType.INT,
|
||||
pretty_name: 'Delay after',
|
||||
default: 1000,
|
||||
array: false,
|
||||
description: 'The length of time to delay after entering fullscreen mode before ending the trial.'
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
plugin.trial = function(display_element, trial) {
|
||||
|
||||
// check if keys are allowed in fullscreen mode
|
||||
var keyboardNotAllowed = typeof Element !== 'undefined' && 'ALLOW_KEYBOARD_INPUT' in Element;
|
||||
if (keyboardNotAllowed) {
|
||||
// This is Safari, and keyboard events will be disabled. Don't allow fullscreen here.
|
||||
// do something else?
|
||||
endTrial();
|
||||
} else {
|
||||
if(trial.fullscreen_mode){
|
||||
display_element.innerHTML = trial.message + '<button id="jspsych-fullscreen-btn" class="jspsych-btn">'+trial.button_label+'</button>';
|
||||
var listener = display_element.querySelector('#jspsych-fullscreen-btn').addEventListener('click', function() {
|
||||
var element = document.documentElement;
|
||||
if (element.requestFullscreen) {
|
||||
element.requestFullscreen();
|
||||
} else if (element.mozRequestFullScreen) {
|
||||
element.mozRequestFullScreen();
|
||||
} else if (element.webkitRequestFullscreen) {
|
||||
element.webkitRequestFullscreen();
|
||||
} else if (element.msRequestFullscreen) {
|
||||
element.msRequestFullscreen();
|
||||
}
|
||||
endTrial();
|
||||
});
|
||||
} else {
|
||||
if (document.exitFullscreen) {
|
||||
document.exitFullscreen();
|
||||
} else if (document.msExitFullscreen) {
|
||||
document.msExitFullscreen();
|
||||
} else if (document.mozCancelFullScreen) {
|
||||
document.mozCancelFullScreen();
|
||||
} else if (document.webkitExitFullscreen) {
|
||||
document.webkitExitFullscreen();
|
||||
}
|
||||
endTrial();
|
||||
}
|
||||
}
|
||||
|
||||
function endTrial() {
|
||||
|
||||
display_element.innerHTML = '';
|
||||
|
||||
jsPsych.pluginAPI.setTimeout(function(){
|
||||
|
||||
var trial_data = {
|
||||
success: !keyboardNotAllowed
|
||||
};
|
||||
|
||||
jsPsych.finishTrial(trial_data);
|
||||
|
||||
}, trial.delay_after);
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
return plugin;
|
||||
})();
|
||||
188
PCSurvey/PCstatic/js/plugins/jspsych-html-button-response.js
Normal file
188
PCSurvey/PCstatic/js/plugins/jspsych-html-button-response.js
Normal file
@@ -0,0 +1,188 @@
|
||||
/**
|
||||
* jspsych-html-button-response
|
||||
* Josh de Leeuw
|
||||
*
|
||||
* plugin for displaying a stimulus and getting a keyboard response
|
||||
*
|
||||
* documentation: docs.jspsych.org
|
||||
*
|
||||
**/
|
||||
|
||||
jsPsych.plugins["html-button-response"] = (function() {
|
||||
|
||||
var plugin = {};
|
||||
|
||||
plugin.info = {
|
||||
name: 'html-button-response',
|
||||
description: '',
|
||||
parameters: {
|
||||
stimulus: {
|
||||
type: jsPsych.plugins.parameterType.HTML_STRING,
|
||||
pretty_name: 'Stimulus',
|
||||
default: undefined,
|
||||
description: 'The HTML string to be displayed'
|
||||
},
|
||||
choices: {
|
||||
type: jsPsych.plugins.parameterType.STRING,
|
||||
pretty_name: 'Choices',
|
||||
default: undefined,
|
||||
array: true,
|
||||
description: 'The labels for the buttons.'
|
||||
},
|
||||
button_html: {
|
||||
type: jsPsych.plugins.parameterType.STRING,
|
||||
pretty_name: 'Button HTML',
|
||||
default: '<button class="jspsych-btn">%choice%</button>',
|
||||
array: true,
|
||||
description: 'The html of the button. Can create own style.'
|
||||
},
|
||||
prompt: {
|
||||
type: jsPsych.plugins.parameterType.STRING,
|
||||
pretty_name: 'Prompt',
|
||||
default: null,
|
||||
description: 'Any content here will be displayed under the button.'
|
||||
},
|
||||
stimulus_duration: {
|
||||
type: jsPsych.plugins.parameterType.INT,
|
||||
pretty_name: 'Stimulus duration',
|
||||
default: null,
|
||||
description: 'How long to hide the stimulus.'
|
||||
},
|
||||
trial_duration: {
|
||||
type: jsPsych.plugins.parameterType.INT,
|
||||
pretty_name: 'Trial duration',
|
||||
default: null,
|
||||
description: 'How long to show the trial.'
|
||||
},
|
||||
margin_vertical: {
|
||||
type: jsPsych.plugins.parameterType.STRING,
|
||||
pretty_name: 'Margin vertical',
|
||||
default: '0px',
|
||||
description: 'The vertical margin of the button.'
|
||||
},
|
||||
margin_horizontal: {
|
||||
type: jsPsych.plugins.parameterType.STRING,
|
||||
pretty_name: 'Margin horizontal',
|
||||
default: '8px',
|
||||
description: 'The horizontal margin of the button.'
|
||||
},
|
||||
response_ends_trial: {
|
||||
type: jsPsych.plugins.parameterType.BOOL,
|
||||
pretty_name: 'Response ends trial',
|
||||
default: true,
|
||||
description: 'If true, then trial will end when user responds.'
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
plugin.trial = function(display_element, trial) {
|
||||
|
||||
// display stimulus
|
||||
var html = '<div id="jspsych-html-button-response-stimulus">'+trial.stimulus+'</div>';
|
||||
|
||||
//display buttons
|
||||
var buttons = [];
|
||||
if (Array.isArray(trial.button_html)) {
|
||||
if (trial.button_html.length == trial.choices.length) {
|
||||
buttons = trial.button_html;
|
||||
} else {
|
||||
console.error('Error in html-button-response plugin. The length of the button_html array does not equal the length of the choices array');
|
||||
}
|
||||
} else {
|
||||
for (var i = 0; i < trial.choices.length; i++) {
|
||||
buttons.push(trial.button_html);
|
||||
}
|
||||
}
|
||||
html += '<div id="jspsych-html-button-response-btngroup">';
|
||||
for (var i = 0; i < trial.choices.length; i++) {
|
||||
var str = buttons[i].replace(/%choice%/g, trial.choices[i]);
|
||||
html += '<div class="jspsych-html-button-response-button" style="display: inline-block; margin:'+trial.margin_vertical+' '+trial.margin_horizontal+'" id="jspsych-html-button-response-button-' + i +'" data-choice="'+i+'">'+str+'</div>';
|
||||
}
|
||||
html += '</div>';
|
||||
|
||||
//show prompt if there is one
|
||||
if (trial.prompt !== null) {
|
||||
html += trial.prompt;
|
||||
}
|
||||
display_element.innerHTML = html;
|
||||
|
||||
// start time
|
||||
var start_time = performance.now();
|
||||
|
||||
// add event listeners to buttons
|
||||
for (var i = 0; i < trial.choices.length; i++) {
|
||||
display_element.querySelector('#jspsych-html-button-response-button-' + i).addEventListener('click', function(e){
|
||||
var choice = e.currentTarget.getAttribute('data-choice'); // don't use dataset for jsdom compatibility
|
||||
after_response(choice);
|
||||
});
|
||||
}
|
||||
|
||||
// store response
|
||||
var response = {
|
||||
rt: null,
|
||||
button: null
|
||||
};
|
||||
|
||||
// function to handle responses by the subject
|
||||
function after_response(choice) {
|
||||
|
||||
// measure rt
|
||||
var end_time = performance.now();
|
||||
var rt = end_time - start_time;
|
||||
response.button = choice;
|
||||
response.rt = rt;
|
||||
|
||||
// after a valid response, the stimulus will have the CSS class 'responded'
|
||||
// which can be used to provide visual feedback that a response was recorded
|
||||
display_element.querySelector('#jspsych-html-button-response-stimulus').className += ' responded';
|
||||
|
||||
// disable all the buttons after a response
|
||||
var btns = document.querySelectorAll('.jspsych-html-button-response-button button');
|
||||
for(var i=0; i<btns.length; i++){
|
||||
//btns[i].removeEventListener('click');
|
||||
btns[i].setAttribute('disabled', 'disabled');
|
||||
}
|
||||
|
||||
if (trial.response_ends_trial) {
|
||||
end_trial();
|
||||
}
|
||||
};
|
||||
|
||||
// function to end trial when it is time
|
||||
function end_trial() {
|
||||
|
||||
// kill any remaining setTimeout handlers
|
||||
jsPsych.pluginAPI.clearAllTimeouts();
|
||||
|
||||
// gather the data to store for the trial
|
||||
var trial_data = {
|
||||
"rt": response.rt,
|
||||
"stimulus": trial.stimulus,
|
||||
"button_pressed": response.button
|
||||
};
|
||||
|
||||
// clear the display
|
||||
display_element.innerHTML = '';
|
||||
|
||||
// move on to the next trial
|
||||
jsPsych.finishTrial(trial_data);
|
||||
};
|
||||
|
||||
// hide image if timing is set
|
||||
if (trial.stimulus_duration !== null) {
|
||||
jsPsych.pluginAPI.setTimeout(function() {
|
||||
display_element.querySelector('#jspsych-html-button-response-stimulus').style.visibility = 'hidden';
|
||||
}, trial.stimulus_duration);
|
||||
}
|
||||
|
||||
// end trial if time limit is set
|
||||
if (trial.trial_duration !== null) {
|
||||
jsPsych.pluginAPI.setTimeout(function() {
|
||||
end_trial();
|
||||
}, trial.trial_duration);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
return plugin;
|
||||
})();
|
||||
149
PCSurvey/PCstatic/js/plugins/jspsych-html-keyboard-response.js
Normal file
149
PCSurvey/PCstatic/js/plugins/jspsych-html-keyboard-response.js
Normal file
@@ -0,0 +1,149 @@
|
||||
/**
|
||||
* jspsych-html-keyboard-response
|
||||
* Josh de Leeuw
|
||||
*
|
||||
* plugin for displaying a stimulus and getting a keyboard response
|
||||
*
|
||||
* documentation: docs.jspsych.org
|
||||
*
|
||||
**/
|
||||
|
||||
|
||||
jsPsych.plugins["html-keyboard-response"] = (function() {
|
||||
|
||||
var plugin = {};
|
||||
|
||||
plugin.info = {
|
||||
name: 'html-keyboard-response',
|
||||
description: '',
|
||||
parameters: {
|
||||
stimulus: {
|
||||
type: jsPsych.plugins.parameterType.HTML_STRING,
|
||||
pretty_name: 'Stimulus',
|
||||
default: undefined,
|
||||
description: 'The HTML string to be displayed'
|
||||
},
|
||||
choices: {
|
||||
type: jsPsych.plugins.parameterType.KEYCODE,
|
||||
array: true,
|
||||
pretty_name: 'Choices',
|
||||
default: jsPsych.ALL_KEYS,
|
||||
description: 'The keys the subject is allowed to press to respond to the stimulus.'
|
||||
},
|
||||
prompt: {
|
||||
type: jsPsych.plugins.parameterType.STRING,
|
||||
pretty_name: 'Prompt',
|
||||
default: null,
|
||||
description: 'Any content here will be displayed below the stimulus.'
|
||||
},
|
||||
stimulus_duration: {
|
||||
type: jsPsych.plugins.parameterType.INT,
|
||||
pretty_name: 'Stimulus duration',
|
||||
default: null,
|
||||
description: 'How long to hide the stimulus.'
|
||||
},
|
||||
trial_duration: {
|
||||
type: jsPsych.plugins.parameterType.INT,
|
||||
pretty_name: 'Trial duration',
|
||||
default: null,
|
||||
description: 'How long to show trial before it ends.'
|
||||
},
|
||||
response_ends_trial: {
|
||||
type: jsPsych.plugins.parameterType.BOOL,
|
||||
pretty_name: 'Response ends trial',
|
||||
default: true,
|
||||
description: 'If true, trial will end when subject makes a response.'
|
||||
},
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
plugin.trial = function(display_element, trial) {
|
||||
|
||||
var new_html = '<div id="jspsych-html-keyboard-response-stimulus">'+trial.stimulus+'</div>';
|
||||
|
||||
// add prompt
|
||||
if(trial.prompt !== null){
|
||||
new_html += trial.prompt;
|
||||
}
|
||||
|
||||
// draw
|
||||
display_element.innerHTML = new_html;
|
||||
|
||||
// store response
|
||||
var response = {
|
||||
rt: null,
|
||||
key: null
|
||||
};
|
||||
|
||||
// function to end trial when it is time
|
||||
var end_trial = function() {
|
||||
|
||||
// kill any remaining setTimeout handlers
|
||||
jsPsych.pluginAPI.clearAllTimeouts();
|
||||
|
||||
// kill keyboard listeners
|
||||
if (typeof keyboardListener !== 'undefined') {
|
||||
jsPsych.pluginAPI.cancelKeyboardResponse(keyboardListener);
|
||||
}
|
||||
|
||||
// gather the data to store for the trial
|
||||
var trial_data = {
|
||||
"rt": response.rt,
|
||||
"stimulus": trial.stimulus,
|
||||
"key_press": response.key
|
||||
};
|
||||
|
||||
// clear the display
|
||||
display_element.innerHTML = '';
|
||||
|
||||
// move on to the next trial
|
||||
jsPsych.finishTrial(trial_data);
|
||||
};
|
||||
|
||||
// function to handle responses by the subject
|
||||
var after_response = function(info) {
|
||||
|
||||
// after a valid response, the stimulus will have the CSS class 'responded'
|
||||
// which can be used to provide visual feedback that a response was recorded
|
||||
display_element.querySelector('#jspsych-html-keyboard-response-stimulus').className += ' responded';
|
||||
|
||||
// only record the first response
|
||||
if (response.key == null) {
|
||||
response = info;
|
||||
}
|
||||
|
||||
if (trial.response_ends_trial) {
|
||||
end_trial();
|
||||
}
|
||||
};
|
||||
|
||||
// start the response listener
|
||||
if (trial.choices != jsPsych.NO_KEYS) {
|
||||
var keyboardListener = jsPsych.pluginAPI.getKeyboardResponse({
|
||||
callback_function: after_response,
|
||||
valid_responses: trial.choices,
|
||||
rt_method: 'performance',
|
||||
persist: false,
|
||||
allow_held_key: false
|
||||
});
|
||||
}
|
||||
|
||||
// hide stimulus if stimulus_duration is set
|
||||
if (trial.stimulus_duration !== null) {
|
||||
jsPsych.pluginAPI.setTimeout(function() {
|
||||
display_element.querySelector('#jspsych-html-keyboard-response-stimulus').style.visibility = 'hidden';
|
||||
}, trial.stimulus_duration);
|
||||
}
|
||||
|
||||
// end trial if trial_duration is set
|
||||
if (trial.trial_duration !== null) {
|
||||
jsPsych.pluginAPI.setTimeout(function() {
|
||||
end_trial();
|
||||
}, trial.trial_duration);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
return plugin;
|
||||
})();
|
||||
193
PCSurvey/PCstatic/js/plugins/jspsych-html-slider-response.js
Normal file
193
PCSurvey/PCstatic/js/plugins/jspsych-html-slider-response.js
Normal file
@@ -0,0 +1,193 @@
|
||||
/**
|
||||
* jspsych-html-slider-response
|
||||
* a jspsych plugin for free response survey questions
|
||||
*
|
||||
* Josh de Leeuw
|
||||
*
|
||||
* documentation: docs.jspsych.org
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
jsPsych.plugins['html-slider-response'] = (function() {
|
||||
|
||||
var plugin = {};
|
||||
|
||||
plugin.info = {
|
||||
name: 'html-slider-response',
|
||||
description: '',
|
||||
parameters: {
|
||||
stimulus: {
|
||||
type: jsPsych.plugins.parameterType.HTML_STRING,
|
||||
pretty_name: 'Stimulus',
|
||||
default: undefined,
|
||||
description: 'The HTML string to be displayed'
|
||||
},
|
||||
min: {
|
||||
type: jsPsych.plugins.parameterType.INT,
|
||||
pretty_name: 'Min slider',
|
||||
default: 0,
|
||||
description: 'Sets the minimum value of the slider.'
|
||||
},
|
||||
max: {
|
||||
type: jsPsych.plugins.parameterType.INT,
|
||||
pretty_name: 'Max slider',
|
||||
default: 100,
|
||||
description: 'Sets the maximum value of the slider',
|
||||
},
|
||||
start: {
|
||||
type: jsPsych.plugins.parameterType.INT,
|
||||
pretty_name: 'Slider starting value',
|
||||
default: 50,
|
||||
description: 'Sets the starting value of the slider',
|
||||
},
|
||||
step: {
|
||||
type: jsPsych.plugins.parameterType.INT,
|
||||
pretty_name: 'Step',
|
||||
default: 1,
|
||||
description: 'Sets the step of the slider'
|
||||
},
|
||||
labels: {
|
||||
type: jsPsych.plugins.parameterType.HTML_STRING,
|
||||
pretty_name:'Labels',
|
||||
default: [],
|
||||
array: true,
|
||||
description: 'Labels of the slider.',
|
||||
},
|
||||
slider_width: {
|
||||
type: jsPsych.plugins.parameterType.INT,
|
||||
pretty_name:'Slider width',
|
||||
default: null,
|
||||
description: 'Width of the slider in pixels.'
|
||||
},
|
||||
button_label: {
|
||||
type: jsPsych.plugins.parameterType.STRING,
|
||||
pretty_name: 'Button label',
|
||||
default: 'Continue',
|
||||
array: false,
|
||||
description: 'Label of the button to advance.'
|
||||
},
|
||||
require_movement: {
|
||||
type: jsPsych.plugins.parameterType.BOOL,
|
||||
pretty_name: 'Require movement',
|
||||
default: false,
|
||||
description: 'If true, the participant will have to move the slider before continuing.'
|
||||
},
|
||||
prompt: {
|
||||
type: jsPsych.plugins.parameterType.STRING,
|
||||
pretty_name: 'Prompt',
|
||||
default: null,
|
||||
description: 'Any content here will be displayed below the slider.'
|
||||
},
|
||||
stimulus_duration: {
|
||||
type: jsPsych.plugins.parameterType.INT,
|
||||
pretty_name: 'Stimulus duration',
|
||||
default: null,
|
||||
description: 'How long to hide the stimulus.'
|
||||
},
|
||||
trial_duration: {
|
||||
type: jsPsych.plugins.parameterType.INT,
|
||||
pretty_name: 'Trial duration',
|
||||
default: null,
|
||||
description: 'How long to show the trial.'
|
||||
},
|
||||
response_ends_trial: {
|
||||
type: jsPsych.plugins.parameterType.BOOL,
|
||||
pretty_name: 'Response ends trial',
|
||||
default: true,
|
||||
description: 'If true, trial will end when user makes a response.'
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
plugin.trial = function(display_element, trial) {
|
||||
|
||||
var html = '<div id="jspsych-html-slider-response-wrapper" style="margin: 100px 0px;">';
|
||||
html += '<div id="jspsych-html-slider-response-stimulus">' + trial.stimulus + '</div>';
|
||||
html += '<div class="jspsych-html-slider-response-container" style="position:relative; margin: 0 auto 3em auto; ';
|
||||
if(trial.slider_width !== null){
|
||||
html += 'width:'+trial.slider_width+'px;';
|
||||
}
|
||||
html += '">';
|
||||
html += '<input type="range" value="'+trial.start+'" min="'+trial.min+'" max="'+trial.max+'" step="'+trial.step+'" style="width: 100%;" id="jspsych-html-slider-response-response"></input>';
|
||||
html += '<div>'
|
||||
for(var j=0; j < trial.labels.length; j++){
|
||||
var width = 100/(trial.labels.length-1);
|
||||
var left_offset = (j * (100 /(trial.labels.length - 1))) - (width/2);
|
||||
html += '<div style="display: inline-block; position: absolute; left:'+left_offset+'%; text-align: center; width: '+width+'%;">';
|
||||
html += '<span style="text-align: center; font-size: 80%;">'+trial.labels[j]+'</span>';
|
||||
html += '</div>'
|
||||
}
|
||||
html += '</div>';
|
||||
html += '</div>';
|
||||
html += '</div>';
|
||||
|
||||
if (trial.prompt !== null){
|
||||
html += trial.prompt;
|
||||
}
|
||||
|
||||
// add submit button
|
||||
html += '<button id="jspsych-html-slider-response-next" class="jspsych-btn" '+ (trial.require_movement ? "disabled" : "") + '>'+trial.button_label+'</button>';
|
||||
|
||||
display_element.innerHTML = html;
|
||||
|
||||
var response = {
|
||||
rt: null,
|
||||
response: null
|
||||
};
|
||||
|
||||
if(trial.require_movement){
|
||||
display_element.querySelector('#jspsych-html-slider-response-response').addEventListener('change', function(){
|
||||
display_element.querySelector('#jspsych-html-slider-response-next').disabled = false;
|
||||
})
|
||||
}
|
||||
|
||||
display_element.querySelector('#jspsych-html-slider-response-next').addEventListener('click', function() {
|
||||
// measure response time
|
||||
var endTime = performance.now();
|
||||
response.rt = endTime - startTime;
|
||||
response.response = display_element.querySelector('#jspsych-html-slider-response-response').value;
|
||||
|
||||
if(trial.response_ends_trial){
|
||||
end_trial();
|
||||
} else {
|
||||
display_element.querySelector('#jspsych-html-slider-response-next').disabled = true;
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
function end_trial(){
|
||||
|
||||
jsPsych.pluginAPI.clearAllTimeouts();
|
||||
|
||||
// save data
|
||||
var trialdata = {
|
||||
"rt": response.rt,
|
||||
"response": response.response,
|
||||
"stimulus": trial.stimulus
|
||||
};
|
||||
|
||||
display_element.innerHTML = '';
|
||||
|
||||
// next trial
|
||||
jsPsych.finishTrial(trialdata);
|
||||
}
|
||||
|
||||
if (trial.stimulus_duration !== null) {
|
||||
jsPsych.pluginAPI.setTimeout(function() {
|
||||
display_element.querySelector('#jspsych-html-slider-response-stimulus').style.visibility = 'hidden';
|
||||
}, trial.stimulus_duration);
|
||||
}
|
||||
|
||||
// end trial if trial_duration is set
|
||||
if (trial.trial_duration !== null) {
|
||||
jsPsych.pluginAPI.setTimeout(function() {
|
||||
end_trial();
|
||||
}, trial.trial_duration);
|
||||
}
|
||||
|
||||
var startTime = performance.now();
|
||||
};
|
||||
|
||||
return plugin;
|
||||
})();
|
||||
284
PCSurvey/PCstatic/js/plugins/jspsych-iat-html.js
Normal file
284
PCSurvey/PCstatic/js/plugins/jspsych-iat-html.js
Normal file
@@ -0,0 +1,284 @@
|
||||
/**
|
||||
* jspsych-iat
|
||||
* Kristin Diep
|
||||
*
|
||||
* plugin for displaying a stimulus and getting a keyboard response
|
||||
*
|
||||
* documentation: docs.jspsych.org
|
||||
*
|
||||
**/
|
||||
|
||||
|
||||
jsPsych.plugins['iat-html'] = (function() {
|
||||
|
||||
var plugin = {};
|
||||
|
||||
plugin.info = {
|
||||
name: 'iat-html',
|
||||
description: '',
|
||||
parameters: {
|
||||
stimulus: {
|
||||
type: jsPsych.plugins.parameterType.HTML_STRING,
|
||||
pretty_name: 'Stimulus',
|
||||
default: undefined,
|
||||
description: 'The HTML string to be displayed.'
|
||||
},
|
||||
left_category_key: {
|
||||
type: jsPsych.plugins.parameterType.HTML_STRING,
|
||||
pretty_name: 'Left category key',
|
||||
default: 'E',
|
||||
description: 'Key press that is associated with the left category label.'
|
||||
},
|
||||
right_category_key: {
|
||||
type: jsPsych.plugins.parameterType.STRING,
|
||||
pretty_name: 'Right category key',
|
||||
default: 'I',
|
||||
description: 'Key press that is associated with the right category label.'
|
||||
},
|
||||
left_category_label: {
|
||||
type: jsPsych.plugins.parameterType.STRING,
|
||||
pretty_name: 'Left category label',
|
||||
array: true,
|
||||
default: ['left'],
|
||||
description: 'The label that is associated with the stimulus. Aligned to the left side of page.'
|
||||
},
|
||||
right_category_label: {
|
||||
type: jsPsych.plugins.parameterType.STRING,
|
||||
pretty_name: 'Right category label',
|
||||
array: true,
|
||||
default: ['right'],
|
||||
description: 'The label that is associated with the stimulus. Aligned to the right side of the page.'
|
||||
},
|
||||
key_to_move_forward: {
|
||||
type: jsPsych.plugins.parameterType.KEYCODE,
|
||||
pretty_name: 'Key to move forward',
|
||||
array: true,
|
||||
default: jsPsych.ALL_KEYS,
|
||||
description: 'The keys that allow the user to advance to the next trial if their key press was incorrect.'
|
||||
},
|
||||
display_feedback: {
|
||||
type: jsPsych.plugins.parameterType.BOOL,
|
||||
pretty_name: 'Display feedback',
|
||||
default: false,
|
||||
description: 'If true, then html when wrong will be displayed when user makes an incorrect key press.'
|
||||
},
|
||||
html_when_wrong: {
|
||||
type: jsPsych.plugins.parameterType.HTML_STRING,
|
||||
pretty_name: 'HTML when wrong',
|
||||
default: '<span style="color: red; font-size: 80px">X</span>',
|
||||
description: 'The image to display when a user presses the wrong key.'
|
||||
},
|
||||
bottom_instructions: {
|
||||
type: jsPsych.plugins.parameterType.HTML_STRING,
|
||||
pretty_name: 'Bottom instructions',
|
||||
default: '<p>If you press the wrong key, a red X will appear. Press any key to continue.</p>',
|
||||
description: 'Instructions shown at the bottom of the page.'
|
||||
},
|
||||
force_correct_key_press: {
|
||||
type: jsPsych.plugins.parameterType.BOOL,
|
||||
pretty_name: 'Force correct key press',
|
||||
default: false,
|
||||
description: 'If true, in order to advance to the next trial after a wrong key press the user will be forced to press the correct key.'
|
||||
},
|
||||
stim_key_association: {
|
||||
type: jsPsych.plugins.parameterType.HTML_STRING,
|
||||
pretty_name: 'Stimulus key association',
|
||||
options: ['left', 'right'],
|
||||
default: 'undefined',
|
||||
description: 'Stimulus will be associated with eight "left" or "right".'
|
||||
},
|
||||
response_ends_trial: {
|
||||
type: jsPsych.plugins.parameterType.BOOL,
|
||||
pretty_name: 'Response ends trial',
|
||||
default: true,
|
||||
description: 'If true, trial will end when user makes a response.'
|
||||
},
|
||||
trial_duration: {
|
||||
type: jsPsych.plugins.parameterType.INT,
|
||||
pretty_name: 'Trial duration',
|
||||
default: null,
|
||||
description: 'How long to show the trial.'
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
plugin.trial = function(display_element, trial) {
|
||||
|
||||
var html_str = "";
|
||||
|
||||
html_str += "<div style='position: absolute; height: 20%; width: 100%; margin-left: auto; margin-right: auto; top: 42%; left: 0; right: 0'><p id='jspsych-iat-stim'>" + trial.stimulus + "</p></div>";
|
||||
|
||||
html_str += "<div id='trial_left_align' style='position: absolute; top: 18%; left: 20%'>";
|
||||
|
||||
if(trial.left_category_label.length == 1) {
|
||||
html_str += "<p>Press " + trial.left_category_key + " for:<br> " +
|
||||
trial.left_category_label[0].bold() + "</p></div>";
|
||||
} else {
|
||||
html_str += "<p>Press " + trial.left_category_key + " for:<br> " +
|
||||
trial.left_category_label[0].bold() + "<br>" + "or<br>" +
|
||||
trial.left_category_label[1].bold() + "</p></div>";
|
||||
}
|
||||
|
||||
html_str += "<div id='trial_right_align' style='position: absolute; top: 18%; right: 20%'>";
|
||||
|
||||
if(trial.right_category_label.length == 1) {
|
||||
html_str += "<p>Press " + trial.right_category_key + " for:<br> " +
|
||||
trial.right_category_label[0].bold() + '</p></div>';
|
||||
} else {
|
||||
html_str += "<p>Press " + trial.right_category_key + " for:<br> " +
|
||||
trial.right_category_label[0].bold() + "<br>" + "or<br>" +
|
||||
trial.right_category_label[1].bold() + "</p></div>";
|
||||
}
|
||||
|
||||
html_str += "<div id='wrongImgID' style='position:relative; top: 300px; margin-left: auto; margin-right: auto; left: 0; right: 0'>";
|
||||
|
||||
if(trial.display_feedback === true) {
|
||||
html_str += "<div id='wrongImgContainer' style='visibility: hidden; position: absolute; top: -75px; margin-left: auto; margin-right: auto; left: 0; right: 0'><p>"+trial.html_when_wrong+"</p></div>";
|
||||
html_str += "<div>"+trial.bottom_instructions+"</div>";
|
||||
} else {
|
||||
html_str += "<div>"+trial.bottom_instructions+"</div>";
|
||||
}
|
||||
|
||||
html_str += "</div>";
|
||||
|
||||
display_element.innerHTML = html_str;
|
||||
|
||||
|
||||
// store response
|
||||
var response = {
|
||||
rt: null,
|
||||
key: null,
|
||||
correct: false
|
||||
};
|
||||
|
||||
// function to end trial when it is time
|
||||
var end_trial = function() {
|
||||
|
||||
// kill any remaining setTimeout handlers
|
||||
jsPsych.pluginAPI.clearAllTimeouts();
|
||||
|
||||
// kill keyboard listeners
|
||||
if (typeof keyboardListener !== 'undefined') {
|
||||
jsPsych.pluginAPI.cancelKeyboardResponse(keyboardListener);
|
||||
}
|
||||
|
||||
// gather the data to store for the trial
|
||||
var trial_data = {
|
||||
"rt": response.rt,
|
||||
"stimulus": trial.stimulus,
|
||||
"key_press": response.key,
|
||||
"correct": response.correct
|
||||
};
|
||||
|
||||
// clears the display
|
||||
display_element.innerHTML = '';
|
||||
|
||||
// move on to the next trial
|
||||
jsPsych.finishTrial(trial_data);
|
||||
};
|
||||
|
||||
var leftKeyCode = jsPsych.pluginAPI.convertKeyCharacterToKeyCode(trial.left_category_key);
|
||||
var rightKeyCode = jsPsych.pluginAPI.convertKeyCharacterToKeyCode(trial.right_category_key);
|
||||
|
||||
// function to handle responses by the subject
|
||||
var after_response = function(info) {
|
||||
var wImg = document.getElementById("wrongImgContainer");
|
||||
// after a valid response, the stimulus will have the CSS class 'responded'
|
||||
// which can be used to provide visual feedback that a response was recorded
|
||||
display_element.querySelector('#jspsych-iat-stim').className += ' responded';
|
||||
|
||||
// only record the first response
|
||||
if (response.key == null ) {
|
||||
response = info;
|
||||
}
|
||||
|
||||
if(trial.stim_key_association == "right") {
|
||||
if(response.rt !== null && response.key == rightKeyCode) {
|
||||
response.correct = true;
|
||||
if (trial.response_ends_trial) {
|
||||
end_trial();
|
||||
}
|
||||
} else {
|
||||
response.correct = false;
|
||||
if(!trial.response_ends_trial && trial.display_feedback == true) {
|
||||
wImg.style.visibility = "visible";
|
||||
}
|
||||
if (trial.response_ends_trial && trial.display_feedback == true) {
|
||||
wImg.style.visibility = "visible";
|
||||
if(trial.force_correct_key_press) {
|
||||
var keyListener = jsPsych.pluginAPI.getKeyboardResponse({
|
||||
callback_function: end_trial,
|
||||
valid_responses: [trial.right_category_key]
|
||||
});
|
||||
} else {
|
||||
var keyListener = jsPsych.pluginAPI.getKeyboardResponse({
|
||||
callback_function: end_trial,
|
||||
valid_responses: trial.key_to_move_forward
|
||||
});}
|
||||
} else if(trial.response_ends_trial && trial.display_feedback != true) {
|
||||
var keyListener = jsPsych.pluginAPI.getKeyboardResponse({
|
||||
callback_function: end_trial,
|
||||
valid_responses: [jsPsych.ALL_KEYS]
|
||||
});
|
||||
} else if(!trial.response_ends_trial && trial.display_feedback != true) {
|
||||
|
||||
}
|
||||
}
|
||||
} else if(trial.stim_key_association == "left") {
|
||||
if(response.rt !== null && response.key == leftKeyCode) {
|
||||
response.correct = true;
|
||||
if (trial.response_ends_trial) {
|
||||
end_trial();
|
||||
}
|
||||
} else {
|
||||
response.correct = false;
|
||||
if(!trial.response_ends_trial && trial.display_feedback == true) {
|
||||
wImg.style.visibility = "visible";
|
||||
}
|
||||
if (trial.response_ends_trial && trial.display_feedback == true) {
|
||||
wImg.style.visibility = "visible";
|
||||
if(trial.force_correct_key_press) {
|
||||
var keyListener = jsPsych.pluginAPI.getKeyboardResponse({
|
||||
callback_function: end_trial,
|
||||
valid_responses: [trial.left_category_key]
|
||||
});
|
||||
} else {
|
||||
var keyListener = jsPsych.pluginAPI.getKeyboardResponse({
|
||||
callback_function: end_trial,
|
||||
valid_responses: trial.key_to_move_forward
|
||||
});}
|
||||
} else if(trial.response_ends_trial && trial.display_feedback != true) {
|
||||
var keyListener = jsPsych.pluginAPI.getKeyboardResponse({
|
||||
callback_function: end_trial,
|
||||
valid_responses: [jsPsych.ALL_KEYS]
|
||||
});
|
||||
} else if(!trial.response_ends_trial && trial.display_feedback != true) {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// start the response listener
|
||||
if (trial.left_category_key != jsPsych.NO_KEYS && trial.right_category_key != jsPsych.NO_KEYS) {
|
||||
var keyboardListener = jsPsych.pluginAPI.getKeyboardResponse({
|
||||
callback_function: after_response,
|
||||
valid_responses: [trial.left_category_key, trial.right_category_key],
|
||||
rt_method: 'performance',
|
||||
persist: false,
|
||||
allow_held_key: false
|
||||
});
|
||||
}
|
||||
|
||||
// end trial if time limit is set
|
||||
if (trial.trial_duration !== null && trial.response_ends_trial != true) {
|
||||
jsPsych.pluginAPI.setTimeout(function() {
|
||||
end_trial();
|
||||
}, trial.trial_duration);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
return plugin;
|
||||
})();
|
||||
286
PCSurvey/PCstatic/js/plugins/jspsych-iat-image.js
Normal file
286
PCSurvey/PCstatic/js/plugins/jspsych-iat-image.js
Normal file
@@ -0,0 +1,286 @@
|
||||
/**
|
||||
* jspsych-iat
|
||||
* Kristin Diep
|
||||
*
|
||||
* plugin for displaying a stimulus and getting a keyboard response
|
||||
*
|
||||
* documentation: docs.jspsych.org
|
||||
*
|
||||
**/
|
||||
|
||||
|
||||
jsPsych.plugins['iat-image'] = (function() {
|
||||
|
||||
var plugin = {};
|
||||
|
||||
jsPsych.pluginAPI.registerPreload('iat-image', 'stimulus', 'image');
|
||||
|
||||
plugin.info = {
|
||||
name: 'iat-image',
|
||||
description: '',
|
||||
parameters: {
|
||||
stimulus: {
|
||||
type: jsPsych.plugins.parameterType.IMAGE,
|
||||
pretty_name: 'Stimulus',
|
||||
default: undefined,
|
||||
description: 'The image to be displayed'
|
||||
},
|
||||
left_category_key: {
|
||||
type: jsPsych.plugins.parameterType.HTML_STRING,
|
||||
pretty_name: 'Left category key',
|
||||
default: 'E',
|
||||
description: 'Key press that is associated with the left category label.'
|
||||
},
|
||||
right_category_key: {
|
||||
type: jsPsych.plugins.parameterType.STRING,
|
||||
pretty_name: 'Right category key',
|
||||
default: 'I',
|
||||
description: 'Key press that is associated with the right category label.'
|
||||
},
|
||||
left_category_label: {
|
||||
type: jsPsych.plugins.parameterType.STRING,
|
||||
pretty_name: 'Left category label',
|
||||
array: true,
|
||||
default: ['left'],
|
||||
description: 'The label that is associated with the stimulus. Aligned to the left side of page.'
|
||||
},
|
||||
right_category_label: {
|
||||
type: jsPsych.plugins.parameterType.STRING,
|
||||
pretty_name: 'Right category label',
|
||||
array: true,
|
||||
default: ['right'],
|
||||
description: 'The label that is associated with the stimulus. Aligned to the right side of the page.'
|
||||
},
|
||||
key_to_move_forward: {
|
||||
type: jsPsych.plugins.parameterType.KEYCODE,
|
||||
pretty_name: 'Key to move forward',
|
||||
array: true,
|
||||
default: jsPsych.ALL_KEYS,
|
||||
description: 'The keys that allow the user to advance to the next trial if their key press was incorrect.'
|
||||
},
|
||||
display_feedback: {
|
||||
type: jsPsych.plugins.parameterType.BOOL,
|
||||
pretty_name: 'Display feedback',
|
||||
default: false,
|
||||
description: 'If true, then html when wrong will be displayed when user makes an incorrect key press.'
|
||||
},
|
||||
html_when_wrong: {
|
||||
type: jsPsych.plugins.parameterType.HTML_STRING,
|
||||
pretty_name: 'HTML when wrong',
|
||||
default: '<span style="color: red; font-size: 80px">X</span>',
|
||||
description: 'The image to display when a user presses the wrong key.'
|
||||
},
|
||||
bottom_instructions: {
|
||||
type: jsPsych.plugins.parameterType.HTML_STRING,
|
||||
pretty_name: 'Bottom instructions',
|
||||
default: '<p>If you press the wrong key, a red X will appear. Press any key to continue.</p>',
|
||||
description: 'Instructions shown at the bottom of the page.'
|
||||
},
|
||||
force_correct_key_press: {
|
||||
type: jsPsych.plugins.parameterType.BOOL,
|
||||
pretty_name: 'Force correct key press',
|
||||
default: false,
|
||||
description: 'If true, in order to advance to the next trial after a wrong key press the user will be forced to press the correct key.'
|
||||
},
|
||||
stim_key_association: {
|
||||
type: jsPsych.plugins.parameterType.HTML_STRING,
|
||||
pretty_name: 'Stimulus key association',
|
||||
options: ['left', 'right'],
|
||||
default: 'undefined',
|
||||
description: 'Stimulus will be associated with eight "left" or "right".'
|
||||
},
|
||||
response_ends_trial: {
|
||||
type: jsPsych.plugins.parameterType.BOOL,
|
||||
pretty_name: 'Response ends trial',
|
||||
default: true,
|
||||
description: 'If true, trial will end when user makes a response.'
|
||||
},
|
||||
trial_duration: {
|
||||
type: jsPsych.plugins.parameterType.INT,
|
||||
pretty_name: 'Trial duration',
|
||||
default: null,
|
||||
description: 'How long to show the trial.'
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
plugin.trial = function(display_element, trial) {
|
||||
|
||||
var html_str = "";
|
||||
|
||||
html_str += "<div style='position: absolute; height: 20%; width: 100%; margin-left: auto; margin-right: auto; top: 42%; left: 0; right: 0'><img src='"+trial.stimulus+"' id='jspsych-iat-stim'></img></div>";
|
||||
|
||||
html_str += "<div id='trial_left_align' style='position: absolute; top: 18%; left: 20%'>";
|
||||
|
||||
if(trial.left_category_label.length == 1) {
|
||||
html_str += "<p>Press " + trial.left_category_key + " for:<br> " +
|
||||
trial.left_category_label[0].bold() + "</p></div>";
|
||||
} else {
|
||||
html_str += "<p>Press " + trial.left_category_key + " for:<br> " +
|
||||
trial.left_category_label[0].bold() + "<br>" + "or<br>" +
|
||||
trial.left_category_label[1].bold() + "</p></div>";
|
||||
}
|
||||
|
||||
html_str += "<div id='trial_right_align' style='position: absolute; top: 18%; right: 20%'>";
|
||||
|
||||
if(trial.right_category_label.length == 1) {
|
||||
html_str += "<p>Press " + trial.right_category_key + " for:<br> " +
|
||||
trial.right_category_label[0].bold() + '</p></div>';
|
||||
} else {
|
||||
html_str += "<p>Press " + trial.right_category_key + " for:<br> " +
|
||||
trial.right_category_label[0].bold() + "<br>" + "or<br>" +
|
||||
trial.right_category_label[1].bold() + "</p></div>";
|
||||
}
|
||||
|
||||
html_str += "<div id='wrongImgID' style='position:relative; top: 300px; margin-left: auto; margin-right: auto; left: 0; right: 0'>";
|
||||
|
||||
if(trial.display_feedback === true) {
|
||||
html_str += "<div id='wrongImgContainer' style='visibility: hidden; position: absolute; top: -75px; margin-left: auto; margin-right: auto; left: 0; right: 0'><p>"+trial.html_when_wrong+"</p></div>";
|
||||
html_str += "<div>"+trial.bottom_instructions+"</div>";
|
||||
} else {
|
||||
html_str += "<div>"+trial.bottom_instructions+"</div>";
|
||||
}
|
||||
|
||||
html_str += "</div>";
|
||||
|
||||
display_element.innerHTML = html_str;
|
||||
|
||||
|
||||
// store response
|
||||
var response = {
|
||||
rt: null,
|
||||
key: null,
|
||||
correct: false
|
||||
};
|
||||
|
||||
// function to end trial when it is time
|
||||
var end_trial = function() {
|
||||
|
||||
// kill any remaining setTimeout handlers
|
||||
jsPsych.pluginAPI.clearAllTimeouts();
|
||||
|
||||
// kill keyboard listeners
|
||||
if (typeof keyboardListener !== 'undefined') {
|
||||
jsPsych.pluginAPI.cancelKeyboardResponse(keyboardListener);
|
||||
}
|
||||
|
||||
// gather the data to store for the trial
|
||||
var trial_data = {
|
||||
"rt": response.rt,
|
||||
"stimulus": trial.stimulus,
|
||||
"key_press": response.key,
|
||||
"correct": response.correct
|
||||
};
|
||||
|
||||
// clears the display
|
||||
display_element.innerHTML = '';
|
||||
|
||||
// move on to the next trial
|
||||
jsPsych.finishTrial(trial_data);
|
||||
};
|
||||
|
||||
var leftKeyCode = jsPsych.pluginAPI.convertKeyCharacterToKeyCode(trial.left_category_key);
|
||||
var rightKeyCode = jsPsych.pluginAPI.convertKeyCharacterToKeyCode(trial.right_category_key);
|
||||
|
||||
// function to handle responses by the subject
|
||||
var after_response = function(info) {
|
||||
var wImg = document.getElementById("wrongImgContainer");
|
||||
// after a valid response, the stimulus will have the CSS class 'responded'
|
||||
// which can be used to provide visual feedback that a response was recorded
|
||||
display_element.querySelector('#jspsych-iat-stim').className += ' responded';
|
||||
|
||||
// only record the first response
|
||||
if (response.key == null ) {
|
||||
response = info;
|
||||
}
|
||||
|
||||
if(trial.stim_key_association == "right") {
|
||||
if(response.rt !== null && response.key == rightKeyCode) {
|
||||
response.correct = true;
|
||||
if (trial.response_ends_trial) {
|
||||
end_trial();
|
||||
}
|
||||
} else {
|
||||
response.correct = false;
|
||||
if(!trial.response_ends_trial && trial.display_feedback == true) {
|
||||
wImg.style.visibility = "visible";
|
||||
}
|
||||
if (trial.response_ends_trial && trial.display_feedback == true) {
|
||||
wImg.style.visibility = "visible";
|
||||
if(trial.force_correct_key_press) {
|
||||
var keyListener = jsPsych.pluginAPI.getKeyboardResponse({
|
||||
callback_function: end_trial,
|
||||
valid_responses: [trial.right_category_key]
|
||||
});
|
||||
} else {
|
||||
var keyListener = jsPsych.pluginAPI.getKeyboardResponse({
|
||||
callback_function: end_trial,
|
||||
valid_responses: trial.key_to_move_forward
|
||||
});}
|
||||
} else if(trial.response_ends_trial && trial.display_feedback != true) {
|
||||
var keyListener = jsPsych.pluginAPI.getKeyboardResponse({
|
||||
callback_function: end_trial,
|
||||
valid_responses: [jsPsych.ALL_KEYS]
|
||||
});
|
||||
} else if(!trial.response_ends_trial && trial.display_feedback != true) {
|
||||
|
||||
}
|
||||
}
|
||||
} else if(trial.stim_key_association == "left") {
|
||||
if(response.rt !== null && response.key == leftKeyCode) {
|
||||
response.correct = true;
|
||||
if (trial.response_ends_trial) {
|
||||
end_trial();
|
||||
}
|
||||
} else {
|
||||
response.correct = false;
|
||||
if(!trial.response_ends_trial && trial.display_feedback == true) {
|
||||
wImg.style.visibility = "visible";
|
||||
}
|
||||
if (trial.response_ends_trial && trial.display_feedback == true) {
|
||||
wImg.style.visibility = "visible";
|
||||
if(trial.force_correct_key_press) {
|
||||
var keyListener = jsPsych.pluginAPI.getKeyboardResponse({
|
||||
callback_function: end_trial,
|
||||
valid_responses: [trial.left_category_key]
|
||||
});
|
||||
} else {
|
||||
var keyListener = jsPsych.pluginAPI.getKeyboardResponse({
|
||||
callback_function: end_trial,
|
||||
valid_responses: trial.key_to_move_forward
|
||||
});}
|
||||
} else if(trial.response_ends_trial && trial.display_feedback != true) {
|
||||
var keyListener = jsPsych.pluginAPI.getKeyboardResponse({
|
||||
callback_function: end_trial,
|
||||
valid_responses: [jsPsych.ALL_KEYS]
|
||||
});
|
||||
} else if(!trial.response_ends_trial && trial.display_feedback != true) {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// start the response listener
|
||||
if (trial.left_category_key != jsPsych.NO_KEYS && trial.right_category_key != jsPsych.NO_KEYS) {
|
||||
var keyboardListener = jsPsych.pluginAPI.getKeyboardResponse({
|
||||
callback_function: after_response,
|
||||
valid_responses: [trial.left_category_key, trial.right_category_key],
|
||||
rt_method: 'performance',
|
||||
persist: false,
|
||||
allow_held_key: false
|
||||
});
|
||||
}
|
||||
|
||||
// end trial if time limit is set
|
||||
if (trial.trial_duration !== null && trial.response_ends_trial != true) {
|
||||
jsPsych.pluginAPI.setTimeout(function() {
|
||||
end_trial();
|
||||
}, trial.trial_duration);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
return plugin;
|
||||
})();
|
||||
224
PCSurvey/PCstatic/js/plugins/jspsych-image-button-response.js
Normal file
224
PCSurvey/PCstatic/js/plugins/jspsych-image-button-response.js
Normal file
@@ -0,0 +1,224 @@
|
||||
/**
|
||||
* jspsych-image-button-response
|
||||
* Josh de Leeuw
|
||||
*
|
||||
* plugin for displaying a stimulus and getting a keyboard response
|
||||
*
|
||||
* documentation: docs.jspsych.org
|
||||
*
|
||||
**/
|
||||
|
||||
jsPsych.plugins["image-button-response"] = (function() {
|
||||
|
||||
var plugin = {};
|
||||
|
||||
jsPsych.pluginAPI.registerPreload('image-button-response', 'stimulus', 'image');
|
||||
|
||||
plugin.info = {
|
||||
name: 'image-button-response',
|
||||
description: '',
|
||||
parameters: {
|
||||
stimulus: {
|
||||
type: jsPsych.plugins.parameterType.IMAGE,
|
||||
pretty_name: 'Stimulus',
|
||||
default: undefined,
|
||||
description: 'The image to be displayed'
|
||||
},
|
||||
stimulus_height: {
|
||||
type: jsPsych.plugins.parameterType.INT,
|
||||
pretty_name: 'Image height',
|
||||
default: null,
|
||||
description: 'Set the image height in pixels'
|
||||
},
|
||||
stimulus_width: {
|
||||
type: jsPsych.plugins.parameterType.INT,
|
||||
pretty_name: 'Image width',
|
||||
default: null,
|
||||
description: 'Set the image width in pixels'
|
||||
},
|
||||
maintain_aspect_ratio: {
|
||||
type: jsPsych.plugins.parameterType.BOOL,
|
||||
pretty_name: 'Maintain aspect ratio',
|
||||
default: true,
|
||||
description: 'Maintain the aspect ratio after setting width or height'
|
||||
},
|
||||
choices: {
|
||||
type: jsPsych.plugins.parameterType.STRING,
|
||||
pretty_name: 'Choices',
|
||||
default: undefined,
|
||||
array: true,
|
||||
description: 'The labels for the buttons.'
|
||||
},
|
||||
button_html: {
|
||||
type: jsPsych.plugins.parameterType.STRING,
|
||||
pretty_name: 'Button HTML',
|
||||
default: '<button class="jspsych-btn">%choice%</button>',
|
||||
array: true,
|
||||
description: 'The html of the button. Can create own style.'
|
||||
},
|
||||
prompt: {
|
||||
type: jsPsych.plugins.parameterType.STRING,
|
||||
pretty_name: 'Prompt',
|
||||
default: null,
|
||||
description: 'Any content here will be displayed under the button.'
|
||||
},
|
||||
stimulus_duration: {
|
||||
type: jsPsych.plugins.parameterType.INT,
|
||||
pretty_name: 'Stimulus duration',
|
||||
default: null,
|
||||
description: 'How long to hide the stimulus.'
|
||||
},
|
||||
trial_duration: {
|
||||
type: jsPsych.plugins.parameterType.INT,
|
||||
pretty_name: 'Trial duration',
|
||||
default: null,
|
||||
description: 'How long to show the trial.'
|
||||
},
|
||||
margin_vertical: {
|
||||
type: jsPsych.plugins.parameterType.STRING,
|
||||
pretty_name: 'Margin vertical',
|
||||
default: '0px',
|
||||
description: 'The vertical margin of the button.'
|
||||
},
|
||||
margin_horizontal: {
|
||||
type: jsPsych.plugins.parameterType.STRING,
|
||||
pretty_name: 'Margin horizontal',
|
||||
default: '8px',
|
||||
description: 'The horizontal margin of the button.'
|
||||
},
|
||||
response_ends_trial: {
|
||||
type: jsPsych.plugins.parameterType.BOOL,
|
||||
pretty_name: 'Response ends trial',
|
||||
default: true,
|
||||
description: 'If true, then trial will end when user responds.'
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
plugin.trial = function(display_element, trial) {
|
||||
|
||||
// display stimulus
|
||||
var html = '<img src="'+trial.stimulus+'" id="jspsych-image-button-response-stimulus" style="';
|
||||
if(trial.stimulus_height !== null){
|
||||
html += 'height:'+trial.stimulus_height+'px; '
|
||||
if(trial.stimulus_width == null && trial.maintain_aspect_ratio){
|
||||
html += 'width: auto; ';
|
||||
}
|
||||
}
|
||||
if(trial.stimulus_width !== null){
|
||||
html += 'width:'+trial.stimulus_width+'px; '
|
||||
if(trial.stimulus_height == null && trial.maintain_aspect_ratio){
|
||||
html += 'height: auto; ';
|
||||
}
|
||||
}
|
||||
html +='"></img>';
|
||||
|
||||
//display buttons
|
||||
var buttons = [];
|
||||
if (Array.isArray(trial.button_html)) {
|
||||
if (trial.button_html.length == trial.choices.length) {
|
||||
buttons = trial.button_html;
|
||||
} else {
|
||||
console.error('Error in image-button-response plugin. The length of the button_html array does not equal the length of the choices array');
|
||||
}
|
||||
} else {
|
||||
for (var i = 0; i < trial.choices.length; i++) {
|
||||
buttons.push(trial.button_html);
|
||||
}
|
||||
}
|
||||
html += '<div id="jspsych-image-button-response-btngroup">';
|
||||
|
||||
for (var i = 0; i < trial.choices.length; i++) {
|
||||
var str = buttons[i].replace(/%choice%/g, trial.choices[i]);
|
||||
html += '<div class="jspsych-image-button-response-button" style="display: inline-block; margin:'+trial.margin_vertical+' '+trial.margin_horizontal+'" id="jspsych-image-button-response-button-' + i +'" data-choice="'+i+'">'+str+'</div>';
|
||||
}
|
||||
html += '</div>';
|
||||
|
||||
//show prompt if there is one
|
||||
if (trial.prompt !== null) {
|
||||
html += trial.prompt;
|
||||
}
|
||||
|
||||
display_element.innerHTML = html;
|
||||
|
||||
// start timing
|
||||
var start_time = performance.now();
|
||||
|
||||
for (var i = 0; i < trial.choices.length; i++) {
|
||||
display_element.querySelector('#jspsych-image-button-response-button-' + i).addEventListener('click', function(e){
|
||||
var choice = e.currentTarget.getAttribute('data-choice'); // don't use dataset for jsdom compatibility
|
||||
after_response(choice);
|
||||
});
|
||||
}
|
||||
|
||||
// store response
|
||||
var response = {
|
||||
rt: null,
|
||||
button: null
|
||||
};
|
||||
|
||||
// function to handle responses by the subject
|
||||
function after_response(choice) {
|
||||
|
||||
// measure rt
|
||||
var end_time = performance.now();
|
||||
var rt = end_time - start_time;
|
||||
response.button = choice;
|
||||
response.rt = rt;
|
||||
|
||||
// after a valid response, the stimulus will have the CSS class 'responded'
|
||||
// which can be used to provide visual feedback that a response was recorded
|
||||
display_element.querySelector('#jspsych-image-button-response-stimulus').className += ' responded';
|
||||
|
||||
// disable all the buttons after a response
|
||||
var btns = document.querySelectorAll('.jspsych-image-button-response-button button');
|
||||
for(var i=0; i<btns.length; i++){
|
||||
//btns[i].removeEventListener('click');
|
||||
btns[i].setAttribute('disabled', 'disabled');
|
||||
}
|
||||
|
||||
if (trial.response_ends_trial) {
|
||||
end_trial();
|
||||
}
|
||||
};
|
||||
|
||||
// function to end trial when it is time
|
||||
function end_trial() {
|
||||
|
||||
// kill any remaining setTimeout handlers
|
||||
jsPsych.pluginAPI.clearAllTimeouts();
|
||||
|
||||
// gather the data to store for the trial
|
||||
var trial_data = {
|
||||
"rt": response.rt,
|
||||
"stimulus": trial.stimulus,
|
||||
"button_pressed": response.button
|
||||
};
|
||||
|
||||
// clear the display
|
||||
display_element.innerHTML = '';
|
||||
|
||||
// move on to the next trial
|
||||
jsPsych.finishTrial(trial_data);
|
||||
};
|
||||
|
||||
|
||||
|
||||
// hide image if timing is set
|
||||
if (trial.stimulus_duration !== null) {
|
||||
jsPsych.pluginAPI.setTimeout(function() {
|
||||
display_element.querySelector('#jspsych-image-button-response-stimulus').style.visibility = 'hidden';
|
||||
}, trial.stimulus_duration);
|
||||
}
|
||||
|
||||
// end trial if time limit is set
|
||||
if (trial.trial_duration !== null) {
|
||||
jsPsych.pluginAPI.setTimeout(function() {
|
||||
end_trial();
|
||||
}, trial.trial_duration);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
return plugin;
|
||||
})();
|
||||
182
PCSurvey/PCstatic/js/plugins/jspsych-image-keyboard-response.js
Normal file
182
PCSurvey/PCstatic/js/plugins/jspsych-image-keyboard-response.js
Normal file
@@ -0,0 +1,182 @@
|
||||
/**
|
||||
* jspsych-image-keyboard-response
|
||||
* Josh de Leeuw
|
||||
*
|
||||
* plugin for displaying a stimulus and getting a keyboard response
|
||||
*
|
||||
* documentation: docs.jspsych.org
|
||||
*
|
||||
**/
|
||||
|
||||
|
||||
jsPsych.plugins["image-keyboard-response"] = (function() {
|
||||
|
||||
var plugin = {};
|
||||
|
||||
jsPsych.pluginAPI.registerPreload('image-keyboard-response', 'stimulus', 'image');
|
||||
|
||||
plugin.info = {
|
||||
name: 'image-keyboard-response',
|
||||
description: '',
|
||||
parameters: {
|
||||
stimulus: {
|
||||
type: jsPsych.plugins.parameterType.IMAGE,
|
||||
pretty_name: 'Stimulus',
|
||||
default: undefined,
|
||||
description: 'The image to be displayed'
|
||||
},
|
||||
stimulus_height: {
|
||||
type: jsPsych.plugins.parameterType.INT,
|
||||
pretty_name: 'Image height',
|
||||
default: null,
|
||||
description: 'Set the image height in pixels'
|
||||
},
|
||||
stimulus_width: {
|
||||
type: jsPsych.plugins.parameterType.INT,
|
||||
pretty_name: 'Image width',
|
||||
default: null,
|
||||
description: 'Set the image width in pixels'
|
||||
},
|
||||
maintain_aspect_ratio: {
|
||||
type: jsPsych.plugins.parameterType.BOOL,
|
||||
pretty_name: 'Maintain aspect ratio',
|
||||
default: true,
|
||||
description: 'Maintain the aspect ratio after setting width or height'
|
||||
},
|
||||
choices: {
|
||||
type: jsPsych.plugins.parameterType.KEYCODE,
|
||||
array: true,
|
||||
pretty_name: 'Choices',
|
||||
default: jsPsych.ALL_KEYS,
|
||||
description: 'The keys the subject is allowed to press to respond to the stimulus.'
|
||||
},
|
||||
prompt: {
|
||||
type: jsPsych.plugins.parameterType.STRING,
|
||||
pretty_name: 'Prompt',
|
||||
default: null,
|
||||
description: 'Any content here will be displayed below the stimulus.'
|
||||
},
|
||||
stimulus_duration: {
|
||||
type: jsPsych.plugins.parameterType.INT,
|
||||
pretty_name: 'Stimulus duration',
|
||||
default: null,
|
||||
description: 'How long to hide the stimulus.'
|
||||
},
|
||||
trial_duration: {
|
||||
type: jsPsych.plugins.parameterType.INT,
|
||||
pretty_name: 'Trial duration',
|
||||
default: null,
|
||||
description: 'How long to show trial before it ends.'
|
||||
},
|
||||
response_ends_trial: {
|
||||
type: jsPsych.plugins.parameterType.BOOL,
|
||||
pretty_name: 'Response ends trial',
|
||||
default: true,
|
||||
description: 'If true, trial will end when subject makes a response.'
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
plugin.trial = function(display_element, trial) {
|
||||
|
||||
// display stimulus
|
||||
var html = '<img src="'+trial.stimulus+'" id="jspsych-image-keyboard-response-stimulus" style="';
|
||||
if(trial.stimulus_height !== null){
|
||||
html += 'height:'+trial.stimulus_height+'px; '
|
||||
if(trial.stimulus_width == null && trial.maintain_aspect_ratio){
|
||||
html += 'width: auto; ';
|
||||
}
|
||||
}
|
||||
if(trial.stimulus_width !== null){
|
||||
html += 'width:'+trial.stimulus_width+'px; '
|
||||
if(trial.stimulus_height == null && trial.maintain_aspect_ratio){
|
||||
html += 'height: auto; ';
|
||||
}
|
||||
}
|
||||
html +='"></img>';
|
||||
|
||||
// add prompt
|
||||
if (trial.prompt !== null){
|
||||
html += trial.prompt;
|
||||
}
|
||||
|
||||
// render
|
||||
display_element.innerHTML = html;
|
||||
|
||||
// store response
|
||||
var response = {
|
||||
rt: null,
|
||||
key: null
|
||||
};
|
||||
|
||||
// function to end trial when it is time
|
||||
var end_trial = function() {
|
||||
|
||||
// kill any remaining setTimeout handlers
|
||||
jsPsych.pluginAPI.clearAllTimeouts();
|
||||
|
||||
// kill keyboard listeners
|
||||
if (typeof keyboardListener !== 'undefined') {
|
||||
jsPsych.pluginAPI.cancelKeyboardResponse(keyboardListener);
|
||||
}
|
||||
|
||||
// gather the data to store for the trial
|
||||
var trial_data = {
|
||||
"rt": response.rt,
|
||||
"stimulus": trial.stimulus,
|
||||
"key_press": response.key
|
||||
};
|
||||
|
||||
// clear the display
|
||||
display_element.innerHTML = '';
|
||||
|
||||
// move on to the next trial
|
||||
jsPsych.finishTrial(trial_data);
|
||||
};
|
||||
|
||||
// function to handle responses by the subject
|
||||
var after_response = function(info) {
|
||||
|
||||
// after a valid response, the stimulus will have the CSS class 'responded'
|
||||
// which can be used to provide visual feedback that a response was recorded
|
||||
display_element.querySelector('#jspsych-image-keyboard-response-stimulus').className += ' responded';
|
||||
|
||||
// only record the first response
|
||||
if (response.key == null) {
|
||||
response = info;
|
||||
}
|
||||
|
||||
if (trial.response_ends_trial) {
|
||||
end_trial();
|
||||
}
|
||||
};
|
||||
|
||||
// start the response listener
|
||||
if (trial.choices != jsPsych.NO_KEYS) {
|
||||
var keyboardListener = jsPsych.pluginAPI.getKeyboardResponse({
|
||||
callback_function: after_response,
|
||||
valid_responses: trial.choices,
|
||||
rt_method: 'performance',
|
||||
persist: false,
|
||||
allow_held_key: false
|
||||
});
|
||||
}
|
||||
|
||||
// hide stimulus if stimulus_duration is set
|
||||
if (trial.stimulus_duration !== null) {
|
||||
jsPsych.pluginAPI.setTimeout(function() {
|
||||
display_element.querySelector('#jspsych-image-keyboard-response-stimulus').style.visibility = 'hidden';
|
||||
}, trial.stimulus_duration);
|
||||
}
|
||||
|
||||
// end trial if trial_duration is set
|
||||
if (trial.trial_duration !== null) {
|
||||
jsPsych.pluginAPI.setTimeout(function() {
|
||||
end_trial();
|
||||
}, trial.trial_duration);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
return plugin;
|
||||
})();
|
||||
227
PCSurvey/PCstatic/js/plugins/jspsych-image-slider-response.js
Normal file
227
PCSurvey/PCstatic/js/plugins/jspsych-image-slider-response.js
Normal file
@@ -0,0 +1,227 @@
|
||||
/**
|
||||
* jspsych-image-slider-response
|
||||
* a jspsych plugin for free response survey questions
|
||||
*
|
||||
* Josh de Leeuw
|
||||
*
|
||||
* documentation: docs.jspsych.org
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
jsPsych.plugins['image-slider-response'] = (function() {
|
||||
|
||||
var plugin = {};
|
||||
|
||||
jsPsych.pluginAPI.registerPreload('image-slider-response', 'stimulus', 'image');
|
||||
|
||||
plugin.info = {
|
||||
name: 'image-slider-response',
|
||||
description: '',
|
||||
parameters: {
|
||||
stimulus: {
|
||||
type: jsPsych.plugins.parameterType.IMAGE,
|
||||
pretty_name: 'Stimulus',
|
||||
default: undefined,
|
||||
description: 'The image to be displayed'
|
||||
},
|
||||
stimulus_height: {
|
||||
type: jsPsych.plugins.parameterType.INT,
|
||||
pretty_name: 'Image height',
|
||||
default: null,
|
||||
description: 'Set the image height in pixels'
|
||||
},
|
||||
stimulus_width: {
|
||||
type: jsPsych.plugins.parameterType.INT,
|
||||
pretty_name: 'Image width',
|
||||
default: null,
|
||||
description: 'Set the image width in pixels'
|
||||
},
|
||||
maintain_aspect_ratio: {
|
||||
type: jsPsych.plugins.parameterType.BOOL,
|
||||
pretty_name: 'Maintain aspect ratio',
|
||||
default: true,
|
||||
description: 'Maintain the aspect ratio after setting width or height'
|
||||
},
|
||||
min: {
|
||||
type: jsPsych.plugins.parameterType.INT,
|
||||
pretty_name: 'Min slider',
|
||||
default: 0,
|
||||
description: 'Sets the minimum value of the slider.'
|
||||
},
|
||||
max: {
|
||||
type: jsPsych.plugins.parameterType.INT,
|
||||
pretty_name: 'Max slider',
|
||||
default: 100,
|
||||
description: 'Sets the maximum value of the slider',
|
||||
},
|
||||
start: {
|
||||
type: jsPsych.plugins.parameterType.INT,
|
||||
pretty_name: 'Slider starting value',
|
||||
default: 50,
|
||||
description: 'Sets the starting value of the slider',
|
||||
},
|
||||
step: {
|
||||
type: jsPsych.plugins.parameterType.INT,
|
||||
pretty_name: 'Step',
|
||||
default: 1,
|
||||
description: 'Sets the step of the slider'
|
||||
},
|
||||
labels: {
|
||||
type: jsPsych.plugins.parameterType.HTML_STRING,
|
||||
pretty_name:'Labels',
|
||||
default: [],
|
||||
array: true,
|
||||
description: 'Labels of the slider.',
|
||||
},
|
||||
slider_width: {
|
||||
type: jsPsych.plugins.parameterType.INT,
|
||||
pretty_name:'Slider width',
|
||||
default: null,
|
||||
description: 'Width of the slider in pixels.'
|
||||
},
|
||||
button_label: {
|
||||
type: jsPsych.plugins.parameterType.STRING,
|
||||
pretty_name: 'Button label',
|
||||
default: 'Continue',
|
||||
array: false,
|
||||
description: 'Label of the button to advance.'
|
||||
},
|
||||
require_movement: {
|
||||
type: jsPsych.plugins.parameterType.BOOL,
|
||||
pretty_name: 'Require movement',
|
||||
default: false,
|
||||
description: 'If true, the participant will have to move the slider before continuing.'
|
||||
},
|
||||
prompt: {
|
||||
type: jsPsych.plugins.parameterType.STRING,
|
||||
pretty_name: 'Prompt',
|
||||
default: null,
|
||||
description: 'Any content here will be displayed below the slider.'
|
||||
},
|
||||
stimulus_duration: {
|
||||
type: jsPsych.plugins.parameterType.INT,
|
||||
pretty_name: 'Stimulus duration',
|
||||
default: null,
|
||||
description: 'How long to hide the stimulus.'
|
||||
},
|
||||
trial_duration: {
|
||||
type: jsPsych.plugins.parameterType.INT,
|
||||
pretty_name: 'Trial duration',
|
||||
default: null,
|
||||
description: 'How long to show the trial.'
|
||||
},
|
||||
response_ends_trial: {
|
||||
type: jsPsych.plugins.parameterType.BOOL,
|
||||
pretty_name: 'Response ends trial',
|
||||
default: true,
|
||||
description: 'If true, trial will end when user makes a response.'
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
plugin.trial = function(display_element, trial) {
|
||||
|
||||
var html = '<div id="jspsych-image-slider-response-wrapper" style="margin: 100px 0px;">';
|
||||
html += '<div id="jspsych-image-slider-response-stimulus">';
|
||||
html += '<img src="'+trial.stimulus+'" style="';
|
||||
if(trial.stimulus_height !== null){
|
||||
html += 'height:'+trial.stimulus_height+'px; '
|
||||
if(trial.stimulus_width == null && trial.maintain_aspect_ratio){
|
||||
html += 'width: auto; ';
|
||||
}
|
||||
}
|
||||
if(trial.stimulus_width !== null){
|
||||
html += 'width:'+trial.stimulus_width+'px; '
|
||||
if(trial.stimulus_height == null && trial.maintain_aspect_ratio){
|
||||
html += 'height: auto; ';
|
||||
}
|
||||
}
|
||||
html += '"></img>';
|
||||
html += '</div>';
|
||||
html += '<div class="jspsych-image-slider-response-container" style="position:relative; margin: 0 auto 3em auto; ';
|
||||
if(trial.slider_width !== null){
|
||||
html += 'width:'+trial.slider_width+'px;';
|
||||
}
|
||||
html += '">';
|
||||
html += '<input type="range" value="'+trial.start+'" min="'+trial.min+'" max="'+trial.max+'" step="'+trial.step+'" style="width: 100%;" id="jspsych-image-slider-response-response"></input>';
|
||||
html += '<div>'
|
||||
for(var j=0; j < trial.labels.length; j++){
|
||||
var width = 100/(trial.labels.length-1);
|
||||
var left_offset = (j * (100 /(trial.labels.length - 1))) - (width/2);
|
||||
html += '<div style="display: inline-block; position: absolute; left:'+left_offset+'%; text-align: center; width: '+width+'%;">';
|
||||
html += '<span style="text-align: center; font-size: 80%;">'+trial.labels[j]+'</span>';
|
||||
html += '</div>'
|
||||
}
|
||||
html += '</div>';
|
||||
html += '</div>';
|
||||
html += '</div>';
|
||||
|
||||
if (trial.prompt !== null){
|
||||
html += trial.prompt;
|
||||
}
|
||||
|
||||
// add submit button
|
||||
html += '<button id="jspsych-image-slider-response-next" class="jspsych-btn" '+ (trial.require_movement ? "disabled" : "") + '>'+trial.button_label+'</button>';
|
||||
|
||||
display_element.innerHTML = html;
|
||||
|
||||
var response = {
|
||||
rt: null,
|
||||
response: null
|
||||
};
|
||||
|
||||
if(trial.require_movement){
|
||||
display_element.querySelector('#jspsych-image-slider-response-response').addEventListener('change', function(){
|
||||
display_element.querySelector('#jspsych-image-slider-response-next').disabled = false;
|
||||
})
|
||||
}
|
||||
|
||||
display_element.querySelector('#jspsych-image-slider-response-next').addEventListener('click', function() {
|
||||
// measure response time
|
||||
var endTime = performance.now();
|
||||
response.rt = endTime - startTime;
|
||||
response.response = display_element.querySelector('#jspsych-image-slider-response-response').value;
|
||||
|
||||
if(trial.response_ends_trial){
|
||||
end_trial();
|
||||
} else {
|
||||
display_element.querySelector('#jspsych-image-slider-response-next').disabled = true;
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
function end_trial(){
|
||||
|
||||
jsPsych.pluginAPI.clearAllTimeouts();
|
||||
|
||||
// save data
|
||||
var trialdata = {
|
||||
"rt": response.rt,
|
||||
"response": response.response
|
||||
};
|
||||
|
||||
display_element.innerHTML = '';
|
||||
|
||||
// next trial
|
||||
jsPsych.finishTrial(trialdata);
|
||||
}
|
||||
|
||||
if (trial.stimulus_duration !== null) {
|
||||
jsPsych.pluginAPI.setTimeout(function() {
|
||||
display_element.querySelector('#jspsych-image-slider-response-stimulus').style.visibility = 'hidden';
|
||||
}, trial.stimulus_duration);
|
||||
}
|
||||
|
||||
// end trial if trial_duration is set
|
||||
if (trial.trial_duration !== null) {
|
||||
jsPsych.pluginAPI.setTimeout(function() {
|
||||
end_trial();
|
||||
}, trial.trial_duration);
|
||||
}
|
||||
|
||||
var startTime = performance.now();
|
||||
};
|
||||
|
||||
return plugin;
|
||||
})();
|
||||
203
PCSurvey/PCstatic/js/plugins/jspsych-instructions.js
Normal file
203
PCSurvey/PCstatic/js/plugins/jspsych-instructions.js
Normal file
@@ -0,0 +1,203 @@
|
||||
/* jspsych-text.js
|
||||
* Josh de Leeuw
|
||||
*
|
||||
* This plugin displays text (including HTML formatted strings) during the experiment.
|
||||
* Use it to show instructions, provide performance feedback, etc...
|
||||
*
|
||||
* documentation: docs.jspsych.org
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
jsPsych.plugins.instructions = (function() {
|
||||
|
||||
var plugin = {};
|
||||
|
||||
plugin.info = {
|
||||
name: 'instructions',
|
||||
description: '',
|
||||
parameters: {
|
||||
pages: {
|
||||
type: jsPsych.plugins.parameterType.HTML_STRING,
|
||||
pretty_name: 'Pages',
|
||||
default: undefined,
|
||||
array: true,
|
||||
description: 'Each element of the array is the content for a single page.'
|
||||
},
|
||||
key_forward: {
|
||||
type: jsPsych.plugins.parameterType.KEYCODE,
|
||||
pretty_name: 'Key forward',
|
||||
default: 'rightarrow',
|
||||
description: 'The key the subject can press in order to advance to the next page.'
|
||||
},
|
||||
key_backward: {
|
||||
type: jsPsych.plugins.parameterType.KEYCODE,
|
||||
pretty_name: 'Key backward',
|
||||
default: 'leftarrow',
|
||||
description: 'The key that the subject can press to return to the previous page.'
|
||||
},
|
||||
allow_backward: {
|
||||
type: jsPsych.plugins.parameterType.BOOL,
|
||||
pretty_name: 'Allow backward',
|
||||
default: true,
|
||||
description: 'If true, the subject can return to the previous page of the instructions.'
|
||||
},
|
||||
allow_keys: {
|
||||
type: jsPsych.plugins.parameterType.BOOL,
|
||||
pretty_name: 'Allow keys',
|
||||
default: true,
|
||||
description: 'If true, the subject can use keyboard keys to navigate the pages.'
|
||||
},
|
||||
show_clickable_nav: {
|
||||
type: jsPsych.plugins.parameterType.BOOL,
|
||||
pretty_name: 'Show clickable nav',
|
||||
default: false,
|
||||
description: 'If true, then a "Previous" and "Next" button will be displayed beneath the instructions.'
|
||||
},
|
||||
button_label_previous: {
|
||||
type: jsPsych.plugins.parameterType.STRING,
|
||||
pretty_name: 'Button label previous',
|
||||
default: 'Previous',
|
||||
description: 'The text that appears on the button to go backwards.'
|
||||
},
|
||||
button_label_next: {
|
||||
type: jsPsych.plugins.parameterType.STRING,
|
||||
pretty_name: 'Button label next',
|
||||
default: 'Next',
|
||||
description: 'The text that appears on the button to go forwards.'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
plugin.trial = function(display_element, trial) {
|
||||
|
||||
var current_page = 0;
|
||||
|
||||
var view_history = [];
|
||||
|
||||
var start_time = (new Date()).getTime();
|
||||
|
||||
var last_page_update_time = start_time;
|
||||
|
||||
function btnListener(evt){
|
||||
evt.target.removeEventListener('click', btnListener);
|
||||
if(this.id === "jspsych-instructions-back"){
|
||||
back();
|
||||
}
|
||||
else if(this.id === 'jspsych-instructions-next'){
|
||||
next();
|
||||
}
|
||||
}
|
||||
|
||||
function show_current_page() {
|
||||
display_element.innerHTML = trial.pages[current_page];
|
||||
|
||||
if (trial.show_clickable_nav) {
|
||||
|
||||
var nav_html = "<div class='jspsych-instructions-nav' style='padding: 10px 0px;'>";
|
||||
if (current_page != 0 && trial.allow_backward) {
|
||||
nav_html += "<button id='jspsych-instructions-back' class='jspsych-btn' style='margin-right: 5px;'>< "+trial.button_label_previous+"</button>";
|
||||
}
|
||||
nav_html += "<button id='jspsych-instructions-next' class='jspsych-btn' style='margin-left: 5px;'>"+trial.button_label_next+" ></button></div>"
|
||||
|
||||
display_element.innerHTML += nav_html;
|
||||
|
||||
if (current_page != 0 && trial.allow_backward) {
|
||||
display_element.querySelector('#jspsych-instructions-back').addEventListener('click', btnListener);
|
||||
}
|
||||
|
||||
display_element.querySelector('#jspsych-instructions-next').addEventListener('click', btnListener);
|
||||
}
|
||||
}
|
||||
|
||||
function next() {
|
||||
|
||||
add_current_page_to_view_history()
|
||||
|
||||
current_page++;
|
||||
|
||||
// if done, finish up...
|
||||
if (current_page >= trial.pages.length) {
|
||||
endTrial();
|
||||
} else {
|
||||
show_current_page();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function back() {
|
||||
|
||||
add_current_page_to_view_history()
|
||||
|
||||
current_page--;
|
||||
|
||||
show_current_page();
|
||||
}
|
||||
|
||||
function add_current_page_to_view_history() {
|
||||
|
||||
var current_time = (new Date()).getTime();
|
||||
|
||||
var page_view_time = current_time - last_page_update_time;
|
||||
|
||||
view_history.push({
|
||||
page_index: current_page,
|
||||
viewing_time: page_view_time
|
||||
});
|
||||
|
||||
last_page_update_time = current_time;
|
||||
}
|
||||
|
||||
function endTrial() {
|
||||
|
||||
if (trial.allow_keys) {
|
||||
jsPsych.pluginAPI.cancelKeyboardResponse(keyboard_listener);
|
||||
}
|
||||
|
||||
display_element.innerHTML = '';
|
||||
|
||||
var trial_data = {
|
||||
"view_history": JSON.stringify(view_history),
|
||||
"rt": (new Date()).getTime() - start_time
|
||||
};
|
||||
|
||||
jsPsych.finishTrial(trial_data);
|
||||
}
|
||||
|
||||
var after_response = function(info) {
|
||||
|
||||
// have to reinitialize this instead of letting it persist to prevent accidental skips of pages by holding down keys too long
|
||||
keyboard_listener = jsPsych.pluginAPI.getKeyboardResponse({
|
||||
callback_function: after_response,
|
||||
valid_responses: [trial.key_forward, trial.key_backward],
|
||||
rt_method: 'date',
|
||||
persist: false,
|
||||
allow_held_key: false
|
||||
});
|
||||
// check if key is forwards or backwards and update page
|
||||
if (info.key === trial.key_backward || info.key === jsPsych.pluginAPI.convertKeyCharacterToKeyCode(trial.key_backward)) {
|
||||
if (current_page !== 0 && trial.allow_backward) {
|
||||
back();
|
||||
}
|
||||
}
|
||||
|
||||
if (info.key === trial.key_forward || info.key === jsPsych.pluginAPI.convertKeyCharacterToKeyCode(trial.key_forward)) {
|
||||
next();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
show_current_page();
|
||||
|
||||
if (trial.allow_keys) {
|
||||
var keyboard_listener = jsPsych.pluginAPI.getKeyboardResponse({
|
||||
callback_function: after_response,
|
||||
valid_responses: [trial.key_forward, trial.key_backward],
|
||||
rt_method: 'date',
|
||||
persist: false
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
return plugin;
|
||||
})();
|
||||
1369
PCSurvey/PCstatic/js/plugins/jspsych-rdk.js
Normal file
1369
PCSurvey/PCstatic/js/plugins/jspsych-rdk.js
Normal file
File diff suppressed because it is too large
Load Diff
134
PCSurvey/PCstatic/js/plugins/jspsych-reconstruction.js
Normal file
134
PCSurvey/PCstatic/js/plugins/jspsych-reconstruction.js
Normal file
@@ -0,0 +1,134 @@
|
||||
/**
|
||||
* jspsych-reconstruction
|
||||
* a jspsych plugin for a reconstruction task where the subject recreates
|
||||
* a stimulus from memory
|
||||
*
|
||||
* Josh de Leeuw
|
||||
*
|
||||
* documentation: docs.jspsych.org
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
jsPsych.plugins['reconstruction'] = (function() {
|
||||
|
||||
var plugin = {};
|
||||
|
||||
plugin.info = {
|
||||
name: 'reconstruction',
|
||||
description: '',
|
||||
parameters: {
|
||||
stim_function: {
|
||||
type: jsPsych.plugins.parameterType.FUNCTION,
|
||||
pretty_name: 'Stimulus function',
|
||||
default: undefined,
|
||||
description: 'A function with a single parameter that returns an HTML-formatted string representing the stimulus.'
|
||||
},
|
||||
starting_value: {
|
||||
type: jsPsych.plugins.parameterType.FLOAT,
|
||||
pretty_name: 'Starting value',
|
||||
default: 0.5,
|
||||
description: 'The starting value of the stimulus parameter.'
|
||||
},
|
||||
step_size: {
|
||||
type: jsPsych.plugins.parameterType.FLOAT,
|
||||
pretty_name: 'Step size',
|
||||
default: 0.05,
|
||||
description: 'The change in the stimulus parameter caused by pressing one of the modification keys.'
|
||||
},
|
||||
key_increase: {
|
||||
type: jsPsych.plugins.parameterType.KEYCODE,
|
||||
pretty_name: 'Key increase',
|
||||
default: 'h',
|
||||
description: 'The key to press for increasing the parameter value.'
|
||||
},
|
||||
key_decrease: {
|
||||
type: jsPsych.plugins.parameterType.KEYCODE,
|
||||
pretty_name: 'Key decrease',
|
||||
default: 'g',
|
||||
description: 'The key to press for decreasing the parameter value.'
|
||||
},
|
||||
button_label: {
|
||||
type: jsPsych.plugins.parameterType.STRING,
|
||||
pretty_name: 'Button label',
|
||||
default: 'Continue',
|
||||
description: 'The text that appears on the button to finish the trial.'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
plugin.trial = function(display_element, trial) {
|
||||
|
||||
// current param level
|
||||
var param = trial.starting_value;
|
||||
|
||||
// set-up key listeners
|
||||
var after_response = function(info) {
|
||||
|
||||
//console.log('fire');
|
||||
|
||||
var key_i = (typeof trial.key_increase == 'string') ? jsPsych.pluginAPI.convertKeyCharacterToKeyCode(trial.key_increase) : trial.key_increase;
|
||||
var key_d = (typeof trial.key_decrease == 'string') ? jsPsych.pluginAPI.convertKeyCharacterToKeyCode(trial.key_decrease) : trial.key_decrease;
|
||||
|
||||
// get new param value
|
||||
if (info.key == key_i) {
|
||||
param = param + trial.step_size;
|
||||
} else if (info.key == key_d) {
|
||||
param = param - trial.step_size;
|
||||
}
|
||||
param = Math.max(Math.min(1, param), 0);
|
||||
|
||||
// refresh the display
|
||||
draw(param);
|
||||
}
|
||||
|
||||
// listen for responses
|
||||
var key_listener = jsPsych.pluginAPI.getKeyboardResponse({
|
||||
callback_function: after_response,
|
||||
valid_responses: [trial.key_increase, trial.key_decrease],
|
||||
rt_method: 'performance',
|
||||
persist: true,
|
||||
allow_held_key: true
|
||||
});
|
||||
// draw first iteration
|
||||
draw(param);
|
||||
|
||||
function draw(param) {
|
||||
|
||||
//console.log(param);
|
||||
|
||||
display_element.innerHTML = '<div id="jspsych-reconstruction-stim-container">'+trial.stim_function(param)+'</div>';
|
||||
|
||||
// add submit button
|
||||
display_element.innerHTML += '<button id="jspsych-reconstruction-next" class="jspsych-btn jspsych-reconstruction">'+trial.button_label+'</button>';
|
||||
|
||||
display_element.querySelector('#jspsych-reconstruction-next').addEventListener('click', endTrial);
|
||||
}
|
||||
|
||||
function endTrial() {
|
||||
// measure response time
|
||||
var endTime =performance.now();
|
||||
var response_time = endTime - startTime;
|
||||
|
||||
// clear keyboard response
|
||||
jsPsych.pluginAPI.cancelKeyboardResponse(key_listener);
|
||||
|
||||
// save data
|
||||
var trial_data = {
|
||||
"rt": response_time,
|
||||
"final_value": param,
|
||||
"start_value": trial.starting_value
|
||||
};
|
||||
|
||||
display_element.innerHTML = '';
|
||||
|
||||
// next trial
|
||||
jsPsych.finishTrial(trial_data);
|
||||
}
|
||||
|
||||
var startTime = performance.now();
|
||||
|
||||
};
|
||||
|
||||
return plugin;
|
||||
})();
|
||||
166
PCSurvey/PCstatic/js/plugins/jspsych-resize.js
Normal file
166
PCSurvey/PCstatic/js/plugins/jspsych-resize.js
Normal file
@@ -0,0 +1,166 @@
|
||||
/**
|
||||
* jspsych-resize
|
||||
* Steve Chao
|
||||
*
|
||||
* plugin for controlling the real world size of the display
|
||||
*
|
||||
* documentation: docs.jspsych.org
|
||||
*
|
||||
**/
|
||||
|
||||
jsPsych.plugins["resize"] = (function() {
|
||||
|
||||
var plugin = {};
|
||||
|
||||
plugin.info = {
|
||||
name: 'resize',
|
||||
description: '',
|
||||
parameters: {
|
||||
item_height: {
|
||||
type: jsPsych.plugins.parameterType.INT,
|
||||
pretty_name: 'Item height',
|
||||
default: 1,
|
||||
description: 'The height of the item to be measured.'
|
||||
},
|
||||
item_width: {
|
||||
type: jsPsych.plugins.parameterType.INT,
|
||||
pretty_name: 'Item width',
|
||||
default: 1,
|
||||
description: 'The width of the item to be measured.'
|
||||
},
|
||||
prompt: {
|
||||
type: jsPsych.plugins.parameterType.STRING,
|
||||
pretty_name: 'Prompt',
|
||||
default: null,
|
||||
description: 'The content displayed below the resizable box and above the button.'
|
||||
},
|
||||
pixels_per_unit: {
|
||||
type: jsPsych.plugins.parameterType.INT,
|
||||
pretty_name: 'Pixels per unit',
|
||||
default: 100,
|
||||
description: 'After the scaling factor is applied, this many pixels will equal one unit of measurement.'
|
||||
},
|
||||
starting_size: {
|
||||
type: jsPsych.plugins.parameterType.INT,
|
||||
pretty_name: 'Starting size',
|
||||
default: 100,
|
||||
description: 'The initial size of the box, in pixels, along the larget dimension.'
|
||||
},
|
||||
button_label: {
|
||||
type: jsPsych.plugins.parameterType.STRING,
|
||||
pretty_name: 'Button label',
|
||||
default: 'Continue',
|
||||
description: 'Label to display on the button to complete calibration.'
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
plugin.trial = function(display_element, trial) {
|
||||
|
||||
var aspect_ratio = trial.item_width / trial.item_height;
|
||||
|
||||
// variables to determine div size
|
||||
if(trial.item_width >= trial.item_height){
|
||||
var start_div_width = trial.starting_size;
|
||||
var start_div_height = Math.round(trial.starting_size / aspect_ratio);
|
||||
} else {
|
||||
var start_div_height = trial.starting_size;
|
||||
var start_div_width = Math.round(trial.starting_size * aspect_ratio);
|
||||
}
|
||||
|
||||
// create html for display
|
||||
var html ='<div id="jspsych-resize-div" style="border: 2px solid steelblue; height: '+start_div_height+'px; width:'+start_div_width+'px; margin: 7px auto; background-color: lightsteelblue; position: relative;">';
|
||||
html += '<div id="jspsych-resize-handle" style="cursor: nwse-resize; background-color: steelblue; width: 10px; height: 10px; border: 2px solid lightsteelblue; position: absolute; bottom: 0; right: 0;"></div>';
|
||||
html += '</div>';
|
||||
if (trial.prompt !== null){
|
||||
html += trial.prompt;
|
||||
}
|
||||
html += '<a class="jspsych-btn" id="jspsych-resize-btn">'+trial.button_label+'</a>';
|
||||
|
||||
// render
|
||||
display_element.innerHTML = html;
|
||||
|
||||
// listens for the click
|
||||
document.getElementById("jspsych-resize-btn").addEventListener('click', function() {
|
||||
scale();
|
||||
end_trial();
|
||||
});
|
||||
|
||||
var dragging = false;
|
||||
var origin_x, origin_y;
|
||||
var cx, cy;
|
||||
|
||||
var mousedownevent = function(e){
|
||||
e.preventDefault();
|
||||
dragging = true;
|
||||
origin_x = e.pageX;
|
||||
origin_y = e.pageY;
|
||||
cx = parseInt(scale_div.style.width);
|
||||
cy = parseInt(scale_div.style.height);
|
||||
}
|
||||
|
||||
display_element.querySelector('#jspsych-resize-handle').addEventListener('mousedown', mousedownevent);
|
||||
|
||||
var mouseupevent = function(e){
|
||||
dragging = false;
|
||||
}
|
||||
|
||||
document.addEventListener('mouseup', mouseupevent);
|
||||
|
||||
var scale_div = display_element.querySelector('#jspsych-resize-div');
|
||||
|
||||
var resizeevent = function(e){
|
||||
if(dragging){
|
||||
var dx = (e.pageX - origin_x);
|
||||
var dy = (e.pageY - origin_y);
|
||||
|
||||
if(Math.abs(dx) >= Math.abs(dy)){
|
||||
scale_div.style.width = Math.round(Math.max(20, cx+dx*2)) + "px";
|
||||
scale_div.style.height = Math.round(Math.max(20, cx+dx*2) / aspect_ratio ) + "px";
|
||||
} else {
|
||||
scale_div.style.height = Math.round(Math.max(20, cy+dy*2)) + "px";
|
||||
scale_div.style.width = Math.round(aspect_ratio * Math.max(20, cy+dy*2)) + "px";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
document.addEventListener('mousemove', resizeevent);
|
||||
|
||||
// scales the stimulus
|
||||
var scale_factor;
|
||||
var final_height_px, final_width_px;
|
||||
function scale() {
|
||||
final_width_px = scale_div.offsetWidth;
|
||||
//final_height_px = scale_div.offsetHeight;
|
||||
|
||||
var pixels_unit_screen = final_width_px / trial.item_width;
|
||||
|
||||
scale_factor = pixels_unit_screen / trial.pixels_per_unit;
|
||||
document.getElementById("jspsych-content").style.transform = "scale(" + scale_factor + ")";
|
||||
};
|
||||
|
||||
|
||||
// function to end trial
|
||||
function end_trial() {
|
||||
|
||||
// clear document event listeners
|
||||
document.removeEventListener('mousemove', resizeevent);
|
||||
document.removeEventListener('mouseup', mouseupevent);
|
||||
|
||||
// clear the screen
|
||||
display_element.innerHTML = '';
|
||||
|
||||
// finishes trial
|
||||
|
||||
var trial_data = {
|
||||
'final_height_px': final_height_px,
|
||||
'final_width_px': final_width_px,
|
||||
'scale_factor': scale_factor
|
||||
}
|
||||
|
||||
jsPsych.finishTrial(trial_data);
|
||||
}
|
||||
};
|
||||
|
||||
return plugin;
|
||||
})();
|
||||
168
PCSurvey/PCstatic/js/plugins/jspsych-same-different-html.js
Normal file
168
PCSurvey/PCstatic/js/plugins/jspsych-same-different-html.js
Normal file
@@ -0,0 +1,168 @@
|
||||
/**
|
||||
* jspsych-same-different
|
||||
* Josh de Leeuw
|
||||
*
|
||||
* plugin for showing two stimuli sequentially and getting a same / different judgment
|
||||
*
|
||||
* documentation: docs.jspsych.org
|
||||
*
|
||||
*/
|
||||
|
||||
jsPsych.plugins['same-different-html'] = (function() {
|
||||
|
||||
var plugin = {};
|
||||
|
||||
plugin.info = {
|
||||
name: 'same-different-html',
|
||||
description: '',
|
||||
parameters: {
|
||||
stimuli: {
|
||||
type: jsPsych.plugins.parameterType.HTML_STRING,
|
||||
pretty_name: 'Stimuli',
|
||||
default: undefined,
|
||||
array: true,
|
||||
description: 'The HTML content to be displayed.'
|
||||
},
|
||||
answer: {
|
||||
type: jsPsych.plugins.parameterType.SELECT,
|
||||
pretty_name: 'Answer',
|
||||
options: ['same', 'different'],
|
||||
default: 75,
|
||||
description: 'Either "same" or "different".'
|
||||
},
|
||||
same_key: {
|
||||
type: jsPsych.plugins.parameterType.KEYCODE,
|
||||
pretty_name: 'Same key',
|
||||
default: 'Q',
|
||||
description: ''
|
||||
},
|
||||
different_key: {
|
||||
type: jsPsych.plugins.parameterType.KEYCODE,
|
||||
pretty_name: 'Different key',
|
||||
default: 'P',
|
||||
description: 'The key that subjects should press to indicate that the two stimuli are the same.'
|
||||
},
|
||||
first_stim_duration: {
|
||||
type: jsPsych.plugins.parameterType.INT,
|
||||
pretty_name: 'First stimulus duration',
|
||||
default: 1000,
|
||||
description: 'How long to show the first stimulus for in milliseconds.'
|
||||
},
|
||||
gap_duration: {
|
||||
type: jsPsych.plugins.parameterType.INT,
|
||||
pretty_name: 'Gap duration',
|
||||
default: 500,
|
||||
description: 'How long to show a blank screen in between the two stimuli.'
|
||||
},
|
||||
second_stim_duration: {
|
||||
type: jsPsych.plugins.parameterType.INT,
|
||||
pretty_name: 'Second stimulus duration',
|
||||
default: 1000,
|
||||
description: 'How long to show the second stimulus for in milliseconds.'
|
||||
},
|
||||
prompt: {
|
||||
type: jsPsych.plugins.parameterType.STRING,
|
||||
pretty_name: 'Prompt',
|
||||
default: null,
|
||||
description: 'Any content here will be displayed below the stimulus.'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
plugin.trial = function(display_element, trial) {
|
||||
|
||||
display_element.innerHTML = '<div class="jspsych-same-different-stimulus">'+trial.stimuli[0]+'</div>';
|
||||
|
||||
var first_stim_info;
|
||||
if (trial.first_stim_duration > 0) {
|
||||
jsPsych.pluginAPI.setTimeout(function() {
|
||||
showBlankScreen();
|
||||
}, trial.first_stim_duration);
|
||||
} else {
|
||||
function afterKeyboardResponse(info) {
|
||||
first_stim_info = info;
|
||||
showBlankScreen();
|
||||
}
|
||||
jsPsych.pluginAPI.getKeyboardResponse({
|
||||
callback_function: afterKeyboardResponse,
|
||||
valid_responses: trial.advance_key,
|
||||
rt_method: 'performance',
|
||||
persist: false,
|
||||
allow_held_key: false
|
||||
});
|
||||
}
|
||||
|
||||
function showBlankScreen() {
|
||||
display_element.innerHTML = '';
|
||||
|
||||
jsPsych.pluginAPI.setTimeout(function() {
|
||||
showSecondStim();
|
||||
}, trial.gap_duration);
|
||||
}
|
||||
|
||||
function showSecondStim() {
|
||||
|
||||
var html = '<div class="jspsych-same-different-stimulus">'+trial.stimuli[1]+'</div>';
|
||||
//show prompt here
|
||||
if (trial.prompt !== null) {
|
||||
html += trial.prompt;
|
||||
}
|
||||
display_element.innerHTML = html;
|
||||
|
||||
if (trial.second_stim_duration > 0) {
|
||||
jsPsych.pluginAPI.setTimeout(function() {
|
||||
display_element.querySelector('.jspsych-same-different-stimulus').style.visibility = 'hidden';
|
||||
}, trial.second_stim_duration);
|
||||
}
|
||||
|
||||
|
||||
|
||||
var after_response = function(info) {
|
||||
|
||||
// kill any remaining setTimeout handlers
|
||||
jsPsych.pluginAPI.clearAllTimeouts();
|
||||
|
||||
var correct = false;
|
||||
|
||||
var skey = typeof trial.same_key == 'string' ? jsPsych.pluginAPI.convertKeyCharacterToKeyCode(trial.same_key) : trial.same_key;
|
||||
var dkey = typeof trial.different_key == 'string' ? jsPsych.pluginAPI.convertKeyCharacterToKeyCode(trial.different_key) : trial.different_key;
|
||||
|
||||
if (info.key == skey && trial.answer == 'same') {
|
||||
correct = true;
|
||||
}
|
||||
|
||||
if (info.key == dkey && trial.answer == 'different') {
|
||||
correct = true;
|
||||
}
|
||||
|
||||
var trial_data = {
|
||||
"rt": info.rt,
|
||||
"answer": trial.answer,
|
||||
"correct": correct,
|
||||
"stimulus": JSON.stringify([trial.stimuli[0], trial.stimuli[1]]),
|
||||
"key_press": info.key
|
||||
};
|
||||
if (first_stim_info) {
|
||||
trial_data["rt_stim1"] = first_stim_info.rt;
|
||||
trial_data["key_press_stim1"] = first_stim_info.key;
|
||||
}
|
||||
|
||||
display_element.innerHTML = '';
|
||||
|
||||
jsPsych.finishTrial(trial_data);
|
||||
}
|
||||
|
||||
jsPsych.pluginAPI.getKeyboardResponse({
|
||||
callback_function: after_response,
|
||||
valid_responses: [trial.same_key, trial.different_key],
|
||||
rt_method: 'performance',
|
||||
persist: false,
|
||||
allow_held_key: false
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
return plugin;
|
||||
})();
|
||||
169
PCSurvey/PCstatic/js/plugins/jspsych-same-different-image.js
Normal file
169
PCSurvey/PCstatic/js/plugins/jspsych-same-different-image.js
Normal file
@@ -0,0 +1,169 @@
|
||||
/**
|
||||
* jspsych-same-different
|
||||
* Josh de Leeuw
|
||||
*
|
||||
* plugin for showing two stimuli sequentially and getting a same / different judgment
|
||||
*
|
||||
* documentation: docs.jspsych.org
|
||||
*
|
||||
*/
|
||||
|
||||
jsPsych.plugins['same-different-image'] = (function() {
|
||||
|
||||
var plugin = {};
|
||||
|
||||
jsPsych.pluginAPI.registerPreload('same-different-image', 'stimuli', 'image')
|
||||
|
||||
plugin.info = {
|
||||
name: 'same-different-image',
|
||||
description: '',
|
||||
parameters: {
|
||||
stimuli: {
|
||||
type: jsPsych.plugins.parameterType.IMAGE,
|
||||
pretty_name: 'Stimuli',
|
||||
default: undefined,
|
||||
array: true,
|
||||
description: 'The images to be displayed.'
|
||||
},
|
||||
answer: {
|
||||
type: jsPsych.plugins.parameterType.SELECT,
|
||||
pretty_name: 'Answer',
|
||||
options: ['same', 'different'],
|
||||
default: 75,
|
||||
description: 'Either "same" or "different".'
|
||||
},
|
||||
same_key: {
|
||||
type: jsPsych.plugins.parameterType.KEYCODE,
|
||||
pretty_name: 'Same key',
|
||||
default: 'Q',
|
||||
description: ''
|
||||
},
|
||||
different_key: {
|
||||
type: jsPsych.plugins.parameterType.KEYCODE,
|
||||
pretty_name: 'Different key',
|
||||
default: 'P',
|
||||
description: 'The key that subjects should press to indicate that the two stimuli are the same.'
|
||||
},
|
||||
first_stim_duration: {
|
||||
type: jsPsych.plugins.parameterType.INT,
|
||||
pretty_name: 'First stimulus duration',
|
||||
default: 1000,
|
||||
description: 'How long to show the first stimulus for in milliseconds.'
|
||||
},
|
||||
gap_duration: {
|
||||
type: jsPsych.plugins.parameterType.INT,
|
||||
pretty_name: 'Gap duration',
|
||||
default: 500,
|
||||
description: 'How long to show a blank screen in between the two stimuli.'
|
||||
},
|
||||
second_stim_duration: {
|
||||
type: jsPsych.plugins.parameterType.INT,
|
||||
pretty_name: 'Second stimulus duration',
|
||||
default: 1000,
|
||||
description: 'How long to show the second stimulus for in milliseconds.'
|
||||
},
|
||||
prompt: {
|
||||
type: jsPsych.plugins.parameterType.STRING,
|
||||
pretty_name: 'Prompt',
|
||||
default: null,
|
||||
description: 'Any content here will be displayed below the stimulus.'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
plugin.trial = function(display_element, trial) {
|
||||
|
||||
display_element.innerHTML = '<img class="jspsych-same-different-stimulus" src="'+trial.stimuli[0]+'"></img>';
|
||||
|
||||
var first_stim_info;
|
||||
if (trial.first_stim_duration > 0) {
|
||||
jsPsych.pluginAPI.setTimeout(function() {
|
||||
showBlankScreen();
|
||||
}, trial.first_stim_duration);
|
||||
} else {
|
||||
function afterKeyboardResponse(info) {
|
||||
first_stim_info = info;
|
||||
showBlankScreen();
|
||||
}
|
||||
jsPsych.pluginAPI.getKeyboardResponse({
|
||||
callback_function: afterKeyboardResponse,
|
||||
valid_responses: trial.advance_key,
|
||||
rt_method: 'performance',
|
||||
persist: false,
|
||||
allow_held_key: false
|
||||
});
|
||||
}
|
||||
|
||||
function showBlankScreen() {
|
||||
display_element.innerHTML = '';
|
||||
|
||||
jsPsych.pluginAPI.setTimeout(function() {
|
||||
showSecondStim();
|
||||
}, trial.gap_duration);
|
||||
}
|
||||
|
||||
function showSecondStim() {
|
||||
|
||||
var html = '<img class="jspsych-same-different-stimulus" src="'+trial.stimuli[1]+'"></img>';
|
||||
//show prompt
|
||||
if (trial.prompt !== null) {
|
||||
html += trial.prompt;
|
||||
}
|
||||
|
||||
display_element.innerHTML = html;
|
||||
|
||||
if (trial.second_stim_duration > 0) {
|
||||
jsPsych.pluginAPI.setTimeout(function() {
|
||||
display_element.querySelector('.jspsych-same-different-stimulus').style.visibility = 'hidden';
|
||||
}, trial.second_stim_duration);
|
||||
}
|
||||
|
||||
var after_response = function(info) {
|
||||
|
||||
// kill any remaining setTimeout handlers
|
||||
jsPsych.pluginAPI.clearAllTimeouts();
|
||||
|
||||
var correct = false;
|
||||
|
||||
var skey = typeof trial.same_key == 'string' ? jsPsych.pluginAPI.convertKeyCharacterToKeyCode(trial.same_key) : trial.same_key;
|
||||
var dkey = typeof trial.different_key == 'string' ? jsPsych.pluginAPI.convertKeyCharacterToKeyCode(trial.different_key) : trial.different_key;
|
||||
|
||||
if (info.key == skey && trial.answer == 'same') {
|
||||
correct = true;
|
||||
}
|
||||
|
||||
if (info.key == dkey && trial.answer == 'different') {
|
||||
correct = true;
|
||||
}
|
||||
|
||||
var trial_data = {
|
||||
"rt": info.rt,
|
||||
"answer": trial.answer,
|
||||
"correct": correct,
|
||||
"stimulus": JSON.stringify([trial.stimuli[0], trial.stimuli[1]]),
|
||||
"key_press": info.key
|
||||
};
|
||||
if (first_stim_info) {
|
||||
trial_data["rt_stim1"] = first_stim_info.rt;
|
||||
trial_data["key_press_stim1"] = first_stim_info.key;
|
||||
}
|
||||
|
||||
display_element.innerHTML = '';
|
||||
|
||||
jsPsych.finishTrial(trial_data);
|
||||
}
|
||||
|
||||
jsPsych.pluginAPI.getKeyboardResponse({
|
||||
callback_function: after_response,
|
||||
valid_responses: [trial.same_key, trial.different_key],
|
||||
rt_method: 'performance',
|
||||
persist: false,
|
||||
allow_held_key: false
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
return plugin;
|
||||
})();
|
||||
@@ -0,0 +1,213 @@
|
||||
/**
|
||||
* jspsych-serial-reaction-time
|
||||
* Josh de Leeuw
|
||||
*
|
||||
* plugin for running a serial reaction time task
|
||||
*
|
||||
* documentation: docs.jspsych.org
|
||||
*
|
||||
**/
|
||||
|
||||
jsPsych.plugins["serial-reaction-time-mouse"] = (function() {
|
||||
|
||||
var plugin = {};
|
||||
|
||||
plugin.info = {
|
||||
name: 'serial-reaction-time-mouse',
|
||||
description: '',
|
||||
parameters: {
|
||||
target: {
|
||||
type: jsPsych.plugins.parameterType.INT,
|
||||
pretty_name: 'Target',
|
||||
array: true,
|
||||
default: undefined,
|
||||
description: 'The location of the target. The array should be the [row, column] of the target.'
|
||||
},
|
||||
grid: {
|
||||
type: jsPsych.plugins.parameterType.BOOL,
|
||||
pretty_name: 'Grid',
|
||||
array: true,
|
||||
default: [[1,1,1,1]],
|
||||
description: 'This array represents the grid of boxes shown on the screen.'
|
||||
},
|
||||
grid_square_size: {
|
||||
type: jsPsych.plugins.parameterType.INT,
|
||||
pretty_name: 'Grid square size',
|
||||
default: 100,
|
||||
description: 'The width and height in pixels of each square in the grid.'
|
||||
},
|
||||
target_color: {
|
||||
type: jsPsych.plugins.parameterType.STRING,
|
||||
pretty_name: 'Target color',
|
||||
default: "#999",
|
||||
description: 'The color of the target square.'
|
||||
},
|
||||
response_ends_trial: {
|
||||
type: jsPsych.plugins.parameterType.BOOL,
|
||||
pretty_name: 'Response ends trial',
|
||||
default: true,
|
||||
description: 'If true, the trial ends after a key press.'
|
||||
},
|
||||
pre_target_duration: {
|
||||
type: jsPsych.plugins.parameterType.INT,
|
||||
pretty_name: 'Pre-target duration',
|
||||
default: 0,
|
||||
description: 'The number of milliseconds to display the grid before the target changes color.'
|
||||
},
|
||||
trial_duration: {
|
||||
type: jsPsych.plugins.parameterType.INT,
|
||||
pretty_name: 'Trial duration',
|
||||
default: null,
|
||||
description: 'How long to show the trial'
|
||||
},
|
||||
fade_duration: {
|
||||
type: jsPsych.plugins.parameterType.INT,
|
||||
pretty_name: 'Fade duration',
|
||||
default: null,
|
||||
description: 'If a positive number, the target will progressively change color at the start of the trial, with the transition lasting this many milliseconds.'
|
||||
},
|
||||
allow_nontarget_responses: {
|
||||
type: jsPsych.plugins.parameterType.BOOL,
|
||||
pretty_name: 'Allow nontarget response',
|
||||
default: false,
|
||||
description: 'If true, then user can make nontarget response.'
|
||||
},
|
||||
prompt: {
|
||||
type: jsPsych.plugins.parameterType.STRING,
|
||||
pretty_name: 'Prompt',
|
||||
default: null,
|
||||
description: 'Any content here will be displayed below the stimulus'
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
plugin.trial = function(display_element, trial) {
|
||||
|
||||
var startTime = -1;
|
||||
var response = {
|
||||
rt: null,
|
||||
row: null,
|
||||
column: null
|
||||
}
|
||||
|
||||
// display stimulus
|
||||
var stimulus = this.stimulus(trial.grid, trial.grid_square_size);
|
||||
display_element.innerHTML = stimulus;
|
||||
|
||||
|
||||
if(trial.pre_target_duration <= 0){
|
||||
showTarget();
|
||||
} else {
|
||||
jsPsych.pluginAPI.setTimeout(function(){
|
||||
showTarget();
|
||||
}, trial.pre_target_duration);
|
||||
}
|
||||
|
||||
//show prompt if there is one
|
||||
if (trial.prompt !== null) {
|
||||
display_element.innerHTML += trial.prompt;
|
||||
}
|
||||
|
||||
function showTarget(){
|
||||
var resp_targets;
|
||||
if(!trial.allow_nontarget_responses){
|
||||
resp_targets = [display_element.querySelector('#jspsych-serial-reaction-time-stimulus-cell-'+trial.target[0]+'-'+trial.target[1])]
|
||||
} else {
|
||||
resp_targets = display_element.querySelectorAll('.jspsych-serial-reaction-time-stimulus-cell');
|
||||
}
|
||||
for(var i=0; i<resp_targets.length; i++){
|
||||
resp_targets[i].addEventListener('mousedown', function(e){
|
||||
if(startTime == -1){
|
||||
return;
|
||||
} else {
|
||||
var info = {}
|
||||
info.row = e.currentTarget.getAttribute('data-row');
|
||||
info.column = e.currentTarget.getAttribute('data-column');
|
||||
info.rt = performance.now() - startTime;
|
||||
after_response(info);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
startTime = performance.now();
|
||||
|
||||
if(trial.fade_duration == null){
|
||||
display_element.querySelector('#jspsych-serial-reaction-time-stimulus-cell-'+trial.target[0]+'-'+trial.target[1]).style.backgroundColor = trial.target_color;
|
||||
} else {
|
||||
display_element.querySelector('#jspsych-serial-reaction-time-stimulus-cell-'+trial.target[0]+'-'+trial.target[1]).style.transition = "background-color "+trial.fade_duration;
|
||||
display_element.querySelector('#jspsych-serial-reaction-time-stimulus-cell-'+trial.target[0]+'-'+trial.target[1]).style.backgroundColor = trial.target_color;
|
||||
}
|
||||
|
||||
if(trial.trial_duration !== null){
|
||||
jsPsych.pluginAPI.setTimeout(endTrial, trial.trial_duration);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function endTrial() {
|
||||
|
||||
// kill any remaining setTimeout handlers
|
||||
jsPsych.pluginAPI.clearAllTimeouts();
|
||||
|
||||
// gather the data to store for the trial
|
||||
var trial_data = {
|
||||
"rt": response.rt,
|
||||
"grid": JSON.stringify(trial.grid),
|
||||
"target": JSON.stringify(trial.target),
|
||||
"response_row": response.row,
|
||||
"response_column": response.column,
|
||||
"correct": response.row == trial.target[0] && response.column == trial.target[1]
|
||||
};
|
||||
|
||||
// clear the display
|
||||
display_element.innerHTML = '';
|
||||
|
||||
// move on to the next trial
|
||||
jsPsych.finishTrial(trial_data);
|
||||
|
||||
};
|
||||
|
||||
// function to handle responses by the subject
|
||||
function after_response(info) {
|
||||
|
||||
// only record first response
|
||||
response = response.rt == null ? info : response;
|
||||
|
||||
if (trial.response_ends_trial) {
|
||||
endTrial();
|
||||
}
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
plugin.stimulus = function(grid, square_size, target, target_color, labels) {
|
||||
var stimulus = "<div id='jspsych-serial-reaction-time-stimulus' style='margin:auto; display: table; table-layout: fixed; border-spacing:"+square_size/4+"px'>";
|
||||
for(var i=0; i<grid.length; i++){
|
||||
stimulus += "<div class='jspsych-serial-reaction-time-stimulus-row' style='display:table-row;'>";
|
||||
for(var j=0; j<grid[i].length; j++){
|
||||
var classname = 'jspsych-serial-reaction-time-stimulus-cell';
|
||||
|
||||
stimulus += "<div class='"+classname+"' id='jspsych-serial-reaction-time-stimulus-cell-"+i+"-"+j+"' "+
|
||||
"data-row="+i+" data-column="+j+" "+
|
||||
"style='width:"+square_size+"px; height:"+square_size+"px; display:table-cell; vertical-align:middle; text-align: center; cursor: pointer; font-size:"+square_size/2+"px;";
|
||||
if(grid[i][j] == 1){
|
||||
stimulus += "border: 2px solid black;"
|
||||
}
|
||||
if(typeof target !== 'undefined' && target[0] == i && target[1] == j){
|
||||
stimulus += "background-color: "+target_color+";"
|
||||
}
|
||||
stimulus += "'>";
|
||||
if(typeof labels !=='undefined' && labels[i][j] !== false){
|
||||
stimulus += labels[i][j]
|
||||
}
|
||||
stimulus += "</div>";
|
||||
}
|
||||
stimulus += "</div>";
|
||||
}
|
||||
stimulus += "</div>";
|
||||
|
||||
return stimulus
|
||||
}
|
||||
|
||||
return plugin;
|
||||
})();
|
||||
247
PCSurvey/PCstatic/js/plugins/jspsych-serial-reaction-time.js
Normal file
247
PCSurvey/PCstatic/js/plugins/jspsych-serial-reaction-time.js
Normal file
@@ -0,0 +1,247 @@
|
||||
/**
|
||||
* jspsych-serial-reaction-time
|
||||
* Josh de Leeuw
|
||||
*
|
||||
* plugin for running a serial reaction time task
|
||||
*
|
||||
* documentation: docs.jspsych.org
|
||||
*
|
||||
**/
|
||||
|
||||
jsPsych.plugins["serial-reaction-time"] = (function() {
|
||||
|
||||
var plugin = {};
|
||||
|
||||
plugin.info = {
|
||||
name: 'serial-reaction-time',
|
||||
description: '',
|
||||
parameters: {
|
||||
grid: {
|
||||
type: jsPsych.plugins.parameterType.BOOL,
|
||||
pretty_name: 'Grid',
|
||||
array: true,
|
||||
default: [[1,1,1,1]],
|
||||
description: 'This array represents the grid of boxes shown on the screen.'
|
||||
},
|
||||
target: {
|
||||
type: jsPsych.plugins.parameterType.INT,
|
||||
pretty_name: 'Target',
|
||||
array: true,
|
||||
default: undefined,
|
||||
description: 'The location of the target. The array should be the [row, column] of the target.'
|
||||
},
|
||||
choices: {
|
||||
type: jsPsych.plugins.parameterType.KEYCODE,
|
||||
pretty_name: 'Choices',
|
||||
array: true,
|
||||
default: [['3','5','7','9']],
|
||||
description: ' Each entry in this array is the key that should be pressed for that corresponding location in the grid.'
|
||||
},
|
||||
grid_square_size: {
|
||||
type: jsPsych.plugins.parameterType.INT,
|
||||
pretty_name: 'Grid square size',
|
||||
default: 100,
|
||||
description: 'The width and height in pixels of each square in the grid.'
|
||||
},
|
||||
target_color: {
|
||||
type: jsPsych.plugins.parameterType.STRING,
|
||||
pretty_name: 'Target color',
|
||||
default: "#999",
|
||||
description: 'The color of the target square.'
|
||||
},
|
||||
response_ends_trial: {
|
||||
type: jsPsych.plugins.parameterType.BOOL,
|
||||
pretty_name: 'Response ends trial',
|
||||
default: true,
|
||||
description: 'If true, trial ends when user makes a response.'
|
||||
},
|
||||
pre_target_duration: {
|
||||
type: jsPsych.plugins.parameterType.INT,
|
||||
pretty_name: 'Pre-target duration',
|
||||
default: 0,
|
||||
description: 'The number of milliseconds to display the grid before the target changes color.'
|
||||
},
|
||||
trial_duration: {
|
||||
type: jsPsych.plugins.parameterType.INT,
|
||||
pretty_name: 'Trial duration',
|
||||
default: null,
|
||||
description: 'How long to show the trial.'
|
||||
},
|
||||
show_response_feedback: {
|
||||
type: jsPsych.plugins.parameterType.BOOL,
|
||||
pretty_name: 'Show response feedback',
|
||||
default: false,
|
||||
description: 'If true, show feedback indicating where the user responded and whether it was correct.'
|
||||
},
|
||||
feedback_duration: {
|
||||
type: jsPsych.plugins.parameterType.INT,
|
||||
pretty_name: 'Feedback duration',
|
||||
default: 200,
|
||||
description: 'The length of time in milliseconds to show the feedback.'
|
||||
},
|
||||
fade_duration: {
|
||||
type: jsPsych.plugins.parameterType.INT,
|
||||
pretty_name: 'Fade duration',
|
||||
default: null,
|
||||
description: 'If a positive number, the target will progressively change color at the start of the trial, with the transition lasting this many milliseconds.'
|
||||
},
|
||||
prompt: {
|
||||
type: jsPsych.plugins.parameterType.STRING,
|
||||
pretty_name: 'Prompt',
|
||||
default: null,
|
||||
no_function: false,
|
||||
description: ' Any content here will be displayed below the stimulus.'
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
plugin.trial = function(display_element, trial) {
|
||||
|
||||
// create a flattened version of the choices array
|
||||
var flat_choices = jsPsych.utils.flatten(trial.choices);
|
||||
while(flat_choices.indexOf('') > -1){
|
||||
flat_choices.splice(flat_choices.indexOf(''),1);
|
||||
}
|
||||
|
||||
// display stimulus
|
||||
var stimulus = this.stimulus(trial.grid, trial.grid_square_size);
|
||||
display_element.innerHTML = stimulus;
|
||||
|
||||
if(trial.pre_target_duration <= 0){
|
||||
showTarget();
|
||||
} else {
|
||||
jsPsych.pluginAPI.setTimeout(function(){
|
||||
showTarget();
|
||||
}, trial.pre_target_duration);
|
||||
}
|
||||
|
||||
//show prompt if there is one
|
||||
if (trial.prompt !== null) {
|
||||
display_element.innerHTML += trial.prompt;
|
||||
}
|
||||
|
||||
var keyboardListener = {};
|
||||
|
||||
var response = {
|
||||
rt: null,
|
||||
key: false,
|
||||
correct: false
|
||||
}
|
||||
|
||||
function showTarget(){
|
||||
if(trial.fade_duration == null){
|
||||
display_element.querySelector('#jspsych-serial-reaction-time-stimulus-cell-'+trial.target[0]+'-'+trial.target[1]).style.backgroundColor = trial.target_color;
|
||||
} else {
|
||||
display_element.querySelector('#jspsych-serial-reaction-time-stimulus-cell-'+trial.target[0]+'-'+trial.target[1]).style.transition = "background-color "+trial.fade_duration;
|
||||
display_element.querySelector('#jspsych-serial-reaction-time-stimulus-cell-'+trial.target[0]+'-'+trial.target[1]).style.backgroundColor = trial.target_color;
|
||||
}
|
||||
|
||||
keyboardListener = jsPsych.pluginAPI.getKeyboardResponse({
|
||||
callback_function: after_response,
|
||||
valid_responses: flat_choices,
|
||||
allow_held_key: false
|
||||
});
|
||||
|
||||
if(trial.trial_duration > null){
|
||||
jsPsych.pluginAPI.setTimeout(showFeedback, trial.trial_duration);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function showFeedback() {
|
||||
if(response.rt == null || trial.show_response_feedback == false){
|
||||
endTrial();
|
||||
} else {
|
||||
var color = response.correct ? '#0f0' : '#f00';
|
||||
display_element.querySelector('#jspsych-serial-reaction-time-stimulus-cell-'+response.responseLoc[0]+'-'+response.responseLoc[1]).style.transition = "";
|
||||
display_element.querySelector('#jspsych-serial-reaction-time-stimulus-cell-'+response.responseLoc[0]+'-'+response.responseLoc[1]).style.backgroundColor = color;
|
||||
jsPsych.pluginAPI.setTimeout(endTrial, trial.feedback_duration);
|
||||
}
|
||||
}
|
||||
|
||||
function endTrial() {
|
||||
|
||||
// kill any remaining setTimeout handlers
|
||||
jsPsych.pluginAPI.clearAllTimeouts();
|
||||
|
||||
// kill keyboard listeners
|
||||
if (typeof keyboardListener !== 'undefined') {
|
||||
jsPsych.pluginAPI.cancelKeyboardResponse(keyboardListener);
|
||||
}
|
||||
|
||||
// gather the data to store for the trial
|
||||
var trial_data = {
|
||||
"rt": response.rt,
|
||||
"key_press": response.key,
|
||||
"correct": response.correct,
|
||||
"grid": JSON.stringify(trial.grid),
|
||||
"target": JSON.stringify(trial.target)
|
||||
};
|
||||
|
||||
// clear the display
|
||||
display_element.innerHTML = '';
|
||||
|
||||
// move on to the next trial
|
||||
jsPsych.finishTrial(trial_data);
|
||||
|
||||
};
|
||||
|
||||
// function to handle responses by the subject
|
||||
function after_response(info) {
|
||||
|
||||
// only record first response
|
||||
response = response.rt == null ? info : response;
|
||||
|
||||
// check if the response is correct
|
||||
var responseLoc = [];
|
||||
for(var i=0; i<trial.choices.length; i++){
|
||||
for(var j=0; j<trial.choices[i].length; j++){
|
||||
var t = typeof trial.choices[i][j] == 'string' ? jsPsych.pluginAPI.convertKeyCharacterToKeyCode(trial.choices[i][j]) : trial.choices[i][j];
|
||||
if(info.key == t){
|
||||
responseLoc = [i,j];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
response.responseLoc = responseLoc;
|
||||
response.correct = (JSON.stringify(responseLoc) == JSON.stringify(trial.target));
|
||||
|
||||
if (trial.response_ends_trial) {
|
||||
if (trial.show_response_feedback){
|
||||
showFeedback(response.correct);
|
||||
} else {
|
||||
endTrial();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
plugin.stimulus = function(grid, square_size, target, target_color, labels) {
|
||||
var stimulus = "<div id='jspsych-serial-reaction-time-stimulus' style='margin:auto; display: table; table-layout: fixed; border-spacing:"+square_size/4+"px'>";
|
||||
for(var i=0; i<grid.length; i++){
|
||||
stimulus += "<div class='jspsych-serial-reaction-time-stimulus-row' style='display:table-row;'>";
|
||||
for(var j=0; j<grid[i].length; j++){
|
||||
stimulus += "<div class='jspsych-serial-reaction-time-stimulus-cell' id='jspsych-serial-reaction-time-stimulus-cell-"+i+"-"+j+"' "+
|
||||
"style='width:"+square_size+"px; height:"+square_size+"px; display:table-cell; vertical-align:middle; text-align: center; font-size:"+square_size/2+"px;";
|
||||
if(grid[i][j] == 1){
|
||||
stimulus += "border: 2px solid black;"
|
||||
}
|
||||
if(typeof target !== 'undefined' && target[0] == i && target[1] == j){
|
||||
stimulus += "background-color: "+target_color+";"
|
||||
}
|
||||
stimulus += "'>";
|
||||
if(typeof labels !=='undefined' && labels[i][j] !== false){
|
||||
stimulus += labels[i][j]
|
||||
}
|
||||
stimulus += "</div>";
|
||||
}
|
||||
stimulus += "</div>";
|
||||
}
|
||||
stimulus += "</div>";
|
||||
|
||||
return stimulus
|
||||
}
|
||||
|
||||
return plugin;
|
||||
})();
|
||||
144
PCSurvey/PCstatic/js/plugins/jspsych-survey-html-form.js
Normal file
144
PCSurvey/PCstatic/js/plugins/jspsych-survey-html-form.js
Normal file
@@ -0,0 +1,144 @@
|
||||
/**
|
||||
* jspsych-survey-html-form
|
||||
* a jspsych plugin for free html forms
|
||||
*
|
||||
* Jan Simson
|
||||
*
|
||||
* documentation: docs.jspsych.org
|
||||
*
|
||||
*/
|
||||
|
||||
jsPsych.plugins['survey-html-form'] = (function() {
|
||||
|
||||
var plugin = {};
|
||||
|
||||
plugin.info = {
|
||||
name: 'survey-html-form',
|
||||
description: '',
|
||||
parameters: {
|
||||
html: {
|
||||
type: jsPsych.plugins.parameterType.HTML_STRING,
|
||||
pretty_name: 'HTML',
|
||||
default: null,
|
||||
description: 'HTML formatted string containing all the input elements to display. Every element has to have its own distinctive name attribute. The <form> tag must not be included and is generated by the plugin.'
|
||||
},
|
||||
preamble: {
|
||||
type: jsPsych.plugins.parameterType.STRING,
|
||||
pretty_name: 'Preamble',
|
||||
default: null,
|
||||
description: 'HTML formatted string to display at the top of the page above all the questions.'
|
||||
},
|
||||
button_label: {
|
||||
type: jsPsych.plugins.parameterType.STRING,
|
||||
pretty_name: 'Button label',
|
||||
default: 'Continue',
|
||||
description: 'The text that appears on the button to finish the trial.'
|
||||
},
|
||||
dataAsArray: {
|
||||
type: jsPsych.plugins.parameterType.BOOLEAN,
|
||||
pretty_name: 'Data As Array',
|
||||
default: false,
|
||||
description: 'Retrieve the data as an array e.g. [{name: "INPUT_NAME", value: "INPUT_VALUE"}, ...] instead of an object e.g. {INPUT_NAME: INPUT_VALUE, ...}.'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
plugin.trial = function(display_element, trial) {
|
||||
|
||||
var html = '';
|
||||
// show preamble text
|
||||
if(trial.preamble !== null){
|
||||
html += '<div id="jspsych-survey-html-form-preamble" class="jspsych-survey-html-form-preamble">'+trial.preamble+'</div>';
|
||||
}
|
||||
// start form
|
||||
html += '<form id="jspsych-survey-html-form">'
|
||||
|
||||
// add form HTML / input elements
|
||||
html += trial.html;
|
||||
|
||||
// add submit button
|
||||
html += '<input type="submit" id="jspsych-survey-html-form-next" class="jspsych-btn jspsych-survey-html-form" value="'+trial.button_label+'"></input>';
|
||||
|
||||
html += '</form>'
|
||||
display_element.innerHTML = html;
|
||||
|
||||
display_element.querySelector('#jspsych-survey-html-form').addEventListener('submit', function(event) {
|
||||
// don't submit form
|
||||
event.preventDefault();
|
||||
|
||||
// measure response time
|
||||
var endTime = performance.now();
|
||||
var response_time = endTime - startTime;
|
||||
|
||||
var question_data = serializeArray(this);
|
||||
|
||||
if (!trial.dataAsArray) {
|
||||
question_data = objectifyForm(question_data);
|
||||
}
|
||||
|
||||
// save data
|
||||
var trialdata = {
|
||||
"rt": response_time,
|
||||
"responses": JSON.stringify(question_data)
|
||||
};
|
||||
|
||||
display_element.innerHTML = '';
|
||||
|
||||
// next trial
|
||||
jsPsych.finishTrial(trialdata);
|
||||
});
|
||||
|
||||
var startTime = performance.now();
|
||||
};
|
||||
|
||||
/*!
|
||||
* Serialize all form data into an array
|
||||
* (c) 2018 Chris Ferdinandi, MIT License, https://gomakethings.com
|
||||
* @param {Node} form The form to serialize
|
||||
* @return {String} The serialized form data
|
||||
*/
|
||||
var serializeArray = function (form) {
|
||||
// Setup our serialized data
|
||||
var serialized = [];
|
||||
|
||||
// Loop through each field in the form
|
||||
for (var i = 0; i < form.elements.length; i++) {
|
||||
var field = form.elements[i];
|
||||
|
||||
// Don't serialize fields without a name, submits, buttons, file and reset inputs, and disabled fields
|
||||
if (!field.name || field.disabled || field.type === 'file' || field.type === 'reset' || field.type === 'submit' || field.type === 'button') continue;
|
||||
|
||||
// If a multi-select, get all selections
|
||||
if (field.type === 'select-multiple') {
|
||||
for (var n = 0; n < field.options.length; n++) {
|
||||
if (!field.options[n].selected) continue;
|
||||
serialized.push({
|
||||
name: field.name,
|
||||
value: field.options[n].value
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Convert field data to a query string
|
||||
else if ((field.type !== 'checkbox' && field.type !== 'radio') || field.checked) {
|
||||
serialized.push({
|
||||
name: field.name,
|
||||
value: field.value
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return serialized;
|
||||
};
|
||||
|
||||
// from https://stackoverflow.com/questions/1184624/convert-form-data-to-javascript-object-with-jquery
|
||||
function objectifyForm(formArray) {//serialize data function
|
||||
var returnArray = {};
|
||||
for (var i = 0; i < formArray.length; i++){
|
||||
returnArray[formArray[i]['name']] = formArray[i]['value'];
|
||||
}
|
||||
return returnArray;
|
||||
}
|
||||
|
||||
return plugin;
|
||||
})();
|
||||
184
PCSurvey/PCstatic/js/plugins/jspsych-survey-likert.js
Normal file
184
PCSurvey/PCstatic/js/plugins/jspsych-survey-likert.js
Normal file
@@ -0,0 +1,184 @@
|
||||
/**
|
||||
* jspsych-survey-likert
|
||||
* a jspsych plugin for measuring items on a likert scale
|
||||
*
|
||||
* Josh de Leeuw
|
||||
*
|
||||
* documentation: docs.jspsych.org
|
||||
*
|
||||
*/
|
||||
|
||||
jsPsych.plugins['survey-likert'] = (function() {
|
||||
|
||||
var plugin = {};
|
||||
|
||||
plugin.info = {
|
||||
name: 'survey-likert',
|
||||
description: '',
|
||||
parameters: {
|
||||
questions: {
|
||||
type: jsPsych.plugins.parameterType.COMPLEX,
|
||||
array: true,
|
||||
pretty_name: 'Questions',
|
||||
nested: {
|
||||
prompt: {
|
||||
type: jsPsych.plugins.parameterType.STRING,
|
||||
pretty_name: 'Prompt',
|
||||
default: undefined,
|
||||
description: 'Questions that are associated with the slider.'
|
||||
},
|
||||
labels: {
|
||||
type: jsPsych.plugins.parameterType.STRING,
|
||||
array: true,
|
||||
pretty_name: 'Labels',
|
||||
default: undefined,
|
||||
description: 'Labels to display for individual question.'
|
||||
},
|
||||
required: {
|
||||
type: jsPsych.plugins.parameterType.BOOL,
|
||||
pretty_name: 'Required',
|
||||
default: false,
|
||||
description: 'Makes answering the question required.'
|
||||
},
|
||||
name: {
|
||||
type: jsPsych.plugins.parameterType.STRING,
|
||||
pretty_name: 'Question Name',
|
||||
default: '',
|
||||
description: 'Controls the name of data values associated with this question'
|
||||
}
|
||||
}
|
||||
},
|
||||
randomize_question_order: {
|
||||
type: jsPsych.plugins.parameterType.BOOL,
|
||||
pretty_name: 'Randomize Question Order',
|
||||
default: false,
|
||||
description: 'If true, the order of the questions will be randomized'
|
||||
},
|
||||
preamble: {
|
||||
type: jsPsych.plugins.parameterType.STRING,
|
||||
pretty_name: 'Preamble',
|
||||
default: null,
|
||||
description: 'String to display at top of the page.'
|
||||
},
|
||||
scale_width: {
|
||||
type: jsPsych.plugins.parameterType.INT,
|
||||
pretty_name: 'Scale width',
|
||||
default: null,
|
||||
description: 'Width of the likert scales in pixels.'
|
||||
},
|
||||
button_label: {
|
||||
type: jsPsych.plugins.parameterType.STRING,
|
||||
pretty_name: 'Button label',
|
||||
default: 'Continue',
|
||||
description: 'Label of the button.'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
plugin.trial = function(display_element, trial) {
|
||||
|
||||
if(trial.scale_width !== null){
|
||||
var w = trial.scale_width + 'px';
|
||||
} else {
|
||||
var w = '100%';
|
||||
}
|
||||
|
||||
var html = "";
|
||||
// inject CSS for trial
|
||||
html += '<style id="jspsych-survey-likert-css">';
|
||||
html += ".jspsych-survey-likert-statement { display:block; font-size: 16px; padding-top: 40px; margin-bottom:10px; }"+
|
||||
".jspsych-survey-likert-opts { list-style:none; width:"+w+"; margin:auto; padding:0 0 35px; display:block; font-size: 14px; line-height:1.1em; }"+
|
||||
".jspsych-survey-likert-opt-label { line-height: 1.1em; color: #444; }"+
|
||||
".jspsych-survey-likert-opts:before { content: ''; position:relative; top:11px; /*left:9.5%;*/ display:block; background-color:#efefef; height:4px; width:100%; }"+
|
||||
".jspsych-survey-likert-opts:last-of-type { border-bottom: 0; }"+
|
||||
".jspsych-survey-likert-opts li { display:inline-block; /*width:19%;*/ text-align:center; vertical-align: top; }"+
|
||||
".jspsych-survey-likert-opts li input[type=radio] { display:block; position:relative; top:0; left:50%; margin-left:-6px; }"
|
||||
html += '</style>';
|
||||
|
||||
// show preamble text
|
||||
if(trial.preamble !== null){
|
||||
html += '<div id="jspsych-survey-likert-preamble" class="jspsych-survey-likert-preamble">'+trial.preamble+'</div>';
|
||||
}
|
||||
html += '<form id="jspsych-survey-likert-form">';
|
||||
|
||||
// add likert scale questions ///
|
||||
// generate question order. this is randomized here as opposed to randomizing the order of trial.questions
|
||||
// so that the data are always associated with the same question regardless of order
|
||||
var question_order = [];
|
||||
for(var i=0; i<trial.questions.length; i++){
|
||||
question_order.push(i);
|
||||
}
|
||||
if(trial.randomize_question_order){
|
||||
question_order = jsPsych.randomization.shuffle(question_order);
|
||||
}
|
||||
|
||||
for (var i = 0; i < trial.questions.length; i++) {
|
||||
var question = trial.questions[question_order[i]];
|
||||
// add question
|
||||
html += '<label class="jspsych-survey-likert-statement">' + question.prompt + '</label>';
|
||||
// add options
|
||||
var width = 100 / question.labels.length;
|
||||
var options_string = '<ul class="jspsych-survey-likert-opts" data-name="'+question.name+'" data-radio-group="Q' + question_order[i] + '">';
|
||||
for (var j = 0; j < question.labels.length; j++) {
|
||||
options_string += '<li style="width:' + width + '%"><input type="radio" name="Q' + question_order[i] + '" value="' + j + '"';
|
||||
if(question.required){
|
||||
options_string += ' required';
|
||||
}
|
||||
options_string += '><label class="jspsych-survey-likert-opt-label">' + question.labels[j] + '</label></li>';
|
||||
}
|
||||
options_string += '</ul>';
|
||||
html += options_string;
|
||||
}
|
||||
|
||||
// add submit button
|
||||
html += '<input type="submit" id="jspsych-survey-likert-next" class="jspsych-survey-likert jspsych-btn" value="'+trial.button_label+'"></input>';
|
||||
|
||||
html += '</form>'
|
||||
|
||||
display_element.innerHTML = html;
|
||||
|
||||
display_element.querySelector('#jspsych-survey-likert-form').addEventListener('submit', function(e){
|
||||
e.preventDefault();
|
||||
// measure response time
|
||||
var endTime = performance.now();
|
||||
var response_time = endTime - startTime;
|
||||
|
||||
// create object to hold responses
|
||||
var question_data = {};
|
||||
var matches = display_element.querySelectorAll('#jspsych-survey-likert-form .jspsych-survey-likert-opts');
|
||||
for(var index = 0; index < matches.length; index++){
|
||||
var id = matches[index].dataset['radioGroup'];
|
||||
var el = display_element.querySelector('input[name="' + id + '"]:checked');
|
||||
if (el === null) {
|
||||
var response = "";
|
||||
} else {
|
||||
var response = parseInt(el.value);
|
||||
}
|
||||
var obje = {};
|
||||
if(matches[index].attributes['data-name'].value !== ''){
|
||||
var name = matches[index].attributes['data-name'].value;
|
||||
} else {
|
||||
var name = id;
|
||||
}
|
||||
obje[name] = response;
|
||||
Object.assign(question_data, obje);
|
||||
}
|
||||
|
||||
// save data
|
||||
var trial_data = {
|
||||
"rt": response_time,
|
||||
"responses": JSON.stringify(question_data),
|
||||
"question_order": JSON.stringify(question_order)
|
||||
};
|
||||
|
||||
display_element.innerHTML = '';
|
||||
|
||||
// next trial
|
||||
jsPsych.finishTrial(trial_data);
|
||||
});
|
||||
|
||||
var startTime = performance.now();
|
||||
};
|
||||
|
||||
return plugin;
|
||||
})();
|
||||
199
PCSurvey/PCstatic/js/plugins/jspsych-survey-multi-choice.js
Normal file
199
PCSurvey/PCstatic/js/plugins/jspsych-survey-multi-choice.js
Normal file
@@ -0,0 +1,199 @@
|
||||
/**
|
||||
* jspsych-survey-multi-choice
|
||||
* a jspsych plugin for multiple choice survey questions
|
||||
*
|
||||
* Shane Martin
|
||||
*
|
||||
* documentation: docs.jspsych.org
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
jsPsych.plugins['survey-multi-choice'] = (function() {
|
||||
var plugin = {};
|
||||
|
||||
plugin.info = {
|
||||
name: 'survey-multi-choice',
|
||||
description: '',
|
||||
parameters: {
|
||||
questions: {
|
||||
type: jsPsych.plugins.parameterType.COMPLEX,
|
||||
array: true,
|
||||
pretty_name: 'Questions',
|
||||
nested: {
|
||||
prompt: {
|
||||
type: jsPsych.plugins.parameterType.STRING,
|
||||
pretty_name: 'Prompt',
|
||||
default: undefined,
|
||||
description: 'The strings that will be associated with a group of options.'
|
||||
},
|
||||
options: {
|
||||
type: jsPsych.plugins.parameterType.STRING,
|
||||
pretty_name: 'Options',
|
||||
array: true,
|
||||
default: undefined,
|
||||
description: 'Displays options for an individual question.'
|
||||
},
|
||||
required: {
|
||||
type: jsPsych.plugins.parameterType.BOOL,
|
||||
pretty_name: 'Required',
|
||||
default: false,
|
||||
description: 'Subject will be required to pick an option for each question.'
|
||||
},
|
||||
horizontal: {
|
||||
type: jsPsych.plugins.parameterType.BOOL,
|
||||
pretty_name: 'Horizontal',
|
||||
default: false,
|
||||
description: 'If true, then questions are centered and options are displayed horizontally.'
|
||||
},
|
||||
name: {
|
||||
type: jsPsych.plugins.parameterType.STRING,
|
||||
pretty_name: 'Question Name',
|
||||
default: '',
|
||||
description: 'Controls the name of data values associated with this question'
|
||||
}
|
||||
}
|
||||
},
|
||||
randomize_question_order: {
|
||||
type: jsPsych.plugins.parameterType.BOOL,
|
||||
pretty_name: 'Randomize Question Order',
|
||||
default: false,
|
||||
description: 'If true, the order of the questions will be randomized'
|
||||
},
|
||||
preamble: {
|
||||
type: jsPsych.plugins.parameterType.STRING,
|
||||
pretty_name: 'Preamble',
|
||||
default: null,
|
||||
description: 'HTML formatted string to display at the top of the page above all the questions.'
|
||||
},
|
||||
button_label: {
|
||||
type: jsPsych.plugins.parameterType.STRING,
|
||||
pretty_name: 'Button label',
|
||||
default: 'Continue',
|
||||
description: 'Label of the button.'
|
||||
}
|
||||
}
|
||||
}
|
||||
plugin.trial = function(display_element, trial) {
|
||||
var plugin_id_name = "jspsych-survey-multi-choice";
|
||||
|
||||
var html = "";
|
||||
|
||||
// inject CSS for trial
|
||||
html += '<style id="jspsych-survey-multi-choice-css">';
|
||||
html += ".jspsych-survey-multi-choice-question { margin-top: 2em; margin-bottom: 2em; text-align: left; }"+
|
||||
".jspsych-survey-multi-choice-text span.required {color: darkred;}"+
|
||||
".jspsych-survey-multi-choice-horizontal .jspsych-survey-multi-choice-text { text-align: center;}"+
|
||||
".jspsych-survey-multi-choice-option { line-height: 2; }"+
|
||||
".jspsych-survey-multi-choice-horizontal .jspsych-survey-multi-choice-option { display: inline-block; margin-left: 1em; margin-right: 1em; vertical-align: top;}"+
|
||||
"label.jspsych-survey-multi-choice-text input[type='radio'] {margin-right: 1em;}";
|
||||
html += '</style>';
|
||||
|
||||
// show preamble text
|
||||
if(trial.preamble !== null){
|
||||
html += '<div id="jspsych-survey-multi-choice-preamble" class="jspsych-survey-multi-choice-preamble">'+trial.preamble+'</div>';
|
||||
}
|
||||
|
||||
// form element
|
||||
html += '<form id="jspsych-survey-multi-choice-form">';
|
||||
|
||||
// generate question order. this is randomized here as opposed to randomizing the order of trial.questions
|
||||
// so that the data are always associated with the same question regardless of order
|
||||
var question_order = [];
|
||||
for(var i=0; i<trial.questions.length; i++){
|
||||
question_order.push(i);
|
||||
}
|
||||
if(trial.randomize_question_order){
|
||||
question_order = jsPsych.randomization.shuffle(question_order);
|
||||
}
|
||||
|
||||
// add multiple-choice questions
|
||||
for (var i = 0; i < trial.questions.length; i++) {
|
||||
|
||||
// get question based on question_order
|
||||
var question = trial.questions[question_order[i]];
|
||||
var question_id = question_order[i];
|
||||
|
||||
// create question container
|
||||
var question_classes = ['jspsych-survey-multi-choice-question'];
|
||||
if (question.horizontal) {
|
||||
question_classes.push('jspsych-survey-multi-choice-horizontal');
|
||||
}
|
||||
|
||||
html += '<div id="jspsych-survey-multi-choice-'+question_id+'" class="'+question_classes.join(' ')+'" data-name="'+question.name+'">';
|
||||
|
||||
// add question text
|
||||
html += '<p class="jspsych-survey-multi-choice-text survey-multi-choice">' + question.prompt
|
||||
if(question.required){
|
||||
html += "<span class='required'>*</span>";
|
||||
}
|
||||
html += '</p>';
|
||||
|
||||
// create option radio buttons
|
||||
for (var j = 0; j < question.options.length; j++) {
|
||||
// add label and question text
|
||||
var option_id_name = "jspsych-survey-multi-choice-option-"+question_id+"-"+j;
|
||||
var input_name = 'jspsych-survey-multi-choice-response-'+question_id;
|
||||
var input_id = 'jspsych-survey-multi-choice-response-'+question_id+'-'+j;
|
||||
|
||||
var required_attr = question.required ? 'required' : '';
|
||||
|
||||
// add radio button container
|
||||
html += '<div id="'+option_id_name+'" class="jspsych-survey-multi-choice-option">';
|
||||
html += '<label class="jspsych-survey-multi-choice-text" for="'+input_id+'">'+question.options[j]+'</label>';
|
||||
html += '<input type="radio" name="'+input_name+'" id="'+input_id+'" value="'+question.options[j]+'" '+required_attr+'></input>';
|
||||
html += '</div>';
|
||||
}
|
||||
|
||||
html += '</div>';
|
||||
}
|
||||
|
||||
// add submit button
|
||||
html += '<input type="submit" id="'+plugin_id_name+'-next" class="'+plugin_id_name+' jspsych-btn"' + (trial.button_label ? ' value="'+trial.button_label + '"': '') + '></input>';
|
||||
html += '</form>';
|
||||
|
||||
// render
|
||||
display_element.innerHTML = html;
|
||||
|
||||
document.querySelector('form').addEventListener('submit', function(event) {
|
||||
event.preventDefault();
|
||||
// measure response time
|
||||
var endTime = performance.now();
|
||||
var response_time = endTime - startTime;
|
||||
|
||||
// create object to hold responses
|
||||
var question_data = {};
|
||||
for(var i=0; i<trial.questions.length; i++){
|
||||
var match = display_element.querySelector('#jspsych-survey-multi-choice-'+i);
|
||||
var id = "Q" + i;
|
||||
if(match.querySelector("input[type=radio]:checked") !== null){
|
||||
var val = match.querySelector("input[type=radio]:checked").value;
|
||||
} else {
|
||||
var val = "";
|
||||
}
|
||||
var obje = {};
|
||||
var name = id;
|
||||
if(match.attributes['data-name'].value !== ''){
|
||||
name = match.attributes['data-name'].value;
|
||||
}
|
||||
obje[name] = val;
|
||||
Object.assign(question_data, obje);
|
||||
}
|
||||
// save data
|
||||
var trial_data = {
|
||||
"rt": response_time,
|
||||
"responses": JSON.stringify(question_data),
|
||||
"question_order": JSON.stringify(question_order)//,
|
||||
//"reloads": reloads
|
||||
};
|
||||
display_element.innerHTML = '';
|
||||
|
||||
// next trial
|
||||
jsPsych.finishTrial(trial_data);
|
||||
});
|
||||
|
||||
var startTime = performance.now();
|
||||
};
|
||||
|
||||
return plugin;
|
||||
})();
|
||||
223
PCSurvey/PCstatic/js/plugins/jspsych-survey-multi-select.js
Normal file
223
PCSurvey/PCstatic/js/plugins/jspsych-survey-multi-select.js
Normal file
@@ -0,0 +1,223 @@
|
||||
/**
|
||||
* jspsych-survey-multi-select
|
||||
* a jspsych plugin for multiple choice survey questions
|
||||
*
|
||||
* documentation: docs.jspsych.org
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
jsPsych.plugins['survey-multi-select'] = (function() {
|
||||
var plugin = {};
|
||||
|
||||
plugin.info = {
|
||||
name: 'survey-multi-select',
|
||||
description: '',
|
||||
parameters: {
|
||||
questions: {
|
||||
type: jsPsych.plugins.parameterType.COMPLEX,
|
||||
array: true,
|
||||
pretty_name: 'Questions',
|
||||
nested: {
|
||||
prompt: {
|
||||
type: jsPsych.plugins.parameterType.STRING,
|
||||
pretty_name: 'Prompt',
|
||||
default: undefined,
|
||||
description: 'The strings that will be associated with a group of options.'
|
||||
},
|
||||
options: {
|
||||
type: jsPsych.plugins.parameterType.STRING,
|
||||
pretty_name: 'Options',
|
||||
array: true,
|
||||
default: undefined,
|
||||
description: 'Displays options for an individual question.'
|
||||
},
|
||||
horizontal: {
|
||||
type: jsPsych.plugins.parameterType.BOOL,
|
||||
pretty_name: 'Horizontal',
|
||||
default: false,
|
||||
description: 'If true, then questions are centered and options are displayed horizontally.'
|
||||
},
|
||||
required: {
|
||||
type: jsPsych.plugins.parameterType.BOOL,
|
||||
pretty_name: 'Required',
|
||||
default: false,
|
||||
description: 'Subject will be required to pick at least one option for this question.'
|
||||
},
|
||||
name: {
|
||||
type: jsPsych.plugins.parameterType.STRING,
|
||||
pretty_name: 'Question Name',
|
||||
default: '',
|
||||
description: 'Controls the name of data values associated with this question'
|
||||
}
|
||||
}
|
||||
},
|
||||
randomize_question_order: {
|
||||
type: jsPsych.plugins.parameterType.BOOL,
|
||||
pretty_name: 'Randomize Question Order',
|
||||
default: false,
|
||||
description: 'If true, the order of the questions will be randomized'
|
||||
},
|
||||
preamble: {
|
||||
type: jsPsych.plugins.parameterType.STRING,
|
||||
pretty_name: 'Preamble',
|
||||
default: null,
|
||||
description: 'HTML formatted string to display at the top of the page above all the questions.'
|
||||
},
|
||||
button_label: {
|
||||
type: jsPsych.plugins.parameterType.STRING,
|
||||
pretty_name: 'Button label',
|
||||
default: 'Continue',
|
||||
description: 'Label of the button.'
|
||||
},
|
||||
required_message: {
|
||||
type: jsPsych.plugins.parameterType.STRING,
|
||||
pretty_name: 'Required message',
|
||||
default: 'You must choose at least one response for this question',
|
||||
description: 'Message that will be displayed if required question is not answered.'
|
||||
}
|
||||
}
|
||||
}
|
||||
plugin.trial = function(display_element, trial) {
|
||||
var plugin_id_name = "jspsych-survey-multi-select";
|
||||
var plugin_id_selector = '#' + plugin_id_name;
|
||||
var _join = function( /*args*/ ) {
|
||||
var arr = Array.prototype.slice.call(arguments, _join.length);
|
||||
return arr.join(separator = '-');
|
||||
}
|
||||
|
||||
// inject CSS for trial
|
||||
var cssstr = ".jspsych-survey-multi-select-question { margin-top: 2em; margin-bottom: 2em; text-align: left; }"+
|
||||
".jspsych-survey-multi-select-text span.required {color: darkred;}"+
|
||||
".jspsych-survey-multi-select-horizontal .jspsych-survey-multi-select-text { text-align: center;}"+
|
||||
".jspsych-survey-multi-select-option { line-height: 2; }"+
|
||||
".jspsych-survey-multi-select-horizontal .jspsych-survey-multi-select-option { display: inline-block; margin-left: 1em; margin-right: 1em; vertical-align: top;}"+
|
||||
"label.jspsych-survey-multi-select-text input[type='checkbox'] {margin-right: 1em;}"
|
||||
display_element.innerHTML = '<style id="jspsych-survey-multi-select-css">' + cssstr + '</style>';
|
||||
|
||||
// form element
|
||||
var trial_form_id = _join(plugin_id_name, "form");
|
||||
display_element.innerHTML += '<form id="'+trial_form_id+'"></form>';
|
||||
var trial_form = display_element.querySelector("#" + trial_form_id);
|
||||
// show preamble text
|
||||
var preamble_id_name = _join(plugin_id_name, 'preamble');
|
||||
if(trial.preamble !== null){
|
||||
trial_form.innerHTML += '<div id="'+preamble_id_name+'" class="'+preamble_id_name+'">'+trial.preamble+'</div>';
|
||||
}
|
||||
// generate question order. this is randomized here as opposed to randomizing the order of trial.questions
|
||||
// so that the data are always associated with the same question regardless of order
|
||||
var question_order = [];
|
||||
for(var i=0; i<trial.questions.length; i++){
|
||||
question_order.push(i);
|
||||
}
|
||||
if(trial.randomize_question_order){
|
||||
question_order = jsPsych.randomization.shuffle(question_order);
|
||||
}
|
||||
// add multiple-select questions
|
||||
for (var i = 0; i < trial.questions.length; i++) {
|
||||
var question = trial.questions[question_order[i]];
|
||||
var question_id = question_order[i];
|
||||
// create question container
|
||||
var question_classes = [_join(plugin_id_name, 'question')];
|
||||
if (question.horizontal) {
|
||||
question_classes.push(_join(plugin_id_name, 'horizontal'));
|
||||
}
|
||||
|
||||
trial_form.innerHTML += '<div id="'+_join(plugin_id_name, question_id)+'" data-name="'+question.name+'" class="'+question_classes.join(' ')+'"></div>';
|
||||
|
||||
var question_selector = _join(plugin_id_selector, question_id);
|
||||
|
||||
// add question text
|
||||
display_element.querySelector(question_selector).innerHTML += '<p id="survey-question" class="' + plugin_id_name + '-text survey-multi-select">' + question.prompt + '</p>';
|
||||
|
||||
// create option check boxes
|
||||
for (var j = 0; j < question.options.length; j++) {
|
||||
var option_id_name = _join(plugin_id_name, "option", question_id, j);
|
||||
|
||||
// add check box container
|
||||
display_element.querySelector(question_selector).innerHTML += '<div id="'+option_id_name+'" class="'+_join(plugin_id_name, 'option')+'"></div>';
|
||||
|
||||
// add label and question text
|
||||
var form = document.getElementById(option_id_name)
|
||||
var input_name = _join(plugin_id_name, 'response', question_id);
|
||||
var input_id = _join(plugin_id_name, 'response', question_id, j);
|
||||
var label = document.createElement('label');
|
||||
label.setAttribute('class', plugin_id_name+'-text');
|
||||
label.innerHTML = question.options[j];
|
||||
label.setAttribute('for', input_id)
|
||||
|
||||
// create checkboxes
|
||||
var input = document.createElement('input');
|
||||
input.setAttribute('type', "checkbox");
|
||||
input.setAttribute('name', input_name);
|
||||
input.setAttribute('id', input_id);
|
||||
input.setAttribute('value', question.options[j])
|
||||
form.appendChild(label)
|
||||
form.insertBefore(input, label)
|
||||
}
|
||||
}
|
||||
// add submit button
|
||||
trial_form.innerHTML += '<div class="fail-message"></div>'
|
||||
trial_form.innerHTML += '<button id="'+plugin_id_name+'-next" class="'+plugin_id_name+' jspsych-btn">'+trial.button_label+'</button>';
|
||||
|
||||
// validation check on the data first for custom validation handling
|
||||
// then submit the form
|
||||
display_element.querySelector('#jspsych-survey-multi-select-next').addEventListener('click', function(){
|
||||
for(var i=0; i<trial.questions.length; i++){
|
||||
if(trial.questions[i].required){
|
||||
if(display_element.querySelector('#jspsych-survey-multi-select-'+i+' input:checked') == null){
|
||||
display_element.querySelector('#jspsych-survey-multi-select-'+i+' input').setCustomValidity(trial.required_message);
|
||||
} else {
|
||||
display_element.querySelector('#jspsych-survey-multi-select-'+i+' input').setCustomValidity('');
|
||||
}
|
||||
}
|
||||
}
|
||||
trial_form.reportValidity();
|
||||
})
|
||||
|
||||
trial_form.addEventListener('submit', function(event) {
|
||||
event.preventDefault();
|
||||
// measure response time
|
||||
var endTime = performance.now();
|
||||
var response_time = endTime - startTime;
|
||||
|
||||
// create object to hold responses
|
||||
var question_data = {};
|
||||
var has_response = [];
|
||||
for(var index=0; index<trial.questions.length; index++){
|
||||
var match = display_element.querySelector('#jspsych-survey-multi-select-'+index);
|
||||
var val = [];
|
||||
var inputboxes = match.querySelectorAll("input[type=checkbox]:checked")
|
||||
for(var j=0; j<inputboxes.length; j++){
|
||||
currentChecked = inputboxes[j];
|
||||
val.push(currentChecked.value)
|
||||
}
|
||||
var id = 'Q' + index
|
||||
var obje = {};
|
||||
var name = id;
|
||||
if(match.attributes['data-name'].value !== ''){
|
||||
name = match.attributes['data-name'].value;
|
||||
}
|
||||
obje[name] = val;
|
||||
Object.assign(question_data, obje);
|
||||
if(val.length == 0){ has_response.push(false); } else { has_response.push(true); }
|
||||
}
|
||||
|
||||
// save data
|
||||
var trial_data = {
|
||||
"rt": response_time,
|
||||
"responses": JSON.stringify(question_data),
|
||||
"question_order": JSON.stringify(question_order)
|
||||
};
|
||||
display_element.innerHTML = '';
|
||||
|
||||
// next trial
|
||||
jsPsych.finishTrial(trial_data);
|
||||
|
||||
});
|
||||
|
||||
var startTime = performance.now();
|
||||
};
|
||||
|
||||
return plugin;
|
||||
})();
|
||||
176
PCSurvey/PCstatic/js/plugins/jspsych-survey-text.js
Normal file
176
PCSurvey/PCstatic/js/plugins/jspsych-survey-text.js
Normal file
@@ -0,0 +1,176 @@
|
||||
/**
|
||||
* jspsych-survey-text
|
||||
* a jspsych plugin for free response survey questions
|
||||
*
|
||||
* Josh de Leeuw
|
||||
*
|
||||
* documentation: docs.jspsych.org
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
jsPsych.plugins['survey-text'] = (function() {
|
||||
|
||||
var plugin = {};
|
||||
|
||||
plugin.info = {
|
||||
name: 'survey-text',
|
||||
description: '',
|
||||
parameters: {
|
||||
questions: {
|
||||
type: jsPsych.plugins.parameterType.COMPLEX,
|
||||
array: true,
|
||||
pretty_name: 'Questions',
|
||||
default: undefined,
|
||||
nested: {
|
||||
prompt: {
|
||||
type: jsPsych.plugins.parameterType.STRING,
|
||||
pretty_name: 'Prompt',
|
||||
default: undefined,
|
||||
description: 'Prompt for the subject to response'
|
||||
},
|
||||
placeholder: {
|
||||
type: jsPsych.plugins.parameterType.STRING,
|
||||
pretty_name: 'Value',
|
||||
default: "",
|
||||
description: 'Placeholder text in the textfield.'
|
||||
},
|
||||
rows: {
|
||||
type: jsPsych.plugins.parameterType.INT,
|
||||
pretty_name: 'Rows',
|
||||
default: 1,
|
||||
description: 'The number of rows for the response text box.'
|
||||
},
|
||||
columns: {
|
||||
type: jsPsych.plugins.parameterType.INT,
|
||||
pretty_name: 'Columns',
|
||||
default: 40,
|
||||
description: 'The number of columns for the response text box.'
|
||||
},
|
||||
required: {
|
||||
type: jsPsych.plugins.parameterType.BOOL,
|
||||
pretty_name: 'Required',
|
||||
default: false,
|
||||
description: 'Require a response'
|
||||
},
|
||||
name: {
|
||||
type: jsPsych.plugins.parameterType.STRING,
|
||||
pretty_name: 'Question Name',
|
||||
default: '',
|
||||
description: 'Controls the name of data values associated with this question'
|
||||
}
|
||||
}
|
||||
},
|
||||
preamble: {
|
||||
type: jsPsych.plugins.parameterType.STRING,
|
||||
pretty_name: 'Preamble',
|
||||
default: null,
|
||||
description: 'HTML formatted string to display at the top of the page above all the questions.'
|
||||
},
|
||||
button_label: {
|
||||
type: jsPsych.plugins.parameterType.STRING,
|
||||
pretty_name: 'Button label',
|
||||
default: 'Continue',
|
||||
description: 'The text that appears on the button to finish the trial.'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
plugin.trial = function(display_element, trial) {
|
||||
|
||||
for (var i = 0; i < trial.questions.length; i++) {
|
||||
if (typeof trial.questions[i].rows == 'undefined') {
|
||||
trial.questions[i].rows = 1;
|
||||
}
|
||||
}
|
||||
for (var i = 0; i < trial.questions.length; i++) {
|
||||
if (typeof trial.questions[i].columns == 'undefined') {
|
||||
trial.questions[i].columns = 40;
|
||||
}
|
||||
}
|
||||
for (var i = 0; i < trial.questions.length; i++) {
|
||||
if (typeof trial.questions[i].value == 'undefined') {
|
||||
trial.questions[i].value = "";
|
||||
}
|
||||
}
|
||||
|
||||
var html = '';
|
||||
// show preamble text
|
||||
if(trial.preamble !== null){
|
||||
html += '<div id="jspsych-survey-text-preamble" class="jspsych-survey-text-preamble">'+trial.preamble+'</div>';
|
||||
}
|
||||
// start form
|
||||
html += '<form id="jspsych-survey-text-form">'
|
||||
|
||||
// generate question order
|
||||
var question_order = [];
|
||||
for(var i=0; i<trial.questions.length; i++){
|
||||
question_order.push(i);
|
||||
}
|
||||
if(trial.randomize_question_order){
|
||||
question_order = jsPsych.randomization.shuffle(question_order);
|
||||
}
|
||||
|
||||
// add questions
|
||||
for (var i = 0; i < trial.questions.length; i++) {
|
||||
var question = trial.questions[question_order[i]];
|
||||
var question_index = question_order[i];
|
||||
html += '<div id="jspsych-survey-text-'+question_index+'" class="jspsych-survey-text-question" style="margin: 2em 0em;">';
|
||||
html += '<p class="jspsych-survey-text">' + question.prompt + '</p>';
|
||||
var autofocus = i == 0 ? "autofocus" : "";
|
||||
var req = question.required ? "required" : "";
|
||||
if(question.rows == 1){
|
||||
html += '<input type="text" id="input-'+question_index+'" name="#jspsych-survey-text-response-' + question_index + '" data-name="'+question.name+'" size="'+question.columns+'" '+autofocus+' '+req+' placeholder="'+question.placeholder+'"></input>';
|
||||
} else {
|
||||
html += '<textarea id="input-'+question_index+'" name="#jspsych-survey-text-response-' + question_index + '" data-name="'+question.name+'" cols="' + question.columns + '" rows="' + question.rows + '" '+autofocus+' '+req+' placeholder="'+question.placeholder+'"></textarea>';
|
||||
}
|
||||
html += '</div>';
|
||||
}
|
||||
|
||||
// add submit button
|
||||
html += '<input type="submit" id="jspsych-survey-text-next" class="jspsych-btn jspsych-survey-text" value="'+trial.button_label+'"></input>';
|
||||
|
||||
html += '</form>'
|
||||
display_element.innerHTML = html;
|
||||
|
||||
// backup in case autofocus doesn't work
|
||||
display_element.querySelector('#input-'+question_order[0]).focus();
|
||||
|
||||
display_element.querySelector('#jspsych-survey-text-form').addEventListener('submit', function(e) {
|
||||
e.preventDefault();
|
||||
// measure response time
|
||||
var endTime = performance.now();
|
||||
var response_time = endTime - startTime;
|
||||
|
||||
// create object to hold responses
|
||||
var question_data = {};
|
||||
|
||||
for(var index=0; index < trial.questions.length; index++){
|
||||
var id = "Q" + index;
|
||||
var q_element = document.querySelector('#jspsych-survey-text-'+index).querySelector('textarea, input');
|
||||
var val = q_element.value;
|
||||
var name = q_element.attributes['data-name'].value;
|
||||
if(name == ''){
|
||||
name = id;
|
||||
}
|
||||
var obje = {};
|
||||
obje[name] = val;
|
||||
Object.assign(question_data, obje);
|
||||
}
|
||||
// save data
|
||||
var trialdata = {
|
||||
"rt": response_time,
|
||||
"responses": JSON.stringify(question_data)
|
||||
};
|
||||
|
||||
display_element.innerHTML = '';
|
||||
|
||||
// next trial
|
||||
jsPsych.finishTrial(trialdata);
|
||||
});
|
||||
|
||||
var startTime = performance.now();
|
||||
};
|
||||
|
||||
return plugin;
|
||||
})();
|
||||
279
PCSurvey/PCstatic/js/plugins/jspsych-video-button-response.js
Normal file
279
PCSurvey/PCstatic/js/plugins/jspsych-video-button-response.js
Normal file
@@ -0,0 +1,279 @@
|
||||
/**
|
||||
* jspsych-video-button-response
|
||||
* Josh de Leeuw
|
||||
*
|
||||
* plugin for playing a video file and getting a button response
|
||||
*
|
||||
* documentation: docs.jspsych.org
|
||||
*
|
||||
**/
|
||||
|
||||
jsPsych.plugins["video-button-response"] = (function() {
|
||||
|
||||
var plugin = {};
|
||||
|
||||
jsPsych.pluginAPI.registerPreload('video-button-response', 'stimulus', 'video');
|
||||
|
||||
plugin.info = {
|
||||
name: 'video-button-response',
|
||||
description: '',
|
||||
parameters: {
|
||||
sources: {
|
||||
type: jsPsych.plugins.parameterType.VIDEO,
|
||||
pretty_name: 'Video',
|
||||
default: undefined,
|
||||
description: 'The video file to play.'
|
||||
},
|
||||
choices: {
|
||||
type: jsPsych.plugins.parameterType.STRING,
|
||||
pretty_name: 'Choices',
|
||||
default: undefined,
|
||||
array: true,
|
||||
description: 'The labels for the buttons.'
|
||||
},
|
||||
button_html: {
|
||||
type: jsPsych.plugins.parameterType.STRING,
|
||||
pretty_name: 'Button HTML',
|
||||
default: '<button class="jspsych-btn">%choice%</button>',
|
||||
array: true,
|
||||
description: 'The html of the button. Can create own style.'
|
||||
},
|
||||
prompt: {
|
||||
type: jsPsych.plugins.parameterType.STRING,
|
||||
pretty_name: 'Prompt',
|
||||
default: null,
|
||||
description: 'Any content here will be displayed below the buttons.'
|
||||
},
|
||||
width: {
|
||||
type: jsPsych.plugins.parameterType.INT,
|
||||
pretty_name: 'Width',
|
||||
default: '',
|
||||
description: 'The width of the video in pixels.'
|
||||
},
|
||||
height: {
|
||||
type: jsPsych.plugins.parameterType.INT,
|
||||
pretty_name: 'Height',
|
||||
default: '',
|
||||
description: 'The height of the video display in pixels.'
|
||||
},
|
||||
autoplay: {
|
||||
type: jsPsych.plugins.parameterType.BOOL,
|
||||
pretty_name: 'Autoplay',
|
||||
default: true,
|
||||
description: 'If true, the video will begin playing as soon as it has loaded.'
|
||||
},
|
||||
controls: {
|
||||
type: jsPsych.plugins.parameterType.BOOL,
|
||||
pretty_name: 'Controls',
|
||||
default: false,
|
||||
description: 'If true, the subject will be able to pause the video or move the playback to any point in the video.'
|
||||
},
|
||||
start: {
|
||||
type: jsPsych.plugins.parameterType.FLOAT,
|
||||
pretty_name: 'Start',
|
||||
default: null,
|
||||
description: 'Time to start the clip.'
|
||||
},
|
||||
stop: {
|
||||
type: jsPsych.plugins.parameterType.FLOAT,
|
||||
pretty_name: 'Stop',
|
||||
default: null,
|
||||
description: 'Time to stop the clip.'
|
||||
},
|
||||
rate: {
|
||||
type: jsPsych.plugins.parameterType.FLOAT,
|
||||
pretty_name: 'Rate',
|
||||
default: 1,
|
||||
description: 'The playback rate of the video. 1 is normal, <1 is slower, >1 is faster.'
|
||||
},
|
||||
trial_ends_after_video: {
|
||||
type: jsPsych.plugins.parameterType.BOOL,
|
||||
pretty_name: 'End trial after video finishes',
|
||||
default: false,
|
||||
description: 'If true, the trial will end immediately after the video finishes playing.'
|
||||
},
|
||||
trial_duration: {
|
||||
type: jsPsych.plugins.parameterType.INT,
|
||||
pretty_name: 'Trial duration',
|
||||
default: null,
|
||||
description: 'How long to show trial before it ends.'
|
||||
},
|
||||
margin_vertical: {
|
||||
type: jsPsych.plugins.parameterType.STRING,
|
||||
pretty_name: 'Margin vertical',
|
||||
default: '0px',
|
||||
description: 'The vertical margin of the button.'
|
||||
},
|
||||
margin_horizontal: {
|
||||
type: jsPsych.plugins.parameterType.STRING,
|
||||
pretty_name: 'Margin horizontal',
|
||||
default: '8px',
|
||||
description: 'The horizontal margin of the button.'
|
||||
},
|
||||
response_ends_trial: {
|
||||
type: jsPsych.plugins.parameterType.BOOL,
|
||||
pretty_name: 'Response ends trial',
|
||||
default: true,
|
||||
description: 'If true, the trial will end when subject makes a response.'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
plugin.trial = function(display_element, trial) {
|
||||
|
||||
// setup stimulus
|
||||
var video_html = '<div>'
|
||||
video_html += '<video id="jspsych-video-button-response-stimulus"';
|
||||
|
||||
if(trial.width) {
|
||||
video_html += ' width="'+trial.width+'"';
|
||||
}
|
||||
if(trial.height) {
|
||||
video_html += ' height="'+trial.height+'"';
|
||||
}
|
||||
if(trial.autoplay){
|
||||
video_html += " autoplay ";
|
||||
}
|
||||
if(trial.controls){
|
||||
video_html +=" controls ";
|
||||
}
|
||||
video_html +=">";
|
||||
|
||||
var video_preload_blob = jsPsych.pluginAPI.getVideoBuffer(trial.sources[0]);
|
||||
if(!video_preload_blob) {
|
||||
for(var i=0; i<trial.sources.length; i++){
|
||||
var file_name = trial.sources[i];
|
||||
if(file_name.indexOf('?') > -1){
|
||||
file_name = file_name.substring(0, file_name.indexOf('?'));
|
||||
}
|
||||
var type = file_name.substr(file_name.lastIndexOf('.') + 1);
|
||||
type = type.toLowerCase();
|
||||
video_html+='<source src="' + file_name + '" type="video/'+type+'">';
|
||||
}
|
||||
}
|
||||
video_html += "</video>";
|
||||
video_html += "</div>";
|
||||
|
||||
//display buttons
|
||||
var buttons = [];
|
||||
if (Array.isArray(trial.button_html)) {
|
||||
if (trial.button_html.length == trial.choices.length) {
|
||||
buttons = trial.button_html;
|
||||
} else {
|
||||
console.error('Error in video-button-response plugin. The length of the button_html array does not equal the length of the choices array');
|
||||
}
|
||||
} else {
|
||||
for (var i = 0; i < trial.choices.length; i++) {
|
||||
buttons.push(trial.button_html);
|
||||
}
|
||||
}
|
||||
video_html += '<div id="jspsych-video-button-response-btngroup">';
|
||||
for (var i = 0; i < trial.choices.length; i++) {
|
||||
var str = buttons[i].replace(/%choice%/g, trial.choices[i]);
|
||||
video_html += '<div class="jspsych-video-button-response-button" style="display: inline-block; margin:'+trial.margin_vertical+' '+trial.margin_horizontal+'" id="jspsych-video-button-response-button-' + i +'" data-choice="'+i+'">'+str+'</div>';
|
||||
}
|
||||
video_html += '</div>';
|
||||
|
||||
// add prompt if there is one
|
||||
if (trial.prompt !== null) {
|
||||
video_html += trial.prompt;
|
||||
}
|
||||
|
||||
display_element.innerHTML = video_html;
|
||||
|
||||
var start_time = performance.now();
|
||||
|
||||
if(video_preload_blob){
|
||||
display_element.querySelector('#jspsych-video-button-response-stimulus').src = video_preload_blob;
|
||||
}
|
||||
|
||||
display_element.querySelector('#jspsych-video-button-response-stimulus').onended = function(){
|
||||
if(trial.trial_ends_after_video){
|
||||
end_trial();
|
||||
}
|
||||
}
|
||||
|
||||
if(trial.start !== null){
|
||||
display_element.querySelector('#jspsych-video-button-response-stimulus').currentTime = trial.start;
|
||||
}
|
||||
|
||||
if(trial.stop !== null){
|
||||
display_element.querySelector('#jspsych-video-button-response-stimulus').addEventListener('timeupdate', function(e){
|
||||
var currenttime = display_element.querySelector('#jspsych-video-button-response-stimulus').currentTime;
|
||||
if(currenttime >= trial.stop){
|
||||
display_element.querySelector('#jspsych-video-button-response-stimulus').pause();
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
display_element.querySelector('#jspsych-video-button-response-stimulus').playbackRate = trial.rate;
|
||||
|
||||
// add event listeners to buttons
|
||||
for (var i = 0; i < trial.choices.length; i++) {
|
||||
display_element.querySelector('#jspsych-video-button-response-button-' + i).addEventListener('click', function(e){
|
||||
var choice = e.currentTarget.getAttribute('data-choice'); // don't use dataset for jsdom compatibility
|
||||
after_response(choice);
|
||||
});
|
||||
}
|
||||
|
||||
// store response
|
||||
var response = {
|
||||
rt: null,
|
||||
button: null
|
||||
};
|
||||
|
||||
// function to end trial when it is time
|
||||
function end_trial() {
|
||||
|
||||
// kill any remaining setTimeout handlers
|
||||
jsPsych.pluginAPI.clearAllTimeouts();
|
||||
|
||||
// gather the data to store for the trial
|
||||
var trial_data = {
|
||||
"rt": response.rt,
|
||||
"stimulus": trial.stimulus,
|
||||
"button_pressed": response.button
|
||||
};
|
||||
|
||||
// clear the display
|
||||
display_element.innerHTML = '';
|
||||
|
||||
// move on to the next trial
|
||||
jsPsych.finishTrial(trial_data);
|
||||
};
|
||||
|
||||
// function to handle responses by the subject
|
||||
function after_response(choice) {
|
||||
|
||||
// measure rt
|
||||
var end_time = performance.now();
|
||||
var rt = end_time - start_time;
|
||||
response.button = choice;
|
||||
response.rt = rt;
|
||||
|
||||
// after a valid response, the stimulus will have the CSS class 'responded'
|
||||
// which can be used to provide visual feedback that a response was recorded
|
||||
display_element.querySelector('#jspsych-video-button-response-stimulus').className += ' responded';
|
||||
|
||||
// disable all the buttons after a response
|
||||
var btns = document.querySelectorAll('.jspsych-video-button-response-button button');
|
||||
for(var i=0; i<btns.length; i++){
|
||||
//btns[i].removeEventListener('click');
|
||||
btns[i].setAttribute('disabled', 'disabled');
|
||||
}
|
||||
|
||||
if (trial.response_ends_trial) {
|
||||
end_trial();
|
||||
}
|
||||
};
|
||||
|
||||
// end trial if time limit is set
|
||||
if (trial.trial_duration !== null) {
|
||||
jsPsych.pluginAPI.setTimeout(function() {
|
||||
end_trial();
|
||||
}, trial.trial_duration);
|
||||
}
|
||||
};
|
||||
|
||||
return plugin;
|
||||
})();
|
||||
236
PCSurvey/PCstatic/js/plugins/jspsych-video-keyboard-response.js
Normal file
236
PCSurvey/PCstatic/js/plugins/jspsych-video-keyboard-response.js
Normal file
@@ -0,0 +1,236 @@
|
||||
/**
|
||||
* jspsych-video-keyboard-response
|
||||
* Josh de Leeuw
|
||||
*
|
||||
* plugin for playing a video file and getting a keyboard response
|
||||
*
|
||||
* documentation: docs.jspsych.org
|
||||
*
|
||||
**/
|
||||
|
||||
jsPsych.plugins["video-keyboard-response"] = (function() {
|
||||
|
||||
var plugin = {};
|
||||
|
||||
jsPsych.pluginAPI.registerPreload('video-keyboard-response', 'stimulus', 'video');
|
||||
|
||||
plugin.info = {
|
||||
name: 'video-keyboard-response',
|
||||
description: '',
|
||||
parameters: {
|
||||
sources: {
|
||||
type: jsPsych.plugins.parameterType.VIDEO,
|
||||
pretty_name: 'Video',
|
||||
default: undefined,
|
||||
description: 'The video file to play.'
|
||||
},
|
||||
choices: {
|
||||
type: jsPsych.plugins.parameterType.KEYCODE,
|
||||
pretty_name: 'Choices',
|
||||
array: true,
|
||||
default: jsPsych.ALL_KEYS,
|
||||
description: 'The keys the subject is allowed to press to respond to the stimulus.'
|
||||
},
|
||||
prompt: {
|
||||
type: jsPsych.plugins.parameterType.STRING,
|
||||
pretty_name: 'Prompt',
|
||||
default: null,
|
||||
description: 'Any content here will be displayed below the stimulus.'
|
||||
},
|
||||
width: {
|
||||
type: jsPsych.plugins.parameterType.INT,
|
||||
pretty_name: 'Width',
|
||||
default: '',
|
||||
description: 'The width of the video in pixels.'
|
||||
},
|
||||
height: {
|
||||
type: jsPsych.plugins.parameterType.INT,
|
||||
pretty_name: 'Height',
|
||||
default: '',
|
||||
description: 'The height of the video display in pixels.'
|
||||
},
|
||||
autoplay: {
|
||||
type: jsPsych.plugins.parameterType.BOOL,
|
||||
pretty_name: 'Autoplay',
|
||||
default: true,
|
||||
description: 'If true, the video will begin playing as soon as it has loaded.'
|
||||
},
|
||||
controls: {
|
||||
type: jsPsych.plugins.parameterType.BOOL,
|
||||
pretty_name: 'Controls',
|
||||
default: false,
|
||||
description: 'If true, the subject will be able to pause the video or move the playback to any point in the video.'
|
||||
},
|
||||
start: {
|
||||
type: jsPsych.plugins.parameterType.FLOAT,
|
||||
pretty_name: 'Start',
|
||||
default: null,
|
||||
description: 'Time to start the clip.'
|
||||
},
|
||||
stop: {
|
||||
type: jsPsych.plugins.parameterType.FLOAT,
|
||||
pretty_name: 'Stop',
|
||||
default: null,
|
||||
description: 'Time to stop the clip.'
|
||||
},
|
||||
rate: {
|
||||
type: jsPsych.plugins.parameterType.FLOAT,
|
||||
pretty_name: 'Rate',
|
||||
default: 1,
|
||||
description: 'The playback rate of the video. 1 is normal, <1 is slower, >1 is faster.'
|
||||
},
|
||||
trial_ends_after_video: {
|
||||
type: jsPsych.plugins.parameterType.BOOL,
|
||||
pretty_name: 'End trial after video finishes',
|
||||
default: false,
|
||||
description: 'If true, the trial will end immediately after the video finishes playing.'
|
||||
},
|
||||
trial_duration: {
|
||||
type: jsPsych.plugins.parameterType.INT,
|
||||
pretty_name: 'Trial duration',
|
||||
default: null,
|
||||
description: 'How long to show trial before it ends.'
|
||||
},
|
||||
response_ends_trial: {
|
||||
type: jsPsych.plugins.parameterType.BOOL,
|
||||
pretty_name: 'Response ends trial',
|
||||
default: true,
|
||||
description: 'If true, the trial will end when subject makes a response.'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
plugin.trial = function(display_element, trial) {
|
||||
|
||||
// setup stimulus
|
||||
var video_html = '<div>'
|
||||
video_html += '<video id="jspsych-video-keyboard-response-stimulus"';
|
||||
|
||||
if(trial.width) {
|
||||
video_html += ' width="'+trial.width+'"';
|
||||
}
|
||||
if(trial.height) {
|
||||
video_html += ' height="'+trial.height+'"';
|
||||
}
|
||||
if(trial.autoplay){
|
||||
video_html += " autoplay ";
|
||||
}
|
||||
if(trial.controls){
|
||||
video_html +=" controls ";
|
||||
}
|
||||
video_html +=">";
|
||||
|
||||
var video_preload_blob = jsPsych.pluginAPI.getVideoBuffer(trial.sources[0]);
|
||||
if(!video_preload_blob) {
|
||||
for(var i=0; i<trial.sources.length; i++){
|
||||
var file_name = trial.sources[i];
|
||||
if(file_name.indexOf('?') > -1){
|
||||
file_name = file_name.substring(0, file_name.indexOf('?'));
|
||||
}
|
||||
var type = file_name.substr(file_name.lastIndexOf('.') + 1);
|
||||
type = type.toLowerCase();
|
||||
video_html+='<source src="' + file_name + '" type="video/'+type+'">';
|
||||
}
|
||||
}
|
||||
video_html += "</video>";
|
||||
video_html += "</div>";
|
||||
|
||||
// add prompt if there is one
|
||||
if (trial.prompt !== null) {
|
||||
video_html += trial.prompt;
|
||||
}
|
||||
|
||||
display_element.innerHTML = video_html;
|
||||
|
||||
if(video_preload_blob){
|
||||
display_element.querySelector('#jspsych-video-keyboard-response-stimulus').src = video_preload_blob;
|
||||
}
|
||||
|
||||
display_element.querySelector('#jspsych-video-keyboard-response-stimulus').onended = function(){
|
||||
if(trial.trial_ends_after_video){
|
||||
end_trial();
|
||||
}
|
||||
}
|
||||
|
||||
if(trial.start !== null){
|
||||
display_element.querySelector('#jspsych-video-keyboard-response-stimulus').currentTime = trial.start;
|
||||
}
|
||||
|
||||
if(trial.stop !== null){
|
||||
display_element.querySelector('#jspsych-video-keyboard-response-stimulus').addEventListener('timeupdate', function(e){
|
||||
var currenttime = display_element.querySelector('#jspsych-video-keyboard-response-stimulus').currentTime;
|
||||
if(currenttime >= trial.stop){
|
||||
display_element.querySelector('#jspsych-video-keyboard-response-stimulus').pause();
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
display_element.querySelector('#jspsych-video-keyboard-response-stimulus').playbackRate = trial.rate;
|
||||
|
||||
// store response
|
||||
var response = {
|
||||
rt: null,
|
||||
key: null
|
||||
};
|
||||
|
||||
// function to end trial when it is time
|
||||
function end_trial() {
|
||||
|
||||
// kill any remaining setTimeout handlers
|
||||
jsPsych.pluginAPI.clearAllTimeouts();
|
||||
|
||||
// kill keyboard listeners
|
||||
jsPsych.pluginAPI.cancelAllKeyboardResponses();
|
||||
|
||||
// gather the data to store for the trial
|
||||
var trial_data = {
|
||||
"rt": response.rt,
|
||||
"stimulus": trial.stimulus,
|
||||
"key_press": response.key
|
||||
};
|
||||
|
||||
// clear the display
|
||||
display_element.innerHTML = '';
|
||||
|
||||
// move on to the next trial
|
||||
jsPsych.finishTrial(trial_data);
|
||||
};
|
||||
|
||||
// function to handle responses by the subject
|
||||
var after_response = function(info) {
|
||||
|
||||
// after a valid response, the stimulus will have the CSS class 'responded'
|
||||
// which can be used to provide visual feedback that a response was recorded
|
||||
display_element.querySelector('#jspsych-video-keyboard-response-stimulus').className += ' responded';
|
||||
|
||||
// only record the first response
|
||||
if (response.key == null) {
|
||||
response = info;
|
||||
}
|
||||
|
||||
if (trial.response_ends_trial) {
|
||||
end_trial();
|
||||
}
|
||||
};
|
||||
|
||||
// start the response listener
|
||||
if (trial.choices != jsPsych.NO_KEYS) {
|
||||
var keyboardListener = jsPsych.pluginAPI.getKeyboardResponse({
|
||||
callback_function: after_response,
|
||||
valid_responses: trial.choices,
|
||||
rt_method: 'performance',
|
||||
persist: false,
|
||||
allow_held_key: false,
|
||||
});
|
||||
}
|
||||
|
||||
// end trial if time limit is set
|
||||
if (trial.trial_duration !== null) {
|
||||
jsPsych.pluginAPI.setTimeout(function() {
|
||||
end_trial();
|
||||
}, trial.trial_duration);
|
||||
}
|
||||
};
|
||||
|
||||
return plugin;
|
||||
})();
|
||||
291
PCSurvey/PCstatic/js/plugins/jspsych-video-slider-response.js
Normal file
291
PCSurvey/PCstatic/js/plugins/jspsych-video-slider-response.js
Normal file
@@ -0,0 +1,291 @@
|
||||
/**
|
||||
* jspsych-video-slider-response
|
||||
* Josh de Leeuw
|
||||
*
|
||||
* plugin for playing a video file and getting a slider response
|
||||
*
|
||||
* documentation: docs.jspsych.org
|
||||
*
|
||||
**/
|
||||
|
||||
jsPsych.plugins["video-slider-response"] = (function() {
|
||||
|
||||
var plugin = {};
|
||||
|
||||
jsPsych.pluginAPI.registerPreload('video-slider-response', 'stimulus', 'video');
|
||||
|
||||
plugin.info = {
|
||||
name: 'video-slider-response',
|
||||
description: '',
|
||||
parameters: {
|
||||
sources: {
|
||||
type: jsPsych.plugins.parameterType.VIDEO,
|
||||
pretty_name: 'Video',
|
||||
default: undefined,
|
||||
description: 'The video file to play.'
|
||||
},
|
||||
prompt: {
|
||||
type: jsPsych.plugins.parameterType.STRING,
|
||||
pretty_name: 'Prompt',
|
||||
default: null,
|
||||
description: 'Any content here will be displayed below the stimulus.'
|
||||
},
|
||||
width: {
|
||||
type: jsPsych.plugins.parameterType.INT,
|
||||
pretty_name: 'Width',
|
||||
default: '',
|
||||
description: 'The width of the video in pixels.'
|
||||
},
|
||||
height: {
|
||||
type: jsPsych.plugins.parameterType.INT,
|
||||
pretty_name: 'Height',
|
||||
default: '',
|
||||
description: 'The height of the video display in pixels.'
|
||||
},
|
||||
autoplay: {
|
||||
type: jsPsych.plugins.parameterType.BOOL,
|
||||
pretty_name: 'Autoplay',
|
||||
default: true,
|
||||
description: 'If true, the video will begin playing as soon as it has loaded.'
|
||||
},
|
||||
controls: {
|
||||
type: jsPsych.plugins.parameterType.BOOL,
|
||||
pretty_name: 'Controls',
|
||||
default: false,
|
||||
description: 'If true, the subject will be able to pause the video or move the playback to any point in the video.'
|
||||
},
|
||||
start: {
|
||||
type: jsPsych.plugins.parameterType.FLOAT,
|
||||
pretty_name: 'Start',
|
||||
default: null,
|
||||
description: 'Time to start the clip.'
|
||||
},
|
||||
stop: {
|
||||
type: jsPsych.plugins.parameterType.FLOAT,
|
||||
pretty_name: 'Stop',
|
||||
default: null,
|
||||
description: 'Time to stop the clip.'
|
||||
},
|
||||
rate: {
|
||||
type: jsPsych.plugins.parameterType.FLOAT,
|
||||
pretty_name: 'Rate',
|
||||
default: 1,
|
||||
description: 'The playback rate of the video. 1 is normal, <1 is slower, >1 is faster.'
|
||||
},
|
||||
min: {
|
||||
type: jsPsych.plugins.parameterType.INT,
|
||||
pretty_name: 'Min slider',
|
||||
default: 0,
|
||||
description: 'Sets the minimum value of the slider.'
|
||||
},
|
||||
max: {
|
||||
type: jsPsych.plugins.parameterType.INT,
|
||||
pretty_name: 'Max slider',
|
||||
default: 100,
|
||||
description: 'Sets the maximum value of the slider',
|
||||
},
|
||||
slider_start: {
|
||||
type: jsPsych.plugins.parameterType.INT,
|
||||
pretty_name: 'Slider starting value',
|
||||
default: 50,
|
||||
description: 'Sets the starting value of the slider',
|
||||
},
|
||||
step: {
|
||||
type: jsPsych.plugins.parameterType.INT,
|
||||
pretty_name: 'Step',
|
||||
default: 1,
|
||||
description: 'Sets the step of the slider'
|
||||
},
|
||||
labels: {
|
||||
type: jsPsych.plugins.parameterType.HTML_STRING,
|
||||
pretty_name:'Labels',
|
||||
default: [],
|
||||
array: true,
|
||||
description: 'Labels of the slider.',
|
||||
},
|
||||
slider_width: {
|
||||
type: jsPsych.plugins.parameterType.INT,
|
||||
pretty_name:'Slider width',
|
||||
default: null,
|
||||
description: 'Width of the slider in pixels.'
|
||||
},
|
||||
button_label: {
|
||||
type: jsPsych.plugins.parameterType.STRING,
|
||||
pretty_name: 'Button label',
|
||||
default: 'Continue',
|
||||
array: false,
|
||||
description: 'Label of the button to advance.'
|
||||
},
|
||||
require_movement: {
|
||||
type: jsPsych.plugins.parameterType.BOOL,
|
||||
pretty_name: 'Require movement',
|
||||
default: false,
|
||||
description: 'If true, the participant will have to move the slider before continuing.'
|
||||
},
|
||||
trial_ends_after_video: {
|
||||
type: jsPsych.plugins.parameterType.BOOL,
|
||||
pretty_name: 'End trial after video finishes',
|
||||
default: false,
|
||||
description: 'If true, the trial will end immediately after the video finishes playing.'
|
||||
},
|
||||
trial_duration: {
|
||||
type: jsPsych.plugins.parameterType.INT,
|
||||
pretty_name: 'Trial duration',
|
||||
default: null,
|
||||
description: 'How long to show trial before it ends.'
|
||||
},
|
||||
response_ends_trial: {
|
||||
type: jsPsych.plugins.parameterType.BOOL,
|
||||
pretty_name: 'Response ends trial',
|
||||
default: true,
|
||||
description: 'If true, the trial will end when subject makes a response.'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
plugin.trial = function(display_element, trial) {
|
||||
|
||||
// setup stimulus
|
||||
var video_html = '<video id="jspsych-video-slider-response-stimulus"';
|
||||
|
||||
if(trial.width) {
|
||||
video_html += ' width="'+trial.width+'"';
|
||||
}
|
||||
if(trial.height) {
|
||||
video_html += ' height="'+trial.height+'"';
|
||||
}
|
||||
if(trial.autoplay){
|
||||
video_html += " autoplay ";
|
||||
}
|
||||
if(trial.controls){
|
||||
video_html +=" controls ";
|
||||
}
|
||||
video_html +=">";
|
||||
|
||||
var video_preload_blob = jsPsych.pluginAPI.getVideoBuffer(trial.sources[0]);
|
||||
if(!video_preload_blob) {
|
||||
for(var i=0; i<trial.sources.length; i++){
|
||||
var file_name = trial.sources[i];
|
||||
if(file_name.indexOf('?') > -1){
|
||||
file_name = file_name.substring(0, file_name.indexOf('?'));
|
||||
}
|
||||
var type = file_name.substr(file_name.lastIndexOf('.') + 1);
|
||||
type = type.toLowerCase();
|
||||
video_html+='<source src="' + file_name + '" type="video/'+type+'">';
|
||||
}
|
||||
}
|
||||
video_html += "</video>";
|
||||
|
||||
var html = '<div id="jspsych-video-slider-response-wrapper" style="margin: 100px 0px;">';
|
||||
html += '<div id="jspsych-video-slider-response-stimulus">' + video_html + '</div>';
|
||||
html += '<div class="jspsych-video-slider-response-container" style="position:relative; margin: 0 auto 3em auto; ';
|
||||
if(trial.slider_width !== null){
|
||||
html += 'width:'+trial.slider_width+'px;';
|
||||
}
|
||||
html += '">';
|
||||
html += '<input type="range" value="'+trial.start+'" min="'+trial.min+'" max="'+trial.max+'" step="'+trial.step+'" style="width: 100%;" id="jspsych-video-slider-response-response"></input>';
|
||||
html += '<div>'
|
||||
for(var j=0; j < trial.labels.length; j++){
|
||||
var width = 100/(trial.labels.length-1);
|
||||
var left_offset = (j * (100 /(trial.labels.length - 1))) - (width/2);
|
||||
html += '<div style="display: inline-block; position: absolute; left:'+left_offset+'%; text-align: center; width: '+width+'%;">';
|
||||
html += '<span style="text-align: center; font-size: 80%;">'+trial.labels[j]+'</span>';
|
||||
html += '</div>'
|
||||
}
|
||||
html += '</div>';
|
||||
html += '</div>';
|
||||
html += '</div>';
|
||||
|
||||
// add prompt if there is one
|
||||
if (trial.prompt !== null) {
|
||||
html += '<div>'+trial.prompt+'</div>';
|
||||
}
|
||||
|
||||
// add submit button
|
||||
html += '<button id="jspsych-video-slider-response-next" class="jspsych-btn" '+ (trial.require_movement ? "disabled" : "") + '>'+trial.button_label+'</button>';
|
||||
|
||||
display_element.innerHTML = html;
|
||||
|
||||
if(video_preload_blob){
|
||||
display_element.querySelector('#jspsych-video-slider-response-stimulus').src = video_preload_blob;
|
||||
}
|
||||
|
||||
display_element.querySelector('#jspsych-video-slider-response-stimulus').onended = function(){
|
||||
if(trial.trial_ends_after_video){
|
||||
end_trial();
|
||||
}
|
||||
}
|
||||
|
||||
if(trial.start !== null){
|
||||
display_element.querySelector('#jspsych-video-slider-response-stimulus').currentTime = trial.start;
|
||||
}
|
||||
|
||||
if(trial.stop !== null){
|
||||
display_element.querySelector('#jspsych-video-slider-response-stimulus').addEventListener('timeupdate', function(e){
|
||||
var currenttime = display_element.querySelector('#jspsych-video-slider-response-stimulus').currentTime;
|
||||
if(currenttime >= trial.stop){
|
||||
display_element.querySelector('#jspsych-video-slider-response-stimulus').pause();
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
display_element.querySelector('#jspsych-video-slider-response-stimulus').playbackRate = trial.rate;
|
||||
|
||||
if(trial.require_movement){
|
||||
display_element.querySelector('#jspsych-video-slider-response-response').addEventListener('change', function(){
|
||||
display_element.querySelector('#jspsych-video-slider-response-next').disabled = false;
|
||||
})
|
||||
}
|
||||
|
||||
var startTime = performance.now();
|
||||
|
||||
// store response
|
||||
var response = {
|
||||
rt: null,
|
||||
response: null
|
||||
};
|
||||
|
||||
display_element.querySelector('#jspsych-video-slider-response-next').addEventListener('click', function() {
|
||||
// measure response time
|
||||
var endTime = performance.now();
|
||||
response.rt = endTime - startTime;
|
||||
response.response = display_element.querySelector('#jspsych-video-slider-response-response').value;
|
||||
|
||||
if(trial.response_ends_trial){
|
||||
end_trial();
|
||||
} else {
|
||||
display_element.querySelector('#jspsych-video-slider-response-next').disabled = true;
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
// function to end trial when it is time
|
||||
function end_trial() {
|
||||
|
||||
// kill any remaining setTimeout handlers
|
||||
jsPsych.pluginAPI.clearAllTimeouts();
|
||||
|
||||
// gather the data to store for the trial
|
||||
var trial_data = {
|
||||
"rt": response.rt,
|
||||
"stimulus": trial.stimulus,
|
||||
"response": response.response
|
||||
};
|
||||
|
||||
// clear the display
|
||||
display_element.innerHTML = '';
|
||||
|
||||
// move on to the next trial
|
||||
jsPsych.finishTrial(trial_data);
|
||||
};
|
||||
|
||||
// end trial if time limit is set
|
||||
if (trial.trial_duration !== null) {
|
||||
jsPsych.pluginAPI.setTimeout(function() {
|
||||
end_trial();
|
||||
}, trial.trial_duration);
|
||||
}
|
||||
};
|
||||
|
||||
return plugin;
|
||||
})();
|
||||
259
PCSurvey/PCstatic/js/plugins/jspsych-visual-search-circle.js
Normal file
259
PCSurvey/PCstatic/js/plugins/jspsych-visual-search-circle.js
Normal file
@@ -0,0 +1,259 @@
|
||||
/**
|
||||
*
|
||||
* jspsych-visual-search-circle
|
||||
* Josh de Leeuw
|
||||
*
|
||||
* display a set of objects, with or without a target, equidistant from fixation
|
||||
* subject responds to whether or not the target is present
|
||||
*
|
||||
* based on code written for psychtoolbox by Ben Motz
|
||||
*
|
||||
* documentation: docs.jspsych.org
|
||||
*
|
||||
**/
|
||||
|
||||
jsPsych.plugins["visual-search-circle"] = (function() {
|
||||
|
||||
var plugin = {};
|
||||
|
||||
jsPsych.pluginAPI.registerPreload('visual-search-circle', 'target', 'image');
|
||||
jsPsych.pluginAPI.registerPreload('visual-search-circle', 'foil', 'image');
|
||||
jsPsych.pluginAPI.registerPreload('visual-search-circle', 'fixation_image', 'image');
|
||||
|
||||
plugin.info = {
|
||||
name: 'visual-search-circle',
|
||||
description: '',
|
||||
parameters: {
|
||||
target: {
|
||||
type: jsPsych.plugins.parameterType.IMAGE,
|
||||
pretty_name: 'Target',
|
||||
default: undefined,
|
||||
description: 'The image to be displayed.'
|
||||
},
|
||||
foil: {
|
||||
type: jsPsych.plugins.parameterType.IMAGE,
|
||||
pretty_name: 'Foil',
|
||||
default: undefined,
|
||||
description: 'Path to image file that is the foil/distractor.'
|
||||
},
|
||||
fixation_image: {
|
||||
type: jsPsych.plugins.parameterType.IMAGE,
|
||||
pretty_name: 'Fixation image',
|
||||
default: undefined,
|
||||
description: 'Path to image file that is a fixation target.'
|
||||
},
|
||||
set_size: {
|
||||
type: jsPsych.plugins.parameterType.INT,
|
||||
pretty_name: 'Set size',
|
||||
default: undefined,
|
||||
description: 'How many items should be displayed?'
|
||||
},
|
||||
target_present: {
|
||||
type: jsPsych.plugins.parameterType.BOOL,
|
||||
pretty_name: 'Target present',
|
||||
default: true,
|
||||
description: 'Is the target present?'
|
||||
},
|
||||
target_size: {
|
||||
type: jsPsych.plugins.parameterType.INT,
|
||||
pretty_name: 'Target size',
|
||||
array: true,
|
||||
default: [50, 50],
|
||||
description: 'Two element array indicating the height and width of the search array element images.'
|
||||
},
|
||||
fixation_size: {
|
||||
type: jsPsych.plugins.parameterType.INT,
|
||||
pretty_name: 'Fixation size',
|
||||
array: true,
|
||||
default: [16, 16],
|
||||
description: 'Two element array indicating the height and width of the fixation image.'
|
||||
},
|
||||
circle_diameter: {
|
||||
type: jsPsych.plugins.parameterType.INT,
|
||||
pretty_name: 'Circle diameter',
|
||||
default: 250,
|
||||
description: 'The diameter of the search array circle in pixels.'
|
||||
},
|
||||
target_present_key: {
|
||||
type: jsPsych.plugins.parameterType.KEYCODE,
|
||||
pretty_name: 'Target present key',
|
||||
default: 'j',
|
||||
description: 'The key to press if the target is present in the search array.'
|
||||
},
|
||||
target_absent_key: {
|
||||
type: jsPsych.plugins.parameterType.KEYCODE,
|
||||
pretty_name: 'Target absent key',
|
||||
default: 'f',
|
||||
description: 'The key to press if the target is not present in the search array.'
|
||||
},
|
||||
trial_duration: {
|
||||
type: jsPsych.plugins.parameterType.INT,
|
||||
pretty_name: 'Trial duration',
|
||||
default: null,
|
||||
description: 'The maximum duration to wait for a response.'
|
||||
},
|
||||
fixation_duration: {
|
||||
type: jsPsych.plugins.parameterType.INT,
|
||||
pretty_name: 'Fixation duration',
|
||||
default: 1000,
|
||||
description: 'How long to show the fixation image for before the search array (in milliseconds).'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
plugin.trial = function(display_element, trial) {
|
||||
|
||||
// circle params
|
||||
var diam = trial.circle_diameter; // pixels
|
||||
var radi = diam / 2;
|
||||
var paper_size = diam + trial.target_size[0];
|
||||
|
||||
// stimuli width, height
|
||||
var stimh = trial.target_size[0];
|
||||
var stimw = trial.target_size[1];
|
||||
var hstimh = stimh / 2;
|
||||
var hstimw = stimw / 2;
|
||||
|
||||
// fixation location
|
||||
var fix_loc = [Math.floor(paper_size / 2 - trial.fixation_size[0] / 2), Math.floor(paper_size / 2 - trial.fixation_size[1] / 2)];
|
||||
|
||||
// possible stimulus locations on the circle
|
||||
var display_locs = [];
|
||||
var possible_display_locs = trial.set_size;
|
||||
var random_offset = Math.floor(Math.random() * 360);
|
||||
for (var i = 0; i < possible_display_locs; i++) {
|
||||
display_locs.push([
|
||||
Math.floor(paper_size / 2 + (cosd(random_offset + (i * (360 / possible_display_locs))) * radi) - hstimw),
|
||||
Math.floor(paper_size / 2 - (sind(random_offset + (i * (360 / possible_display_locs))) * radi) - hstimh)
|
||||
]);
|
||||
}
|
||||
|
||||
// get target to draw on
|
||||
display_element.innerHTML += '<div id="jspsych-visual-search-circle-container" style="position: relative; width:' + paper_size + 'px; height:' + paper_size + 'px"></div>';
|
||||
var paper = display_element.querySelector("#jspsych-visual-search-circle-container");
|
||||
|
||||
// check distractors - array?
|
||||
if(!Array.isArray(trial.foil)){
|
||||
fa = [];
|
||||
for(var i=0; i<trial.set_size; i++){
|
||||
fa.push(trial.foil);
|
||||
}
|
||||
trial.foil = fa;
|
||||
}
|
||||
|
||||
show_fixation();
|
||||
|
||||
function show_fixation() {
|
||||
// show fixation
|
||||
//var fixation = paper.image(trial.fixation_image, fix_loc[0], fix_loc[1], trial.fixation_size[0], trial.fixation_size[1]);
|
||||
paper.innerHTML += "<img src='"+trial.fixation_image+"' style='position: absolute; top:"+fix_loc[0]+"px; left:"+fix_loc[1]+"px; width:"+trial.fixation_size[0]+"px; height:"+trial.fixation_size[1]+"px;'></img>";
|
||||
|
||||
// wait
|
||||
jsPsych.pluginAPI.setTimeout(function() {
|
||||
// after wait is over
|
||||
show_search_array();
|
||||
}, trial.fixation_duration);
|
||||
}
|
||||
|
||||
function show_search_array() {
|
||||
|
||||
var search_array_images = [];
|
||||
|
||||
var to_present = [];
|
||||
if(trial.target_present){
|
||||
to_present.push(trial.target);
|
||||
}
|
||||
to_present = to_present.concat(trial.foil);
|
||||
|
||||
for (var i = 0; i < display_locs.length; i++) {
|
||||
|
||||
paper.innerHTML += "<img src='"+to_present[i]+"' style='position: absolute; top:"+display_locs[i][0]+"px; left:"+display_locs[i][1]+"px; width:"+trial.target_size[0]+"px; height:"+trial.target_size[1]+"px;'></img>";
|
||||
|
||||
}
|
||||
|
||||
var trial_over = false;
|
||||
|
||||
var after_response = function(info) {
|
||||
|
||||
trial_over = true;
|
||||
|
||||
var correct = false;
|
||||
|
||||
if (jsPsych.pluginAPI.compareKeys(info.key,trial.target_present_key) && trial.target_present ||
|
||||
jsPsych.pluginAPI.compareKeys(info.key,trial.target_absent_key) && !trial.target_present) {
|
||||
correct = true;
|
||||
}
|
||||
|
||||
clear_display();
|
||||
|
||||
end_trial(info.rt, correct, info.key);
|
||||
|
||||
}
|
||||
|
||||
var valid_keys = [trial.target_present_key, trial.target_absent_key];
|
||||
|
||||
key_listener = jsPsych.pluginAPI.getKeyboardResponse({
|
||||
callback_function: after_response,
|
||||
valid_responses: valid_keys,
|
||||
rt_method: 'performance',
|
||||
persist: false,
|
||||
allow_held_key: false
|
||||
});
|
||||
|
||||
if (trial.trial_duration !== null) {
|
||||
|
||||
jsPsych.pluginAPI.setTimeout(function() {
|
||||
|
||||
if (!trial_over) {
|
||||
|
||||
jsPsych.pluginAPI.cancelKeyboardResponse(key_listener);
|
||||
|
||||
trial_over = true;
|
||||
|
||||
var rt = null;
|
||||
var correct = 0;
|
||||
var key_press = null;
|
||||
|
||||
clear_display();
|
||||
|
||||
end_trial(rt, correct, key_press);
|
||||
}
|
||||
}, trial.trial_duration);
|
||||
|
||||
}
|
||||
|
||||
function clear_display() {
|
||||
display_element.innerHTML = '';
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function end_trial(rt, correct, key_press) {
|
||||
|
||||
// data saving
|
||||
var trial_data = {
|
||||
correct: correct,
|
||||
rt: rt,
|
||||
key_press: key_press,
|
||||
locations: JSON.stringify(display_locs),
|
||||
target_present: trial.target_present,
|
||||
set_size: trial.set_size
|
||||
};
|
||||
|
||||
// go to next trial
|
||||
jsPsych.finishTrial(trial_data);
|
||||
}
|
||||
};
|
||||
|
||||
// helper function for determining stimulus locations
|
||||
|
||||
function cosd(num) {
|
||||
return Math.cos(num / 180 * Math.PI);
|
||||
}
|
||||
|
||||
function sind(num) {
|
||||
return Math.sin(num / 180 * Math.PI);
|
||||
}
|
||||
|
||||
return plugin;
|
||||
})();
|
||||
196
PCSurvey/PCstatic/js/plugins/jspsych-vsl-animate-occlusion.js
Normal file
196
PCSurvey/PCstatic/js/plugins/jspsych-vsl-animate-occlusion.js
Normal file
@@ -0,0 +1,196 @@
|
||||
/**
|
||||
* jsPsych plugin for showing animations that mimic the experiment described in
|
||||
*
|
||||
* Fiser, J., & Aslin, R. N. (2002). Statistical learning of higher-order
|
||||
* temporal structure from visual shape sequences. Journal of Experimental
|
||||
* Psychology: Learning, Memory, and Cognition, 28(3), 458.
|
||||
*
|
||||
* Josh de Leeuw
|
||||
*
|
||||
* documentation: docs.jspsych.org
|
||||
*
|
||||
*/
|
||||
|
||||
jsPsych.plugins['vsl-animate-occlusion'] = (function() {
|
||||
|
||||
var plugin = {};
|
||||
|
||||
jsPsych.pluginAPI.registerPreload('vsl-animate-occlusion', 'stimuli', 'image');
|
||||
|
||||
plugin.info = {
|
||||
name: 'vsl-animate-occlusion',
|
||||
description: '',
|
||||
parameters: {
|
||||
stimuli: {
|
||||
type: jsPsych.plugins.parameterType.IMAGE,
|
||||
pretty_name: 'Stimuli',
|
||||
default: undefined,
|
||||
array: true,
|
||||
description: 'A stimulus is a path to an image file.'
|
||||
},
|
||||
choices: {
|
||||
type: jsPsych.plugins.parameterType.KEYCODE,
|
||||
pretty_name: 'Choices',
|
||||
array: true,
|
||||
default: jsPsych.ALL_KEYS,
|
||||
description: 'This array contains the keys that the subject is allowed to press in order to respond to the stimulus. '
|
||||
},
|
||||
canvas_size: {
|
||||
type: jsPsych.plugins.parameterType.INT,
|
||||
pretty_name: 'Canvas size',
|
||||
array: true,
|
||||
default: [400,400],
|
||||
description: 'Array specifying the width and height of the area that the animation will display in.'
|
||||
},
|
||||
image_size: {
|
||||
type: jsPsych.plugins.parameterType.INT,
|
||||
pretty_name: 'Image size',
|
||||
array: true,
|
||||
default: [100,100],
|
||||
description: 'Array specifying the width and height of the images to show.'
|
||||
},
|
||||
initial_direction: {
|
||||
type: jsPsych.plugins.parameterType.SELECT,
|
||||
pretty_name: 'Initial direction',
|
||||
choices: ['left','right'],
|
||||
default: 'left',
|
||||
description: 'Which direction the stimulus should move first.'
|
||||
},
|
||||
occlude_center: {
|
||||
type: jsPsych.plugins.parameterType.BOOL,
|
||||
pretty_name: 'Occlude center',
|
||||
default: true,
|
||||
description: 'If true, display a rectangle in the center of the screen that is just wide enough to occlude the image completely as it passes behind.'
|
||||
},
|
||||
cycle_duration: {
|
||||
type: jsPsych.plugins.parameterType.INT,
|
||||
pretty_name: 'Cycle duration',
|
||||
default: 1000,
|
||||
description: 'How long it takes for a stimulus in the sequence to make a complete cycle.'
|
||||
},
|
||||
pre_movement_duration: {
|
||||
type: jsPsych.plugins.parameterType.INT,
|
||||
pretty_name: 'Pre movement duration',
|
||||
default: 500,
|
||||
description: 'How long to wait before the stimuli starts moving from behind the center rectangle.'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
plugin.trial = function(display_element, trial) {
|
||||
|
||||
// variable to keep track of timing info and responses
|
||||
var start_time = 0;
|
||||
var responses = [];
|
||||
|
||||
var directions = [
|
||||
[{
|
||||
params: {
|
||||
x: trial.canvas_size[0] - trial.image_size[0]
|
||||
},
|
||||
ms: trial.cycle_duration / 2
|
||||
}, {
|
||||
params: {
|
||||
x: trial.canvas_size[0] / 2 - trial.image_size[0] / 2
|
||||
},
|
||||
ms: trial.cycle_duration / 2
|
||||
}],
|
||||
[{
|
||||
params: {
|
||||
x: 0
|
||||
},
|
||||
ms: trial.cycle_duration / 2
|
||||
}, {
|
||||
params: {
|
||||
x: trial.canvas_size[0] / 2 - trial.image_size[0] / 2
|
||||
},
|
||||
ms: trial.cycle_duration / 2
|
||||
}]
|
||||
];
|
||||
|
||||
var which_image = 0;
|
||||
var next_direction = (trial.initial_direction == "right") ? 0 : 1;
|
||||
|
||||
function next_step() {
|
||||
if (trial.stimuli.length == which_image) {
|
||||
endTrial();
|
||||
} else {
|
||||
|
||||
var d = directions[next_direction];
|
||||
next_direction === 0 ? next_direction = 1 : next_direction = 0;
|
||||
var i = trial.stimuli[which_image];
|
||||
which_image++;
|
||||
|
||||
c.animate(d[0].params, d[0].ms, mina.linear, function() {
|
||||
c.animate(d[1].params, d[1].ms, mina.linear, function() {
|
||||
next_step();
|
||||
});
|
||||
});
|
||||
|
||||
c.attr({
|
||||
href: i
|
||||
});
|
||||
|
||||
// start timer for this trial
|
||||
start_time = performance.now();
|
||||
}
|
||||
}
|
||||
|
||||
display_element.innerHTML = "<svg id='jspsych-vsl-animate-occlusion-canvas' width=" + trial.canvas_size[0] + " height=" + trial.canvas_size[1] + "></svg>";
|
||||
|
||||
var paper = Snap("#jspsych-vsl-animate-occlusion-canvas");
|
||||
|
||||
var c = paper.image(trial.stimuli[which_image], trial.canvas_size[0] / 2 - trial.image_size[0] / 2, trial.canvas_size[1] / 2 - trial.image_size[1] / 2, trial.image_size[0], trial.image_size[1]).attr({
|
||||
"id": 'jspsych-vsl-animate-occlusion-moving-image'
|
||||
});
|
||||
|
||||
display_element.querySelector('#jspsych-vsl-animate-occlusion-moving-image').removeAttribute('preserveAspectRatio');
|
||||
|
||||
if (trial.occlude_center) {
|
||||
paper.rect((trial.canvas_size[0] / 2) - (trial.image_size[0] / 2), 0, trial.image_size[0], trial.canvas_size[1]).attr({
|
||||
fill: "#000"
|
||||
});
|
||||
}
|
||||
|
||||
// add key listener
|
||||
var after_response = function(info) {
|
||||
responses.push({
|
||||
key: info.key,
|
||||
stimulus: which_image - 1,
|
||||
rt: info.rt
|
||||
});
|
||||
}
|
||||
|
||||
key_listener = jsPsych.pluginAPI.getKeyboardResponse({
|
||||
callback_function: after_response,
|
||||
valid_responses: trial.choices,
|
||||
rt_method: 'performance',
|
||||
persist: true,
|
||||
allow_held_key: false
|
||||
});
|
||||
|
||||
if (trial.pre_movement_duration > 0) {
|
||||
jsPsych.pluginAPI.setTimeout(function() {
|
||||
next_step();
|
||||
}, trial.pre_movement_duration);
|
||||
} else {
|
||||
next_step();
|
||||
}
|
||||
|
||||
function endTrial() {
|
||||
|
||||
display_element.innerHTML = '';
|
||||
|
||||
jsPsych.pluginAPI.cancelKeyboardResponse(key_listener);
|
||||
|
||||
var trial_data = {
|
||||
"stimuli": JSON.stringify(trial.stimuli),
|
||||
"responses": JSON.stringify(responses)
|
||||
};
|
||||
|
||||
jsPsych.finishTrial(trial_data);
|
||||
}
|
||||
};
|
||||
|
||||
return plugin;
|
||||
})();
|
||||
103
PCSurvey/PCstatic/js/plugins/jspsych-vsl-grid-scene.js
Normal file
103
PCSurvey/PCstatic/js/plugins/jspsych-vsl-grid-scene.js
Normal file
@@ -0,0 +1,103 @@
|
||||
/**
|
||||
* jsPsych plugin for showing scenes that mimic the experiments described in
|
||||
*
|
||||
* Fiser, J., & Aslin, R. N. (2001). Unsupervised statistical learning of
|
||||
* higher-order spatial structures from visual scenes. Psychological science,
|
||||
* 12(6), 499-504.
|
||||
*
|
||||
* Josh de Leeuw
|
||||
*
|
||||
* documentation: docs.jspsych.org
|
||||
*
|
||||
*/
|
||||
|
||||
jsPsych.plugins['vsl-grid-scene'] = (function() {
|
||||
|
||||
var plugin = {};
|
||||
|
||||
jsPsych.pluginAPI.registerPreload('vsl-grid-scene', 'stimuli', 'image');
|
||||
|
||||
plugin.info = {
|
||||
name: 'vsl-grid-scene',
|
||||
description: '',
|
||||
parameters: {
|
||||
stimuli: {
|
||||
type: jsPsych.plugins.parameterType.IMAGE,
|
||||
pretty_name: 'Stimuli',
|
||||
array: true,
|
||||
default: undefined,
|
||||
description: 'An array that defines a grid.'
|
||||
},
|
||||
image_size: {
|
||||
type: jsPsych.plugins.parameterType.INT,
|
||||
pretty_name: 'Image size',
|
||||
array: true,
|
||||
default: [100,100],
|
||||
description: 'Array specifying the width and height of the images to show.'
|
||||
},
|
||||
trial_duration: {
|
||||
type: jsPsych.plugins.parameterType.INT,
|
||||
pretty_name: 'Trial duration',
|
||||
default: 2000,
|
||||
description: 'How long to show the stimulus for in milliseconds.'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
plugin.trial = function(display_element, trial) {
|
||||
|
||||
display_element.innerHTML = plugin.generate_stimulus(trial.stimuli, trial.image_size);
|
||||
|
||||
jsPsych.pluginAPI.setTimeout(function() {
|
||||
endTrial();
|
||||
}, trial.trial_duration);
|
||||
|
||||
function endTrial() {
|
||||
|
||||
display_element.innerHTML = '';
|
||||
|
||||
var trial_data = {
|
||||
"stimulus": JSON.stringify(trial.stimuli)
|
||||
};
|
||||
|
||||
jsPsych.finishTrial(trial_data);
|
||||
}
|
||||
};
|
||||
|
||||
plugin.generate_stimulus = function(pattern, image_size) {
|
||||
var nrows = pattern.length;
|
||||
var ncols = pattern[0].length;
|
||||
|
||||
// create blank element to hold code that we generate
|
||||
var html = '<div id="jspsych-vsl-grid-scene-dummy" css="display: none;">';
|
||||
|
||||
// create table
|
||||
html += '<table id="jspsych-vsl-grid-scene table" '+
|
||||
'style="border-collapse: collapse; margin-left: auto; margin-right: auto;">';
|
||||
|
||||
for (var row = 0; row < nrows; row++) {
|
||||
html += '<tr id="jspsych-vsl-grid-scene-table-row-'+row+'" css="height: '+image_size[1]+'px;">';
|
||||
|
||||
for (var col = 0; col < ncols; col++) {
|
||||
html += '<td id="jspsych-vsl-grid-scene-table-' + row + '-' + col +'" '+
|
||||
'style="padding: '+ (image_size[1] / 10) + 'px ' + (image_size[0] / 10) + 'px; border: 1px solid #555;">'+
|
||||
'<div id="jspsych-vsl-grid-scene-table-cell-' + row + '-' + col + '" style="width: '+image_size[0]+'px; height: '+image_size[1]+'px;">';
|
||||
if (pattern[row][col] !== 0) {
|
||||
html += '<img '+
|
||||
'src="'+pattern[row][col]+'" style="width: '+image_size[0]+'px; height: '+image_size[1]+'"></img>';
|
||||
}
|
||||
html += '</div>';
|
||||
html += '</td>';
|
||||
}
|
||||
html += '</tr>';
|
||||
}
|
||||
|
||||
html += '</table>';
|
||||
html += '</div>';
|
||||
|
||||
return html;
|
||||
|
||||
};
|
||||
|
||||
return plugin;
|
||||
})();
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Example plugin template
|
||||
*/
|
||||
|
||||
jsPsych.plugins["PLUGIN-NAME"] = (function() {
|
||||
|
||||
var plugin = {};
|
||||
|
||||
plugin.info = {
|
||||
name: "PLUGIN-NAME",
|
||||
parameters: {
|
||||
parameter_name: {
|
||||
type: jsPsych.plugins.parameterType.INT, // BOOL, STRING, INT, FLOAT, FUNCTION, KEYCODE, SELECT, HTML_STRING, IMAGE, AUDIO, VIDEO, OBJECT, COMPLEX
|
||||
default: undefined
|
||||
},
|
||||
parameter_name: {
|
||||
type: jsPsych.plugins.parameterType.IMAGE,
|
||||
default: undefined
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
plugin.trial = function(display_element, trial) {
|
||||
|
||||
// data saving
|
||||
var trial_data = {
|
||||
parameter_name: 'parameter value'
|
||||
};
|
||||
|
||||
// end trial
|
||||
jsPsych.finishTrial(trial_data);
|
||||
};
|
||||
|
||||
return plugin;
|
||||
})();
|
||||
Reference in New Issue
Block a user