Merge pull request #399 from kristiyip/master

fixed IAT plugin and doc
This commit is contained in:
Josh de Leeuw 2017-06-21 11:32:15 -04:00 committed by GitHub
commit 2f85187ec9
7 changed files with 222 additions and 103 deletions

View File

@ -12,8 +12,9 @@ Parameter | Type | Default Value | Description
----------|------|---------------|------------ ----------|------|---------------|------------
stimulus | string | *undefined* | The stimulus to display. Either HTML-formatted, or the path to an image. stimulus | string | *undefined* | The stimulus to display. Either HTML-formatted, or the path to an image.
is_html | boolean | false | If `stimulus` is an HTML-formatted string, this parameter needs to be set to `true`. is_html | boolean | false | If `stimulus` is an HTML-formatted string, this parameter needs to be set to `true`.
image_when_wrong | string | *undefined* | Displays image feedback when user presses wrong key. Only needed when display_feedback == true. htm_when_wrong | string | '<span style="color: red; font-size: 80px">X</span>' | The image to display when a user presses the wrong key.
wrong_image_name | string | 'wrong image' | The name associated with image_when_wrong. bottom_instructions | string | "<p>If you press the wrong key, a red X will appear. Press any key to continue.</p>" | Instructions about making a wrong key press and whether another key press is needed to continue.
force_correct_key_press | boolean | false | If this is true and the user presses the wrong key then they have to press the other key to continue. An example would be two keys 'E' and 'I'. If the key associated with the stimulus is 'E' and key 'I' was pressed, then pressing 'E' is needed to continue the trial. When this is true, then parameter key_to_move_forward is not used.
display_feedback | boolean | false | If true, then image_when_wrong and wrong_image_name is required. If false, timing_response is needed and trial will continue automatically. display_feedback | boolean | false | If true, then image_when_wrong and wrong_image_name is required. If false, timing_response is needed and trial will continue automatically.
left_category_key | string | 'E' | Key press that is associated with the left_category_label. left_category_key | string | 'E' | Key press that is associated with the left_category_label.
right_category_key | string | 'I' | Key press that is associated with the right_category_label. right_category_key | string | 'I' | Key press that is associated with the right_category_label.
@ -43,15 +44,15 @@ var trial_block = {
stimulus: 'img/blue.png', stimulus: 'img/blue.png',
stim_key_association: 'left', stim_key_association: 'left',
is_html: false, is_html: false,
image_when_wrong: 'img/redX.png', html_when_wrong: '<span style="color: red; font-size: 80px">X</span>',
wrong_image_name: 'red X', bottom_instructions: '<p>If you press the wrong key, a red X will appear. Press the other key to continue</p>',
force_correct_key_press: true,
display_feedback: true, display_feedback: true,
timing_response: 3000, //Only if display_feedback is false timing_response: 3000, //Only if display_feedback is false
left_category_key: 'E', left_category_key: 'E',
right_category_key: 'I', right_category_key: 'I',
left_category_label: ['OLD'], left_category_label: ['OLD'],
right_category_label: ['YOUNG'], right_category_label: ['YOUNG'],
key_to_move_forward: [jsPsych.ALL_KEYS],
response_ends_trial: true response_ends_trial: true
} }

View File

