fixed die
This commit is contained in:
170
index.js
170
index.js
@@ -45,46 +45,42 @@ debug =
|
|||||||
jsPsych.data.getURLVariable('debug') === 'true' ||
|
jsPsych.data.getURLVariable('debug') === 'true' ||
|
||||||
import.meta.env.VITE_DEBUG === 'true';
|
import.meta.env.VITE_DEBUG === 'true';
|
||||||
|
|
||||||
console.log('debug:', debug);
|
|
||||||
|
|
||||||
prolific_id = jsPsych.data.getURLVariable('PROLIFIC_PID');
|
prolific_id = jsPsych.data.getURLVariable('PROLIFIC_PID');
|
||||||
|
|
||||||
const COND = Number(jsPsych.data.getURLVariable('C'));
|
const COND = Number(jsPsych.data.getURLVariable('C'));
|
||||||
|
|
||||||
const probe_preamble = `In this experiment, we told you that you would roll a die to determine the difficulty of the captcha task.\nHowever, `;
|
const probe_closing_text = `<p class ="mt-6">On the next page, you will be asked about your suspicions and thoughts about this aspect of the study.</p>
|
||||||
const probe_closing_text = `\n\nPlease share your thoughts and suspicions about this by indicating your agreement with the following statements.`;
|
<p class="mt-6">Press <span class = "font-semibold"> SPACE</span> to continue</p>`;
|
||||||
|
|
||||||
const probe_text_die =
|
const probe_text_die =
|
||||||
probe_preamble +
|
`<p> In this study, the die roll to determine captcha difficulty was rigged: the number you rolled was predetermined.</p><p class="mt-2"> Therefore, the difficulty of the captcha task was also predetermined.</p>` +
|
||||||
'the die roll was rigged, so that the number you received (and therefore the difficulty of the captcha task) was pre-determined. ' +
|
|
||||||
probe_closing_text;
|
probe_closing_text;
|
||||||
const probe_text_difficulty =
|
const probe_text_difficulty =
|
||||||
probe_preamble +
|
`In this study, the die roll to determine captcha difficulty was indeed random. </p><p class="mt-2"> However, the difficulty of the captcha task was pre-determined. It was unrelated to the die roll.
|
||||||
'while the die roll was random, the difficulty of the captcha task was pre-determined and unrelated to the die roll. ' +
|
</p>` +
|
||||||
probe_closing_text;
|
probe_closing_text;
|
||||||
|
|
||||||
let die_result = 3;
|
const probe_text_baseline = probe_closing_text
|
||||||
|
|
||||||
|
const die_result = Math.random() < 0.5 ? 3 : 4;
|
||||||
|
|
||||||
switch (COND) {
|
switch (COND) {
|
||||||
case 0:
|
case 0:
|
||||||
probe_condition = 'die';
|
probe_condition = 'die';
|
||||||
probe_order = 'die_first';
|
probe_order = 'die_first';
|
||||||
die_result = 4;
|
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
probe_condition = 'die';
|
probe_condition = 'die';
|
||||||
probe_order = 'die_first';
|
probe_order = 'die_first';
|
||||||
die_result = 4;
|
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
probe_condition = 'difficulty';
|
probe_condition = 'difficulty';
|
||||||
probe_order = 'die_first';
|
probe_order = 'die_first';
|
||||||
die_result = 4;
|
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
probe_condition = 'difficulty';
|
probe_condition = 'difficulty';
|
||||||
probe_order = 'die_first';
|
probe_order = 'die_first';
|
||||||
die_result = 4;
|
|
||||||
break;
|
break;
|
||||||
case 4:
|
case 4:
|
||||||
probe_condition = 'die';
|
probe_condition = 'die';
|
||||||
@@ -102,6 +98,22 @@ switch (COND) {
|
|||||||
probe_condition = 'difficulty';
|
probe_condition = 'difficulty';
|
||||||
probe_order = 'difficulty_first';
|
probe_order = 'difficulty_first';
|
||||||
break;
|
break;
|
||||||
|
case 8:
|
||||||
|
probe_condition = 'baseline';
|
||||||
|
probe_order = 'die_first';
|
||||||
|
break;
|
||||||
|
case 9:
|
||||||
|
probe_condition = 'baseline';
|
||||||
|
probe_order = 'die_first';
|
||||||
|
break;
|
||||||
|
case 10:
|
||||||
|
probe_condition = 'baseline';
|
||||||
|
probe_order = 'difficulty_first';
|
||||||
|
break;
|
||||||
|
case 11:
|
||||||
|
probe_condition = 'baseline';
|
||||||
|
probe_order = 'difficulty_first';
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
const stimulusMap = getStimulusMap();
|
const stimulusMap = getStimulusMap();
|
||||||
@@ -174,6 +186,21 @@ const pre_survey_info = {
|
|||||||
stimulus: stimulusMap.get('pre_survey_info'),
|
stimulus: stimulusMap.get('pre_survey_info'),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const die_roll_practice_trial = {
|
||||||
|
type: JsPsychDieRoll,
|
||||||
|
prompt: html`
|
||||||
|
<p class="mt-2">Before the real die roll, you can practice here.</p>
|
||||||
|
<p class="mt-2">
|
||||||
|
Click the die once to start it rolling, then click it again to stop.
|
||||||
|
</p>
|
||||||
|
`,
|
||||||
|
practice_trial: true,
|
||||||
|
practice_roll_limit: 3,
|
||||||
|
roll_duration: 2200,
|
||||||
|
result_template:
|
||||||
|
'Practice roll {{roll_number}}/{{roll_limit}}: You rolled a {{value}}.',
|
||||||
|
};
|
||||||
|
|
||||||
const die_roll_trial = {
|
const die_roll_trial = {
|
||||||
type: JsPsychDieRoll,
|
type: JsPsychDieRoll,
|
||||||
prompt: html`
|
prompt: html`
|
||||||
@@ -204,6 +231,13 @@ const create_captcha_trial = trial_index => {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const pre_die_roll_info = {
|
||||||
|
type: jsPsychHtmlKeyboardResponse,
|
||||||
|
choices: [' '],
|
||||||
|
stimulus: `<p>Practice complete. Now you will roll a die to determine the difficulty of the captcha task.</p>
|
||||||
|
<p class="mt-2">Press <span class ="font-bold">SPACE</span> to continue</p>`,
|
||||||
|
};
|
||||||
|
|
||||||
const captcha_trials = Array.from({ length: CAPTCHA_TRIAL_COUNT }, (_, index) =>
|
const captcha_trials = Array.from({ length: CAPTCHA_TRIAL_COUNT }, (_, index) =>
|
||||||
create_captcha_trial(index)
|
create_captcha_trial(index)
|
||||||
);
|
);
|
||||||
@@ -245,12 +279,12 @@ const survey_function = survey => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const survey = {
|
const survey_1 = {
|
||||||
type: jsPsychSurvey,
|
type: jsPsychSurvey,
|
||||||
survey_function: survey_function,
|
survey_function: survey_function,
|
||||||
survey_json: {
|
survey_json: {
|
||||||
showQuestionNumbers: false,
|
showQuestionNumbers: false,
|
||||||
completeText: 'Done!',
|
completeText: 'Continue',
|
||||||
pageNextText: 'Continue',
|
pageNextText: 'Continue',
|
||||||
pagePrevText: 'Previous',
|
pagePrevText: 'Previous',
|
||||||
showPrevButton: false,
|
showPrevButton: false,
|
||||||
@@ -266,10 +300,6 @@ const survey = {
|
|||||||
isAllRowRequired: debug ? false : true,
|
isAllRowRequired: debug ? false : true,
|
||||||
rowOrder: 'random',
|
rowOrder: 'random',
|
||||||
rows: [
|
rows: [
|
||||||
{
|
|
||||||
text: `I found the captcha task difficult.`,
|
|
||||||
value: 'Difficulty',
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
text: `I felt lucky during the die roll.`,
|
text: `I felt lucky during the die roll.`,
|
||||||
value: 'Luck',
|
value: 'Luck',
|
||||||
@@ -278,6 +308,47 @@ const survey = {
|
|||||||
text: `I felt unlucky during the die roll.`,
|
text: `I felt unlucky during the die roll.`,
|
||||||
value: 'Bad_luck',
|
value: 'Bad_luck',
|
||||||
},
|
},
|
||||||
|
],
|
||||||
|
columns: [
|
||||||
|
{
|
||||||
|
value: 5,
|
||||||
|
text: 'Strongly agree',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: 4,
|
||||||
|
text: 'Agree',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: 3,
|
||||||
|
text: 'Neutral',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: 2,
|
||||||
|
text: 'Disagree',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: 1,
|
||||||
|
text: 'Strongly disagree',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'page2',
|
||||||
|
elements: [
|
||||||
|
{
|
||||||
|
type: 'matrix',
|
||||||
|
name:
|
||||||
|
'Please answer the following questions about your experience in the captcha task.',
|
||||||
|
alternateRows: true,
|
||||||
|
isAllRowRequired: debug ? false : true,
|
||||||
|
rowOrder: 'random',
|
||||||
|
rows: [
|
||||||
|
{
|
||||||
|
text: `I found the captcha task difficult.`,
|
||||||
|
value: 'Difficulty',
|
||||||
|
},
|
||||||
{
|
{
|
||||||
text: `I think I solved all the captchas correctly.`,
|
text: `I think I solved all the captchas correctly.`,
|
||||||
value: 'Accuracy',
|
value: 'Accuracy',
|
||||||
@@ -316,15 +387,43 @@ const survey = {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const pre_manip_info = {
|
||||||
|
type: jsPsychHtmlKeyboardResponse,
|
||||||
|
choices: [' '],
|
||||||
|
stimulus: function () {
|
||||||
|
switch (probe_condition) {
|
||||||
|
case 'die':
|
||||||
|
return probe_text_die;
|
||||||
|
case 'difficulty':
|
||||||
|
return probe_text_difficulty;
|
||||||
|
case 'baseline':
|
||||||
|
return probe_text_baseline;
|
||||||
|
default:
|
||||||
|
return 'ERROR: probe condition not recognized';
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const survey_2 = {
|
||||||
|
type: jsPsychSurvey,
|
||||||
|
survey_function: survey_function,
|
||||||
|
survey_json: {
|
||||||
|
showQuestionNumbers: false,
|
||||||
|
completeText: 'Done!',
|
||||||
|
pageNextText: 'Continue',
|
||||||
|
pagePrevText: 'Previous',
|
||||||
|
showPrevButton: false,
|
||||||
|
pages: [
|
||||||
{
|
{
|
||||||
name: 'page2',
|
name: 'page1',
|
||||||
elements: [
|
elements: [
|
||||||
{
|
{
|
||||||
type: 'matrix',
|
type: 'matrix',
|
||||||
name:
|
name: "Please indicate your agreement with the following statements.",
|
||||||
probe_condition === 'die'
|
|
||||||
? probe_text_die
|
|
||||||
: probe_text_difficulty,
|
|
||||||
alternateRows: true,
|
alternateRows: true,
|
||||||
isAllRowRequired: debug ? false : true,
|
isAllRowRequired: debug ? false : true,
|
||||||
rowOrder: 'random',
|
rowOrder: 'random',
|
||||||
@@ -364,6 +463,21 @@ const survey = {
|
|||||||
],
|
],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'page2',
|
||||||
|
elements: [
|
||||||
|
{
|
||||||
|
type: 'comment',
|
||||||
|
title: `Please write a sentence or two on what you thought the study was about.`,
|
||||||
|
isRequired: debug == true ? false : true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'comment',
|
||||||
|
title: ` Indicate any other thoughts or suspicions you had about the study. \n`,
|
||||||
|
isRequired: debug == true ? false : true,
|
||||||
|
}
|
||||||
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'page3',
|
name: 'page3',
|
||||||
@@ -403,22 +517,28 @@ const survey = {
|
|||||||
const main_experiment_timeline = [
|
const main_experiment_timeline = [
|
||||||
instructions_1,
|
instructions_1,
|
||||||
instructions_2,
|
instructions_2,
|
||||||
|
die_roll_practice_trial,
|
||||||
|
pre_die_roll_info,
|
||||||
die_roll_trial,
|
die_roll_trial,
|
||||||
instructions_3,
|
instructions_3,
|
||||||
...captcha_trials,
|
...captcha_trials,
|
||||||
pre_survey_info,
|
pre_survey_info,
|
||||||
survey,
|
survey_1,
|
||||||
|
pre_manip_info,
|
||||||
|
survey_2,
|
||||||
debrief,
|
debrief,
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
||||||
if (debug) {
|
if (debug) {
|
||||||
|
timeline.push(die_roll_trial);
|
||||||
timeline.push(...main_experiment_timeline);
|
timeline.push(...main_experiment_timeline);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!debug) {
|
if (!debug) {
|
||||||
timeline.push(pre_consent_info);
|
timeline.push(pre_consent_info);
|
||||||
timeline.push(consent_form);
|
|
||||||
timeline.push(enter_fullscreen);
|
timeline.push(enter_fullscreen);
|
||||||
|
timeline.push(consent_form);
|
||||||
timeline.push(...main_experiment_timeline);
|
timeline.push(...main_experiment_timeline);
|
||||||
}
|
}
|
||||||
jsPsych.run(timeline);
|
jsPsych.run(timeline);
|
||||||
|
|||||||
@@ -27,6 +27,14 @@ const info = {
|
|||||||
type: ParameterType.STRING,
|
type: ParameterType.STRING,
|
||||||
default: 'You rolled a {{value}}.',
|
default: 'You rolled a {{value}}.',
|
||||||
},
|
},
|
||||||
|
practice_trial: {
|
||||||
|
type: ParameterType.BOOL,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
practice_roll_limit: {
|
||||||
|
type: ParameterType.INT,
|
||||||
|
default: 5,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -37,13 +45,17 @@ class DieRollPlugin {
|
|||||||
|
|
||||||
trial(display_element, trial) {
|
trial(display_element, trial) {
|
||||||
const start_time = performance.now();
|
const start_time = performance.now();
|
||||||
const sanitized_rigged_value = this.get_rigged_value(trial.rigged_value);
|
const practice_enabled = Boolean(trial.practice_trial);
|
||||||
const final_value =
|
const practice_roll_limit = practice_enabled
|
||||||
sanitized_rigged_value ??
|
? this.get_practice_roll_limit(trial.practice_roll_limit)
|
||||||
this.jsPsych.randomization.sampleWithoutReplacement(
|
: 1;
|
||||||
[1, 2, 3, 4, 5, 6],
|
const sanitized_rigged_value = practice_enabled
|
||||||
1
|
? null
|
||||||
)[0];
|
: this.get_rigged_value(trial.rigged_value);
|
||||||
|
const get_next_result_value = () =>
|
||||||
|
sanitized_rigged_value ?? this.get_random_value();
|
||||||
|
let pending_final_value = get_next_result_value();
|
||||||
|
let last_roll_value = null;
|
||||||
|
|
||||||
display_element.innerHTML = this.build_markup(
|
display_element.innerHTML = this.build_markup(
|
||||||
trial.prompt,
|
trial.prompt,
|
||||||
@@ -60,21 +72,60 @@ class DieRollPlugin {
|
|||||||
'.jspsych_die_roll_button'
|
'.jspsych_die_roll_button'
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const PRACTICE_UNLOCK_DELAY_MS = 600;
|
||||||
|
const MIN_IDLE_CLICK_INTERVAL_MS = 350;
|
||||||
let is_rolling = false;
|
let is_rolling = false;
|
||||||
let has_rolled = false;
|
let has_rolled = false;
|
||||||
let roll_started_at = null;
|
let roll_started_at = null;
|
||||||
let roll_stopped_at = null;
|
let roll_stopped_at = null;
|
||||||
let die_click_count = 0;
|
let die_click_count = 0;
|
||||||
|
let practice_rolls_completed = 0;
|
||||||
|
let practice_reenable_timeout = null;
|
||||||
|
let previous_face_value = null;
|
||||||
|
let last_face_interaction_at = null;
|
||||||
|
|
||||||
const clear_timeouts = () => {
|
const clear_timeouts = () => {
|
||||||
|
if (practice_enabled && practice_reenable_timeout !== null) {
|
||||||
|
window.clearTimeout(practice_reenable_timeout);
|
||||||
|
practice_reenable_timeout = null;
|
||||||
|
}
|
||||||
this.jsPsych.pluginAPI.clearAllTimeouts();
|
this.jsPsych.pluginAPI.clearAllTimeouts();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const lock_die_face = () => {
|
||||||
|
face_element.classList.remove('jspsych_die_roll_face--interactive');
|
||||||
|
face_element.classList.remove('jspsych_die_roll_face--active');
|
||||||
|
face_element.classList.add('jspsych_die_roll_face--locked');
|
||||||
|
face_element.setAttribute('aria-disabled', 'true');
|
||||||
|
face_element.removeAttribute('tabindex');
|
||||||
|
face_element.style.pointerEvents = 'none';
|
||||||
|
};
|
||||||
|
|
||||||
|
const make_die_interactive = () => {
|
||||||
|
face_element.classList.remove('jspsych_die_roll_face--locked');
|
||||||
|
face_element.classList.add('jspsych_die_roll_face--interactive');
|
||||||
|
face_element.setAttribute('tabindex', '0');
|
||||||
|
face_element.removeAttribute('aria-disabled');
|
||||||
|
face_element.style.pointerEvents = '';
|
||||||
|
};
|
||||||
|
|
||||||
|
const get_next_face_value = () => {
|
||||||
|
let value;
|
||||||
|
do {
|
||||||
|
value = Math.floor(Math.random() * 6) + 1;
|
||||||
|
} while (
|
||||||
|
value === previous_face_value ||
|
||||||
|
(sanitized_rigged_value !== null && value === sanitized_rigged_value)
|
||||||
|
);
|
||||||
|
previous_face_value = value;
|
||||||
|
return value;
|
||||||
|
};
|
||||||
|
|
||||||
const cycle_face = () => {
|
const cycle_face = () => {
|
||||||
if (!is_rolling) {
|
if (!is_rolling) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const value = this.random_face(final_value);
|
const value = get_next_face_value();
|
||||||
face_element.textContent = value;
|
face_element.textContent = value;
|
||||||
this.jsPsych.pluginAPI.setTimeout(cycle_face, trial.animation_interval);
|
this.jsPsych.pluginAPI.setTimeout(cycle_face, trial.animation_interval);
|
||||||
};
|
};
|
||||||
@@ -88,25 +139,55 @@ class DieRollPlugin {
|
|||||||
die_click_count += 1;
|
die_click_count += 1;
|
||||||
roll_stopped_at = performance.now();
|
roll_stopped_at = performance.now();
|
||||||
clear_timeouts();
|
clear_timeouts();
|
||||||
face_element.textContent = final_value;
|
last_roll_value = pending_final_value;
|
||||||
face_element.classList.remove('jspsych_die_roll_face--active');
|
face_element.textContent = last_roll_value;
|
||||||
face_element.classList.remove('jspsych_die_roll_face--interactive');
|
lock_die_face();
|
||||||
face_element.classList.add('jspsych_die_roll_face--locked');
|
practice_rolls_completed += 1;
|
||||||
face_element.setAttribute('aria-disabled', 'true');
|
const rolls_remaining = Math.max(
|
||||||
face_element.removeAttribute('tabindex');
|
practice_roll_limit - practice_rolls_completed,
|
||||||
face_element.style.pointerEvents = 'none';
|
0
|
||||||
result_element.textContent = trial.result_template.replace(
|
|
||||||
/\{\{value\}\}/gi,
|
|
||||||
final_value
|
|
||||||
);
|
);
|
||||||
|
const formatted_result = this.render_result_text(
|
||||||
|
trial.result_template,
|
||||||
|
{
|
||||||
|
value: last_roll_value,
|
||||||
|
roll_number: practice_rolls_completed,
|
||||||
|
roll_limit: practice_enabled ? practice_roll_limit : null,
|
||||||
|
rolls_remaining: practice_enabled ? rolls_remaining : null,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
if (practice_enabled) {
|
||||||
|
if (rolls_remaining > 0) {
|
||||||
|
result_element.innerHTML =
|
||||||
|
`${formatted_result} <p class = "mt-2"> You may roll again (${rolls_remaining} ` +
|
||||||
|
`practice ${rolls_remaining === 1 ? 'roll' : 'rolls'} remaining) or click 'Continue' to proceed.</p>`;
|
||||||
|
// Brief delay prevents a double-click from immediately starting a new roll.
|
||||||
|
practice_reenable_timeout = window.setTimeout(() => {
|
||||||
|
make_die_interactive();
|
||||||
|
has_rolled = false;
|
||||||
|
practice_reenable_timeout = null;
|
||||||
|
}, PRACTICE_UNLOCK_DELAY_MS);
|
||||||
|
} else {
|
||||||
|
result_element.textContent =
|
||||||
|
`${formatted_result} Practice complete. Click 'Continue' to proceed.`;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
result_element.textContent = formatted_result;
|
||||||
|
}
|
||||||
|
|
||||||
button_element.disabled = false;
|
button_element.disabled = false;
|
||||||
|
if (!practice_enabled || rolls_remaining === 0) {
|
||||||
button_element.focus();
|
button_element.focus();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const begin_roll = () => {
|
const begin_roll = () => {
|
||||||
if (is_rolling || has_rolled) {
|
if (is_rolling || has_rolled) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
previous_face_value = null;
|
||||||
|
pending_final_value = get_next_result_value();
|
||||||
is_rolling = true;
|
is_rolling = true;
|
||||||
die_click_count += 1;
|
die_click_count += 1;
|
||||||
roll_started_at = performance.now();
|
roll_started_at = performance.now();
|
||||||
@@ -117,31 +198,59 @@ class DieRollPlugin {
|
|||||||
cycle_face();
|
cycle_face();
|
||||||
};
|
};
|
||||||
|
|
||||||
const handle_face_interaction = () => {
|
const handle_face_interaction = event => {
|
||||||
if (!is_rolling && !has_rolled) {
|
const event_type = event?.type ?? 'unknown';
|
||||||
begin_roll();
|
|
||||||
} else if (is_rolling && !has_rolled) {
|
if (
|
||||||
|
(event_type === 'pointerdown' || event_type === 'click') &&
|
||||||
|
typeof event?.button === 'number' &&
|
||||||
|
event.button !== 0
|
||||||
|
) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (practice_enabled) {
|
||||||
|
const now = performance.now();
|
||||||
|
if (!is_rolling && last_face_interaction_at !== null) {
|
||||||
|
const elapsed = now - last_face_interaction_at;
|
||||||
|
if (elapsed < MIN_IDLE_CLICK_INTERVAL_MS) {
|
||||||
|
event?.preventDefault();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
last_face_interaction_at = now;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_rolling) {
|
||||||
finalize_roll();
|
finalize_roll();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!has_rolled) {
|
||||||
|
begin_roll();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
button_element.disabled = true;
|
button_element.disabled = true;
|
||||||
face_element.textContent = '';
|
face_element.textContent = '';
|
||||||
result_element.textContent =
|
result_element.innerHTML = practice_enabled
|
||||||
'Click the die to start, then click it again to lock in your number.';
|
? `<p>Practice rolling the die. You can complete up to ${practice_roll_limit}</p>` +
|
||||||
face_element.classList.add('jspsych_die_roll_face--interactive');
|
`practice ${practice_roll_limit === 1 ? 'roll' : 'rolls'}. <p class = "mt-2"> Click the die to start, then click it again to stop. </p>`
|
||||||
face_element.setAttribute('tabindex', '0');
|
: 'Click the die to start, then click it again to lock in your number.';
|
||||||
|
make_die_interactive();
|
||||||
face_element.setAttribute('role', 'button');
|
face_element.setAttribute('role', 'button');
|
||||||
face_element.setAttribute(
|
face_element.setAttribute(
|
||||||
'aria-label',
|
'aria-label',
|
||||||
'Virtual die. Click to start and stop.'
|
'Virtual die. Click to start and stop.'
|
||||||
);
|
);
|
||||||
|
|
||||||
face_element.addEventListener('click', handle_face_interaction);
|
const face_interaction_event =
|
||||||
|
typeof window.PointerEvent === 'function' ? 'pointerdown' : 'click';
|
||||||
|
face_element.addEventListener(face_interaction_event, handle_face_interaction);
|
||||||
face_element.addEventListener('keydown', event => {
|
face_element.addEventListener('keydown', event => {
|
||||||
if (event.key === 'Enter' || event.key === ' ') {
|
if (event.key === 'Enter' || event.key === ' ') {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
handle_face_interaction();
|
handle_face_interaction(event);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -149,7 +258,7 @@ class DieRollPlugin {
|
|||||||
is_rolling = false;
|
is_rolling = false;
|
||||||
clear_timeouts();
|
clear_timeouts();
|
||||||
const trial_data = {
|
const trial_data = {
|
||||||
roll: final_value,
|
roll: last_roll_value,
|
||||||
rigged_value: sanitized_rigged_value,
|
rigged_value: sanitized_rigged_value,
|
||||||
rigged: sanitized_rigged_value !== null,
|
rigged: sanitized_rigged_value !== null,
|
||||||
die_click_count: die_click_count,
|
die_click_count: die_click_count,
|
||||||
@@ -161,6 +270,14 @@ class DieRollPlugin {
|
|||||||
? roll_stopped_at - roll_started_at
|
? roll_stopped_at - roll_started_at
|
||||||
: null,
|
: null,
|
||||||
rt: performance.now() - start_time,
|
rt: performance.now() - start_time,
|
||||||
|
practice_trial: practice_enabled,
|
||||||
|
practice_roll_limit: practice_enabled ? practice_roll_limit : null,
|
||||||
|
practice_rolls_completed: practice_enabled
|
||||||
|
? practice_rolls_completed
|
||||||
|
: null,
|
||||||
|
practice_rolls_remaining: practice_enabled
|
||||||
|
? Math.max(practice_roll_limit - practice_rolls_completed, 0)
|
||||||
|
: null,
|
||||||
};
|
};
|
||||||
display_element.innerHTML = '';
|
display_element.innerHTML = '';
|
||||||
this.jsPsych.finishTrial(trial_data);
|
this.jsPsych.finishTrial(trial_data);
|
||||||
@@ -187,12 +304,11 @@ class DieRollPlugin {
|
|||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
random_face(exclude_value) {
|
get_random_value() {
|
||||||
let value = Math.floor(Math.random() * 6) + 1;
|
return this.jsPsych.randomization.sampleWithoutReplacement(
|
||||||
if (value === exclude_value) {
|
[1, 2, 3, 4, 5, 6],
|
||||||
value = (value % 6) + 1;
|
1
|
||||||
}
|
)[0];
|
||||||
return value;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
get_rigged_value(value) {
|
get_rigged_value(value) {
|
||||||
@@ -202,6 +318,27 @@ class DieRollPlugin {
|
|||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get_practice_roll_limit(value) {
|
||||||
|
const numeric = Number(value);
|
||||||
|
if (Number.isFinite(numeric) && numeric >= 1) {
|
||||||
|
return Math.round(numeric);
|
||||||
|
}
|
||||||
|
return 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
render_result_text(template, replacements) {
|
||||||
|
if (typeof template !== 'string' || template.length === 0) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
return Object.entries(replacements).reduce((text, [key, value]) => {
|
||||||
|
if (value === null || value === undefined) {
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
const pattern = new RegExp(`\\{\\{${key}\\}\\}`, 'gi');
|
||||||
|
return text.replace(pattern, value);
|
||||||
|
}, template);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DieRollPlugin.info = info;
|
DieRollPlugin.info = info;
|
||||||
|
|||||||
@@ -19,11 +19,11 @@ function getStimulusMap() {
|
|||||||
</p>
|
</p>
|
||||||
<p class="leading-relaxed mt-2"">
|
<p class="leading-relaxed mt-2"">
|
||||||
You will now answer a few questions about your experience in the
|
You will now answer a few questions about your experience in the
|
||||||
experiment. It is important that you read the questions carefully and
|
experiment.
|
||||||
answer them honestly.
|
|
||||||
</p>
|
</p>
|
||||||
<p class="leading-relaxed mt-2">
|
<p class="leading-relaxed mt-2">
|
||||||
Nonsense or random answers may lead to your submission being rejected.
|
It is important that you read the questions carefully and
|
||||||
|
answer them honestly.
|
||||||
</p>
|
</p>
|
||||||
<p class="mt-6">
|
<p class="mt-6">
|
||||||
Press
|
Press
|
||||||
@@ -167,15 +167,14 @@ function getStimulusMap() {
|
|||||||
stimulusMap.set(
|
stimulusMap.set(
|
||||||
'instructions_1',
|
'instructions_1',
|
||||||
html`
|
html`
|
||||||
<p>In this experiment, you will be solving some captchas.</p>
|
<p>In this experiment, you will be solving captchas.</p>
|
||||||
<p class="mt-2">
|
<p class="mt-2">
|
||||||
This will involve identifying slightly distorted letters and numbers
|
This will involve identifying slightly distorted letters and numbers
|
||||||
from an image.
|
from an image.
|
||||||
</p>
|
</p>
|
||||||
<p class="mt-2">
|
<p class="mt-6">
|
||||||
Your task is to solve the captchas as quickly and accurately as
|
Your task is to solve the captchas as quickly and accurately as
|
||||||
possible. You will not be given feedback on your performance.
|
possible. </p>
|
||||||
</p>
|
|
||||||
<p class="mt-6">
|
<p class="mt-6">
|
||||||
Press
|
Press
|
||||||
<strong>SPACE</strong>
|
<strong>SPACE</strong>
|
||||||
@@ -188,9 +187,9 @@ function getStimulusMap() {
|
|||||||
'instructions_2',
|
'instructions_2',
|
||||||
html`
|
html`
|
||||||
<p>
|
<p>
|
||||||
To randomise the difficulty of the captchas you will be solving, we will
|
In this study, we will randomise the difficulty of the captchas you will solve. </p>
|
||||||
first ask you to roll a virtual die. You will then be shown captchas of
|
<p class="mt-2">
|
||||||
a difficulty corresponding to the number you rolled.
|
You will roll a virtual die to determine the difficulty of the captchas you will see.
|
||||||
</p>
|
</p>
|
||||||
<p class="mt-2">
|
<p class="mt-2">
|
||||||
The higher the number you roll, the more difficult the captchas will be.
|
The higher the number you roll, the more difficult the captchas will be.
|
||||||
@@ -207,18 +206,9 @@ function getStimulusMap() {
|
|||||||
'instructions_3',
|
'instructions_3',
|
||||||
html`
|
html`
|
||||||
<p>
|
<p>
|
||||||
You will now proceed to the captcha task, in which you will need to
|
You will now proceed to the captcha task </p> <p class = "mt-2"> You will need to
|
||||||
solve 12 captchas in a row as quickly and accurately as possible.
|
solve 12 captchas in a row as quickly and accurately as possible.
|
||||||
</p>
|
</p>
|
||||||
<p class="mt-2">
|
|
||||||
Please ensure that you are in a quiet environment and that you will not
|
|
||||||
be interrupted for the next few minutes.
|
|
||||||
</p>
|
|
||||||
<p class="mt-2">
|
|
||||||
Please also ensure that you solve these captchas to the best of your
|
|
||||||
ability. Nonsense or random answers may lead to your submission being
|
|
||||||
rejected.
|
|
||||||
</p>
|
|
||||||
<p class="mt-6 text-red-500">
|
<p class="mt-6 text-red-500">
|
||||||
Press
|
Press
|
||||||
<strong>SPACE</strong>
|
<strong>SPACE</strong>
|
||||||
|
|||||||
@@ -76,8 +76,10 @@
|
|||||||
|
|
||||||
.jspsych_die_roll_face--locked {
|
.jspsych_die_roll_face--locked {
|
||||||
cursor: not-allowed;
|
cursor: not-allowed;
|
||||||
opacity: 0.8;
|
opacity: 0.5;
|
||||||
box-shadow: 0 15px 25px rgba(15, 23, 42, 0.15);
|
box-shadow: 0 15px 25px rgba(15, 23, 42, 0.15);
|
||||||
|
background: linear-gradient(145deg, #d4d8de, #cbd2db);
|
||||||
|
color: #475569;
|
||||||
}
|
}
|
||||||
|
|
||||||
@keyframes pulse {
|
@keyframes pulse {
|
||||||
|
|||||||
Reference in New Issue
Block a user