/** * 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 += '
'; // add maxdiff options /// // first generate alternative order, randomized here as opposed to randomizing the order of alternatives // so that the data are always associated with the same alternative regardless of order. var alternative_order = []; for (var i = 0; i < trial.alternatives.length; i++) { alternative_order.push(i); } if (trial.randomize_alternative_order) { alternative_order = jsPsych.randomization.shuffle(alternative_order); } // Start with column headings var maxdiff_table = ''; // construct each row of the maxdiff table for (var i = 0; i < trial.alternatives.length; i++) { var alternative = trial.alternatives[alternative_order[i]]; // add alternative maxdiff_table += ''; maxdiff_table += ''; maxdiff_table += ''; } maxdiff_table += '
' + trial.labels[0] + '' + trial.labels[1] + '

' + alternative + '


'; html += maxdiff_table; // add submit button var enable_submit = trial.required == true ? 'disabled = "disabled"' : ''; html += ''; 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; })();