@ -60,15 +60,15 @@ var trial_block = {
stimulus: jsPsych.timelineVariable('stimulus'), stimulus: jsPsych.timelineVariable('stimulus'),
stim_key_association: jsPsych.timelineVariable('stim_key_association'), stim_key_association: jsPsych.timelineVariable('stim_key_association'),
is_html: false, is_html: false,
image_when_wrong: 'img/redX.png', html_when_wrong: '<span style="color: red; font-size: 80px">X</span>',
wrong_image_name: 'red X', bottom_instructions: '<p>If you press the wrong key, a red X will appear. Press the other key to continue</p>',
force_correct_key_press: true,
display_feedback: true, display_feedback: true,
timing_response: 3000, //Only if display_feedback is false timing_response: 3000, //Only if display_feedback is false
left_category_key: 'E', left_category_key: 'E',
right_category_key: 'I', right_category_key: 'I',
left_category_label: ['OLD'], left_category_label: ['OLD'],
right_category_label: ['YOUNG'], right_category_label: ['YOUNG'],
key_to_move_forward: [jsPsych.ALL_KEYS],
response_ends_trial: true response_ends_trial: true
} }
], ],
@ -110,15 +110,15 @@ var trial_block2 = {
is_html: true, is_html: true,
stimulus: jsPsych.timelineVariable('stimulus'), stimulus: jsPsych.timelineVariable('stimulus'),
stim_key_association: jsPsych.timelineVariable('stim_key_association'), stim_key_association: jsPsych.timelineVariable('stim_key_association'),
image_when_wrong: 'img/redX.png', html_when_wrong: '<span style="color: red; font-size: 80px">X</span>',
wrong_image_name: 'red X', bottom_instructions: '<p>If you press the wrong key, a red X will appear. Press the other key to continue</p>',
force_correct_key_press: true,
display_feedback: true, display_feedback: true,
timing_response: 3000, //Only if display_feedback is false timing_response: 3000, //Only if display_feedback is false
left_category_key: 'E', left_category_key: 'E',
right_category_key: 'I', right_category_key: 'I',
left_category_label: ['BAD'], left_category_label: ['BAD'],
right_category_label: ['GOOD'], right_category_label: ['GOOD'],
key_to_move_forward: [jsPsych.ALL_KEYS],
response_ends_trial: true response_ends_trial: true
} }
], ],
@ -164,15 +164,15 @@ var trial_block3 = {
is_html: jsPsych.timelineVariable('is_html'), is_html: jsPsych.timelineVariable('is_html'),
stimulus: jsPsych.timelineVariable('stimulus'), stimulus: jsPsych.timelineVariable('stimulus'),
stim_key_association: jsPsych.timelineVariable('stim_key_association'), stim_key_association: jsPsych.timelineVariable('stim_key_association'),
image_when_wrong: 'img/redX.png', html_when_wrong: '<span style="color: red; font-size: 80px">X</span>',
wrong_image_name: 'red X', bottom_instructions: '<p>If you press the wrong key, a red X will appear. Press the other key to continue</p>',
force_correct_key_press: true,
display_feedback: true, display_feedback: true,
timing_response: 3000, //Only if display_feedback is false timing_response: 3000, //Only if display_feedback is false
left_category_key: 'E', left_category_key: 'E',
right_category_key: 'I', right_category_key: 'I',
left_category_label: ['BAD', 'OLD'], left_category_label: ['BAD', 'OLD'],
right_category_label: ['GOOD', 'YOUNG'], right_category_label: ['GOOD', 'YOUNG'],
key_to_move_forward: [jsPsych.ALL_KEYS],
response_ends_trial: true response_ends_trial: true
} }
], ],
@ -230,15 +230,15 @@ var trial_block4 = {
is_html: jsPsych.timelineVariable('is_html'), is_html: jsPsych.timelineVariable('is_html'),
stimulus: jsPsych.timelineVariable('stimulus'), stimulus: jsPsych.timelineVariable('stimulus'),
stim_key_association: jsPsych.timelineVariable('stim_key_association'), stim_key_association: jsPsych.timelineVariable('stim_key_association'),
image_when_wrong: 'img/redX.png', html_when_wrong: '<span style="color: red; font-size: 80px">X</span>',
wrong_image_name: 'red X', bottom_instructions: '<p>If you press the wrong key, a red X will appear. Press the other key to continue</p>',
force_correct_key_press: true,
display_feedback: true, display_feedback: true,
timing_response: 3000, //Only if display_feedback is false timing_response: 3000, //Only if display_feedback is false
left_category_key: 'E', left_category_key: 'E',
right_category_key: 'I', right_category_key: 'I',
left_category_label: ['BAD', 'OLD'], left_category_label: ['BAD', 'OLD'],
right_category_label: ['GOOD', 'YOUNG'], right_category_label: ['GOOD', 'YOUNG'],
key_to_move_forward: [jsPsych.ALL_KEYS],
response_ends_trial: true response_ends_trial: true
} }
], ],
@ -294,15 +294,15 @@ var trial_block4 = {
is_html: false, is_html: false,
stimulus: jsPsych.timelineVariable('stimulus'), stimulus: jsPsych.timelineVariable('stimulus'),
stim_key_association: jsPsych.timelineVariable('stim_key_association'), stim_key_association: jsPsych.timelineVariable('stim_key_association'),
image_when_wrong: 'img/redX.png', html_when_wrong: '<span style="color: red; font-size: 80px">X</span>',
wrong_image_name: 'red X', bottom_instructions: '<p>If you press the wrong key, a red X will appear. Press the other key to continue</p>',
force_correct_key_press: true,
display_feedback: true, display_feedback: true,
timing_response: 3000, //Only if display_feedback is false timing_response: 3000, //Only if display_feedback is false
left_category_key: 'E', left_category_key: 'E',
right_category_key: 'I', right_category_key: 'I',
left_category_label: ['YOUNG'], left_category_label: ['YOUNG'],
right_category_label: ['OLD'], right_category_label: ['OLD'],
key_to_move_forward: [jsPsych.ALL_KEYS],
response_ends_trial: true response_ends_trial: true
} }
], ],
@ -343,15 +343,16 @@ var trial_block4 = {
is_html: jsPsych.timelineVariable('is_html'), is_html: jsPsych.timelineVariable('is_html'),
stimulus: jsPsych.timelineVariable('stimulus'), stimulus: jsPsych.timelineVariable('stimulus'),
stim_key_association: jsPsych.timelineVariable('stim_key_association'), stim_key_association: jsPsych.timelineVariable('stim_key_association'),
image_when_wrong: 'img/redX.png', html_when_wrong: '<span style="color: red; font-size: 80px">X</span>',
wrong_image_name: 'red X', bottom_instructions: '<p>If you press the wrong key, a red X will appear. Press the other key to continue</p>',
force_correct_key_press: true,
display_feedback: true, display_feedback: true,
timing_response: 3000, //Only if display_feedback is false timing_response: 3000, //Only if display_feedback is false
left_category_key: 'E', left_category_key: 'E',
right_category_key: 'I', right_category_key: 'I',
left_category_label: ['BAD', 'OLD'], left_category_label: ['BAD', 'OLD'],
right_category_label: ['GOOD', 'YOUNG'], right_category_label: ['GOOD', 'YOUNG'],
key_to_move_forward: [jsPsych.ALL_KEYS], response_ends_trial: true
} }
], ],
timeline_variables: [ timeline_variables: [
@ -419,22 +420,22 @@ var trial_block4 = {
}; };
var timeline = []; var timeline = [];
// timeline.push(welcome_block); timeline.push(welcome_block);
// timeline.push(category_block); timeline.push(category_block);
//timeline.push(instructions_block); timeline.push(instructions_block);
timeline.push(trial_block); timeline.push(trial_block);
// timeline.push(instructions_block2); timeline.push(instructions_block2);
// timeline.push(trial_block2); timeline.push(trial_block2);
// timeline.push(instructions_block3); timeline.push(instructions_block3);
// timeline.push(trial_block3); timeline.push(trial_block3);
// timeline.push(instructions_block4); timeline.push(instructions_block4);
// timeline.push(trial_block4); timeline.push(trial_block4);
// timeline.push(instructions_block5); timeline.push(instructions_block5);
// timeline.push(trial_block5); timeline.push(trial_block5);
// timeline.push(instructions_block6); timeline.push(instructions_block6);
// timeline.push(trial_block6); timeline.push(trial_block6);
// timeline.push(instructions_block7); timeline.push(instructions_block7);
// timeline.push(trial_block6); timeline.push(trial_block6);
timeline.push(debrief_block); timeline.push(debrief_block);
jsPsych.init({ jsPsych.init({

View File

@ -32,8 +32,9 @@
// set default values for the parameters // set default values for the parameters
trial.display_feedback = typeof trial.display_feedback == 'undefined' ? false : trial.display_feedback; trial.display_feedback = typeof trial.display_feedback == 'undefined' ? false : trial.display_feedback;
trial.image_when_wrong = trial.image_when_wrong || 'undefined'; trial.html_when_wrong = trial.html_when_wrong || '<span style="color: red; font-size: 80px">X</span>';
trial.wrong_image_name = trial.wrong_image_name || 'wrong image'; trial.bottom_instructions = trial.bottom_instructions || "<p>If you press the wrong key, a red X will appear. Press any key to continue.</p>";
trial.force_correct_key_press = trial.force_correct_key_press || false; //If true, key_to_move_forward is no longer needed
trial.left_category_key = trial.left_category_key || 'E'; trial.left_category_key = trial.left_category_key || 'E';
trial.right_category_key = trial.right_category_key || 'I'; trial.right_category_key = trial.right_category_key || 'I';
trial.left_category_label = trial.left_category_label || ['left']; trial.left_category_label = trial.left_category_label || ['left'];
@ -43,13 +44,6 @@
trial.timing_response = trial.timing_response || -1; trial.timing_response = trial.timing_response || -1;
trial.key_to_move_forward = trial.key_to_move_forward || jsPsych.ALL_KEYS; trial.key_to_move_forward = trial.key_to_move_forward || jsPsych.ALL_KEYS;
//Get keys to continue and put them in a string
var keysToContinue = "";
var lastKey = trial.key_to_move_forward.length - 1;
for(var i = 0; i < lastKey; i++) {
keysToContinue += trial.key_to_move_forward[i] + ", ";
}
var html_str = ""; var html_str = "";
if (!trial.is_html) { if (!trial.is_html) {
@ -82,47 +76,11 @@
html_str += "<div id='wrongImgID' style='position:relative; top: 300px; margin-left: auto; margin-right: auto; left: 0; right: 0'>"; html_str += "<div id='wrongImgID' style='position:relative; top: 300px; margin-left: auto; margin-right: auto; left: 0; right: 0'>";
if(!trial.response_ends_trial && trial.display_feedback == true) { 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'><img src='" + trial.image_when_wrong + "' id='wrongImgID'></img></div>"; 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>";
var wImg = document.getElementById("wrongImgContainer"); html_str += "<div>"+trial.bottom_instructions+"</div>";
html_str += "<p>Trial will continue automatically.</p>";
}
if(!trial.response_ends_trial && !trial.display_feedback) {
html_str += "<p>Trial will continue automatically.</p>";
}
if(trial.response_ends_trial && 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'><img src='" + trial.image_when_wrong + "' id='wrongImgID'></img></div>";
var wImg = document.getElementById("wrongImgContainer");
//wImg.style.visibility = "hidden";
if(trial.key_to_move_forward.length == 1) {
if(trial.key_to_move_forward[0] == "other key") {
html_str += "<p>If you press the wrong key, a " + trial.wrong_image_name + " will appear. Press the other key to continue.</p>"
} else if(trial.key_to_move_forward[0] == jsPsych.ALL_KEYS) {
html_str += "<p>If you press the wrong key, a " + trial.wrong_image_name + " will appear. Press any key to continue.</p>"
} else { } else {
html_str += "<p>If you press the wrong key, a " + trial.wrong_image_name + " will appear. Press " + trial.key_to_move_forward[0] + " to continue.</p>"; html_str += "<div>"+trial.bottom_instructions+"</div>";
}
} else {
html_str += "<p>If you press the wrong key, a " + trial.wrong_image_name + " will appear. Press " +
keysToContinue + " " + trial.key_to_move_forward[lastKey] + " to continue.</p>";
}
} else if (trial.response_ends_trial && trial.display_feedback != true) {
html_str += "<div id='wrongImgContainer' style='position: absolute; top: -75px; margin-left: auto; margin-right: auto; left: 0; right: 0'></div>";
if(trial.key_to_move_forward.length == 1) {
if(trial.key_to_move_forward[0] == "other key") {
html_str += "<p>If you press the wrong key, press the other key to continue.</p>"
} else if(trial.key_to_move_forward[0] == jsPsych.ALL_KEYS) {
html_str += "<p>If you press the wrong key, press any key to continue.</p>"
} else {
html_str += "<p>If you press the wrong key, press " + trial.key_to_move_forward[0] + " to continue.</p>";
}
} else {
html_str += "<p>If you press the wrong key, press " +
keysToContinue + " " + trial.key_to_move_forward[lastKey] + " to continue.</p>";
}
} }
html_str += "</div>"; html_str += "</div>";
@ -191,7 +149,7 @@
} }
if (trial.response_ends_trial && trial.display_feedback == true) { if (trial.response_ends_trial && trial.display_feedback == true) {
wImg.style.visibility = "visible"; wImg.style.visibility = "visible";
if(trial.key_to_move_forward[0] == "other key") { if(trial.force_correct_key_press) {
var keyListener = jsPsych.pluginAPI.getKeyboardResponse({ var keyListener = jsPsych.pluginAPI.getKeyboardResponse({
callback_function: end_trial, callback_function: end_trial,
valid_responses: [trial.right_category_key] valid_responses: [trial.right_category_key]
@ -207,7 +165,7 @@
valid_responses: [jsPsych.ALL_KEYS] valid_responses: [jsPsych.ALL_KEYS]
}); });
} else if(!trial.response_ends_trial && trial.display_feedback != true) { } else if(!trial.response_ends_trial && trial.display_feedback != true) {
// end_trial();
} }
} }
} else if(trial.stim_key_association == "left") { } else if(trial.stim_key_association == "left") {
@ -223,7 +181,7 @@
} }
if (trial.response_ends_trial && trial.display_feedback == true) { if (trial.response_ends_trial && trial.display_feedback == true) {
wImg.style.visibility = "visible"; wImg.style.visibility = "visible";
if(trial.key_to_move_forward[0] == "other key") { if(trial.force_correct_key_press) {
var keyListener = jsPsych.pluginAPI.getKeyboardResponse({ var keyListener = jsPsych.pluginAPI.getKeyboardResponse({
callback_function: end_trial, callback_function: end_trial,
valid_responses: [trial.left_category_key] valid_responses: [trial.left_category_key]
@ -239,7 +197,7 @@
valid_responses: [jsPsych.ALL_KEYS] valid_responses: [jsPsych.ALL_KEYS]
}); });
} else if(!trial.response_ends_trial && trial.display_feedback != true) { } else if(!trial.response_ends_trial && trial.display_feedback != true) {
// end_trial();
} }
} }
} }

