UNPKG

aiom_pack

Version:

Framework for interdependent (mcmc-like) behavioral experiments

311 lines (279 loc) 10.7 kB
var local_pid; var current_on_left; var start_classes; var classes; var class_questions; var n_rest; var mode; var stimuli_attr; var current_position; var proposal_position; var current_category; var proposal_category; var current_chain; var current_class; var n_trial = 1; var n_turnpoint = 0; var attention_check_pass = true; function submit_id(id) { Cookies.set('pid', id); axios.post('/api/set_table', { names: id, }, {headers: { 'Content-Type': 'application/json', }, }) .then(response => { classes = JSON.stringify(response.data.classes); class_questions = JSON.stringify(response.data.class_questions); Cookies.set('classes', classes); Cookies.set('class_questions', class_questions); Cookies.set('n_rest', response.data.n_rest); Cookies.set('mode', response.data.mode); }) .then(() => {window.location.href = `/instruction`;}) .catch((error) => { console.error('Error:', error); alert(`Error in setting tables`); }); } function load_parameters() { local_pid = Cookies.get('pid'); classes = Cookies.get('classes'); classes = JSON.parse(classes); class_questions = Cookies.get('class_questions'); class_questions = JSON.parse(class_questions); n_rest = Number(Cookies.get('n_rest')); mode = Cookies.get('mode'); if (mode === 'test') { stimuli_attr = 'alt'; } else if (mode === 'image') { stimuli_attr = 'src'; } } function getChoice() { axios.get(`/api/get_choices`, { headers: { 'ID': local_pid }, }) .then(response => { // parse the information from the response current_on_left = 0.5 <= Math.random(); if (['likelihood', 'attention_check'].includes(response.data.trial_type)) { $(".option").removeClass('hidden-option'); current_class = response.data.current_class; $( ".stimuli_left" ).replaceWith('<img class="stimuli_left" src="" alt="" height="128" width="128" onclick="sendChoice(0)">'); $( ".stimuli_right" ).replaceWith('<img class="stimuli_right" src="" alt="" height="128" width="128" onclick="sendChoice(1)">'); $(".question").html(class_questions[classes.indexOf(current_class)]); if (current_on_left) { $(".stimuli_left").attr(stimuli_attr, response.data.current); $(".stimuli_right").attr(stimuli_attr, response.data.proposal); } else { $(".stimuli_right").attr(stimuli_attr, response.data.current); $(".stimuli_left").attr(stimuli_attr, response.data.proposal); } if (response.data.trial_type === 'attention_check') { const attention_check = response.data.attention_check; // mute the onclick function of two stimuli $(".stimuli_left, .stimuli_right").attr("onclick", ""); if (current_on_left) { $(".stimuli_left").attr("onclick", `sendChoice_attentioncheck(${current_class===attention_check[0]})`); $(".stimuli_right").attr("onclick", `sendChoice_attentioncheck(${current_class===attention_check[1]})`); } else { $(".stimuli_left").attr("onclick", `sendChoice_attentioncheck(${current_class===attention_check[1]})`); $(".stimuli_right").attr("onclick", `sendChoice_attentioncheck(${current_class===attention_check[0]})`); } } else { current_chain = response.data.current_chain; current_position = response.data.current_position; proposal_position = response.data.proposal_position; } } else { $(".option").addClass('hidden-option'); current_chain = response.data.current_chain; current_position = response.data.stimulus_position; current_category = response.data.current; proposal_category = response.data.proposal; $( ".stimuli_left" ).replaceWith( '<button class="stimuli_left" id="button_left" onclick="sendChoice_prior(0)">Option</button>' ); $( ".stimuli_right" ).replaceWith( '<button class="stimuli_right" id="button_right" onclick="sendChoice_prior(1)">Option</button>' ); $(".question").html('Which category can best describe the face:<br><br>'); $(".question").append('<img id="question_stimuli" src="" alt="" height="128" width="128"></img>'); $("#question_stimuli").attr(stimuli_attr, response.data.current_stimulus); if (current_on_left) { $(".stimuli_left").html(current_category); $(".stimuli_right").html(proposal_category); } else { $(".stimuli_right").html(current_category); $(".stimuli_left").html(proposal_category); } } fadein_option(); return response.data; }) .catch((error) => { console.error('Error:', error); // alert(`Error sending list ${local_pid}`); endExperiment(); }); } function sendChoice_attentioncheck(attention_check) { axios.post(`/api/register_attentioncheck`, { result: attention_check, }, {headers: { 'Content-Type': 'application/json', 'ID': local_pid, }, }) .then(response => { if (response.data.fail_count >= 2) { attention_check_pass = false; } fadeaway_option(100); // remove the click function of two stimuli $(".stimuli_left, .stimuli_right").attr("onclick", ""); $(".stimuli_left").attr("onclick", "sendChoice(0)"); $(".stimuli_right").attr("onclick", "sendChoice(1)"); setTimeout(() => { getChoice(); }, 500) }) .catch((error) => { console.error('Error:', error); // alert(`Error sending list ${local_pid}`); endExperiment(); }); } function sendChoice(selected) { let decision; if (current_on_left) { decision = selected; } else { decision = 1-selected; } const selected_position = decision==0 ? current_position : proposal_position; axios.post(`/api/register_choices`, { choice: selected_position, }, {headers: { 'Content-Type': 'application/json', 'name': local_pid, 'ID': `${local_pid}_blockwise_no${current_chain}`, 'n_trial': n_trial, 'current_class': current_class, 'trial_type': 'likelihood', }, }) .then(response => { n_trial ++; if (!response.data.finish) { if ((n_trial-1)%n_rest===0 && n_trial != 2) { time_to_rest().then(() => { // Code here will run after the user clicks "Continue" fadeaway_option(response.data.progress); setTimeout(() => { getChoice(); }, 500) }); } else { fadeaway_option(response.data.progress); setTimeout(() => { getChoice(); }, 500) } } else { endExperiment(); } }) .catch((error) => { console.error('Error:', error); // alert(`Error sending list ${local_pid}`); endExperiment(); }); } function sendChoice_prior(selected) { let decision; if (current_on_left) { decision = selected; } else { decision = 1-selected; } const selected_category = decision==0 ? current_category : proposal_category; axios.post(`/api/register_choices`, { choice: selected_category, current_position: current_position, }, {headers: { 'Content-Type': 'application/json', 'ID': `${local_pid}_blockwise_no${current_chain}`, 'name': local_pid, 'n_trial': n_trial, 'trial_type': 'prior', }, }) .then(response => { n_trial ++; if (!response.data.finish) { if ((n_trial-1)%n_rest===0 && n_trial != 2) { time_to_rest().then(() => { // Code here will run after the user clicks "Continue" fadeaway_option(response.data.progress); setTimeout(() => { getChoice(); }, 500) }); } else { fadeaway_option(response.data.progress); setTimeout(() => { getChoice(); }, 500) } } else { endExperiment(); } }) .catch((error) => { console.error('Error:', error); // alert(`Error sending list ${local_pid}`); endExperiment(); }); } function endExperiment() { if (attention_check_pass) window.location.href = `/thanks`; // continue to the next subexperiment else window.location.href = `/early_stop`; // end the experiment without bonus } // UI animation function fadeaway_option(progress) { $('#choice_left').removeClass('fade-in').addClass('fade-out'); $('#choice_right').removeClass('fade-in').addClass('fade-out'); setTimeout(() => { updateProgress(progress); }, 100); } function fadein_option() { $('#choice_left').removeClass('fade-out').addClass('fade-in'); $('#choice_right').removeClass('fade-out').addClass('fade-in'); } function updateProgress(progress) { if (progress <= 1.0) { const progressBar = document.getElementById('progressBar'); progressBar.style.width = `${progress*100}%`; } } function time_to_rest() { return $.Deferred(function(deferred) { // Display the modal $('#restContent p').html('You can have a rest now!'); $("#rest").css("display", "flex"); // Wait for the user to click "Continue" $("#continueButton").on("click", function() { $("#rest").css("display", "none"); // Hide the modal deferred.resolve(); // Continue the script }); }).promise(); }