/** * jspsych-maxdiff * 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 most or least preferred.' }, 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) { const most_least = ["most", "least"] var enable_submit = trial.required == true ? 'disabled = "disabled"' : ''; var html = ""; // inject CSS for trial html += ''; // show preamble text if (trial.preamble !== null) { html += '
' + trial.preamble + '
'; } html += '
'; // add maxdiff options /// // generate alternative order. this is 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 html += ''; html += '
'; display_element.innerHTML = html; // function to control responses // first checks that the same alternative cannot be endorsed as 'most' and 'least' simultaneously // then enables the submit button if the trial is required. most_least.forEach(function(p) { // Get all elements either 'most' or 'least' document.getElementsByName(p).forEach(function(obj) { obj.addEventListener('click', function() { // Find the opposite (if most, then least & vice versa) var op = obj.name == 'most' ? 'least' : 'most'; // Get the opposite button identified by the class (one, two, etc) var n = document.getElementsByClassName(obj.className).namedItem(op); // If it's checked, uncheck it. if (n.checked) { n.checked = false; } // check response if (trial.required){ // Now check if both most and least have been enabled var most_checked = [...document.getElementsByName('most')].some(c => c.checked); var least_checked = [...document.getElementsByName('least')].some(c => c.checked); // If at least one of both have been clicked, allow submission if (most_checked && least_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 display_element.querySelector('#jspsych-maxdiff-form').addEventListener('submit', function(e){ e.preventDefault(); // measure response time var endTime = performance.now(); var response_time = endTime - startTime; var most = parseInt(display_element.querySelectorAll('[name="most"]:checked')[0].getAttribute('data-name')); var least = parseInt(display_element.querySelectorAll('[name="least"]:checked')[0].getAttribute('data-name')); // data saving var trial_data = { "rt": response_time, "most": trial.alternatives[most], "least": trial.alternatives[least] }; // next trial jsPsych.finishTrial(trial_data); }); var startTime = performance.now(); }; return plugin; })();