View File

@ -13,4 +13,19 @@ describe('animation plugin', function(){
expect(typeof window.jsPsych.plugins['animation']).not.toBe('undefined'); expect(typeof window.jsPsych.plugins['animation']).not.toBe('undefined');
}); });
test('displays stimuli', function(){
var animation_sequence = ['img/face_1.jpg', 'img/face_2.jpg'];
var trial = {
type: 'animation',
stimuli: animation_sequence
}
jsPsych.init({
timeline: [trial]
});
expect(jsPsych.getDisplayElement().innerHTML).toMatch('<img src="img/face_1.jpg" id="jspsych-animation-image"></img>');
});
}); });

View File

@ -2,7 +2,7 @@ const root = '../../';
jest.useFakeTimers(); jest.useFakeTimers();
describe('iat plugin', function(){ describe('button-response', function(){
beforeEach(function(){ beforeEach(function(){
require(root + 'jspsych.js'); require(root + 'jspsych.js');
@ -13,4 +13,127 @@ describe('iat plugin', function(){
expect(typeof window.jsPsych.plugins['button-response']).not.toBe('undefined'); expect(typeof window.jsPsych.plugins['button-response']).not.toBe('undefined');
}); });
test('displays image by default', function(){
var trial = {
type: 'button-response',
stimulus: '../media/blue.png'
}
jsPsych.init({
timeline: [trial]
});
expect(jsPsych.getDisplayElement().innerHTML).toBe('<img src="../media/blue.png" id="jspsych-button-response-stimulus">')
});
test('displays html when is_html is true', function(){
var trial = {
type: 'button-response',
stimulus: '<p>button</p>',
choices: ['HAPPY'],
is_html: true,
}
jsPsych.init({
timeline: [trial]
});
expect(jsPsych.getDisplayElement().innerHTML).toMatch('<div id=\"jspsych-button-response-stimulus\"><p>button</p></div>');
});
test('displays buttons in button array', function(){
var trial = {
type: 'button-response',
button_html: ['img/button1.png', 'img/button2.png'],
choices: ['HAPPY', 'SAD'],
}
jsPsych.init({
timeline: [trial]
});
expect(jsPsych.getDisplayElement().innerHTML).toMatch(new RegExp('<div class=\"jspsych-button-response-button\" style=\"display: inline-block; margin:0px 8px\" id=\"jspsych-button-response-button-0\" data-choice=\"0\">img/button1.png</div><div class=\"jspsych-button-response-button\" style=\"display: inline-block; margin:0px 8px\" id=\"jspsych-button-response-button-1\" data-choice=\"1\">img/button2.png</div>'));
});
test('prompt should append html below stimulus', function(){
var trial = {
type: 'button-response',
stimulus: '<p>hello</p>',
is_html: true,
choices: ['HAPPY'],
prompt: '<div id="foo">this is the prompt</div>'
}
jsPsych.init({
timeline: [trial]
});
expect(jsPsych.getDisplayElement().innerHTML).toMatch('<div id=\"foo\">this is the prompt</div>');
});
test('timing_stim should set visibility of content to hidden after time has elapsed', function(){
var trial = {
type: 'button-response',
stimulus: '<p>hello</p>',
is_html: true,
choices: ['HAPPY'],
timing_stim: 500
}
jsPsych.init({
timeline: [trial]
});
expect(jsPsych.getDisplayElement().innerHTML).toMatch('<div id="jspsych-button-response-stimulus"><p>hello</p></div>');
jest.runAllTimers();
expect(jsPsych.getDisplayElement().innerHTML).toMatch('<div id="jspsych-button-response-stimulus" style="visibility: hidden;"><p>hello</p></div>');
});
test('timing_response should end trial after time has elapsed', function(){
var trial = {
type: 'button-response',
stimulus: '<p>hello</p>',
is_html: true,
choices: ['HAPPY'],
timing_response: 500
}
jsPsych.init({
timeline: [trial]
});
expect(jsPsych.getDisplayElement().innerHTML).toMatch('<div id="jspsych-button-response-stimulus"><p>hello</p></div>');
jest.runAllTimers();
expect(jsPsych.getDisplayElement().innerHTML).toBe('');
});
test('trial should not end when response_ends_trial is false and stimulus should get responded class', function(){
var trial = {
type: 'button-response',
stimulus: '<p>hello</p>',
is_html: true,
choices: ['HAPPY'],
response_ends_trial: false,
timing_response: 500
}
jsPsych.init({
timeline: [trial]
});
document.querySelector('#jspsych-button-response-button-0').click();
expect(jsPsych.getDisplayElement().innerHTML).toBe('<div id="jspsych-single-stim-stimulus" class=" responded"><p>hello</p');
jest.runAllTimers();
});
}); });

View File

@ -13,4 +13,21 @@ describe('call-function plugin', function(){
expect(typeof window.jsPsych.plugins['call-function']).not.toBe('undefined'); expect(typeof window.jsPsych.plugins['call-function']).not.toBe('undefined');
}); });
test('calls function', function(){
var myFunc = function() {
return '<p>I am a function</p>';
}
var trial = {
type: 'call-function',
func: myFunc
}
jsPsych.init({
timeline: [trial]
});
expect(jsPsych.getDisplayElement().innerHTML).toBe("");
});
}); });

View File

@ -3,7 +3,11 @@ exports.pressKey = function(key){
document.querySelector('.jspsych-display-element').dispatchEvent(new KeyboardEvent('keyup', {keyCode: key})); document.querySelector('.jspsych-display-element').dispatchEvent(new KeyboardEvent('keyup', {keyCode: key}));
} }
exports.clickTarget = function(target){ exports.mouseDownMouseUpTarget = function(target){
target.dispatchEvent(new MouseEvent('mousedown', {bubbles: true, detail: {target: target}})); target.dispatchEvent(new MouseEvent('mousedown', {bubbles: true}));
target.dispatchEvent(new MouseEvent('mouseup', {bubbles: true, detail: {target: target}})); target.dispatchEvent(new MouseEvent('mouseup', {bubbles: true}));
}
exports.clickTarget = function(target){
target.dispatchEvent(new MouseEvent('click', {bubbles: true}));
} }