/**
* jspsych-maxdiff
* Angus Hughes
*
* a jspsych plugin for maxdiff/conjoint analysis designs
*
*/
jsPsych.plugins['maxdiff'] = (function () {
var plugin = {};
plugin.info = {
name: 'maxdiff',
description: '',
parameters: {
alternatives: {
type: jsPsych.plugins.parameterType.STRING,
pretty_name: 'Alternatives',
array: true,
default: undefined,
description: 'Alternatives presented in the maxdiff table.'
},
labels: {
type: jsPsych.plugins.parameterType.STRING,
array: true,
pretty_name: 'Labels',
default: undefined,
description: 'Labels to display for left and right response columns.'
},
randomize_alternative_order: {
type: jsPsych.plugins.parameterType.BOOL,
pretty_name: 'Randomize Alternative Order',
default: false,
description: 'If true, the order of the alternatives will be randomized'
},
preamble: {
type: jsPsych.plugins.parameterType.STRING,
pretty_name: 'Preamble',
default: '',
description: 'String to display at top of the page.'
},
button_label: {
type: jsPsych.plugins.parameterType.STRING,
pretty_name: 'Button Label',
default: 'Continue',
description: 'Label of the button.'
},
required: {
type: jsPsych.plugins.parameterType.BOOL,
pretty_name: 'Required',
default: false,
description: 'Makes answering the alternative required.'
}
}
}
plugin.trial = function (display_element, trial) {
var html = "";
// inject CSS for trial
html += '';
// show preamble text
if (trial.preamble !== null) {
html += '
' + trial.preamble + '
';
}
html += '';
display_element.innerHTML = html;
// function to control responses
// first checks that the same alternative cannot be endorsed in the left and right columns simultaneously.
// then enables the submit button if the trial is required.
const left_right = ["left", "right"]
left_right.forEach(function(p) {
// Get all elements either 'left' or 'right'
document.getElementsByName(p).forEach(function(alt) {
alt.addEventListener('click', function() {
// Find the opposite (if left, then right & vice versa) identified by the class (jspsych-maxdiff-alt-1, 2, etc)
var op = alt.name == 'left' ? 'right' : 'left';
var n = document.getElementsByClassName(alt.className).namedItem(op);
// If it's checked, uncheck it.
if (n.checked) {
n.checked = false;
}
// check response
if (trial.required){
// Now check if one of both left and right have been enabled to allow submission
var left_checked = [...document.getElementsByName('left')].some(c => c.checked);
var right_checked = [...document.getElementsByName('right')].some(c => c.checked);
if (left_checked && right_checked) {
document.getElementById("jspsych-maxdiff-next").disabled = false;
} else {
document.getElementById("jspsych-maxdiff-next").disabled = true;
}
}
});
});
});
// Get the data once the submit button is clicked
// Get the data once the submit button is clicked
display_element.querySelector('#jspsych-maxdiff-form').addEventListener('submit', function(e){
e.preventDefault();
// measure response time
var endTime = performance.now();
var response_time = endTime - startTime;
// get the alternative by the data-name attribute, allowing a null response if unchecked
get_response = function(side){
var col = display_element.querySelectorAll('[name=\"' + side + '\"]:checked')[0];
if (col === undefined){
return null;
} else {
var i = parseInt(col.getAttribute('data-name'));
return trial.alternatives[i];
}
}
// data saving
var trial_data = {
rt: response_time,
labels: {left: trial.labels[0], right: trial.labels[1]},
response: {left: get_response('left'), right: get_response('right')}
};
// next trial
jsPsych.finishTrial(trial_data);
});
var startTime = performance.now();
};
return plugin;
})();