forked from longouyang/even-odd
-
Notifications
You must be signed in to change notification settings - Fork 0
/
ff_ret.js
280 lines (189 loc) · 7.96 KB
/
ff_ret.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
// ## High-level overview
// Things happen in this order:
//
// 1. Set up the experiment sequence object.
// 2. When the subject clicks the start button, it calls <code>experiment.next()</code>
// 3. <code>experiment.next()</code> checks if there are any trials left to do. If there aren't, it calls <code>experiment.end()</code>, which shows the finish slide, waits for 1.5 seconds, and then uses mmturkey to submit to Turk.
// 4. If there are more trials left, <code>experiment.next()</code> shows the next trial, records the current time for computing reaction time, and sets up a listener for a key press.
// 5. The mouse click listener, when it detects a click, constructs a data object, which includes the presented stimulus, which version was selected, and RT (current time - start time). This entire object gets pushed into the <code>experiment.data</code> array. Then we show a blank screen and wait 500 milliseconds before calling <code>experiment.next()</code> again.
// ## Configuration settings
// Initialize stimuli parameters
var stimdir = "stim/";
var stim = JSON.parse(stimuli);
var preload_imgs = [];
var trialOrder = [];
// For preloading push all versions
// but for trialOrder only push stim name
for (var i = 0; i < stim.length; i++){
var sbst = stim[i];
for (var j = 0; j < sbst.length; j++){
preload_imgs.push(stimdir + sbst[j] + '/e1_s1.jpg');
preload_imgs.push(stimdir + sbst[j] + '/e1_s2.jpg');
preload_imgs.push(stimdir + sbst[j] + '/e2_s1.jpg');
preload_imgs.push(stimdir + sbst[j] + '/e2_s2.jpg');
trialOrder.push(stimdir + sbst[j]);
}
}
// Shuffle
fisherYates(trialOrder);
// ## Start the experiment
// Hide our filler images
$(".upperleft, .upperright, .lowerleft, .lowerright").hide();
// Disable buttons if in preview mode
if (turk.previewMode) {
$("button")[0].disabled = true;
}
// ## Show codescreen slide
// and only allow users with Chrome
if (fingerprint.browser.search("Chrome") < 0 && fingerprint.browser.search("chrome") < 0) {
showSlide("chrome");
} else {
showSlide("codescreen");
}
// ## Preloading
// function called once all images have been successfully loaded
function onLoadedAll() {
experiment.next();
}
// preload images
function preload_wrap() {
showSlide("preload");
$("#num-total").text(preload_imgs.length);
preload(preload_imgs,
onLoadedOne,
onLoadedAll);
}
// ## Code validation
var code = "";
$("form#getcode").submit( function (){
$("#validated").text("");
$("#validated").attr("style", "color:red");
code = $("#getcode")[0].elements["code"].value; //global scope, try to fix later
// screen for invalid format
if (!(code.length == 33 &&
code.slice(0,4) == "8302" &&
(code.slice(-5) == "2153s" || code.slice(-5) == "2153l") &&
!isNaN(code.slice(0,-1)))) {
$("#validated").text("Invalid code. Please enter a valid code. Make sure there are no spaces before or after the code!");
return;
}
// convert to date
var startDate = codeToDate(code.slice(4,16))
var endDate = codeToDate(code.slice(16,28))
var curDate = new Date();
// screen for invalid dates
if (!startDate || !endDate || startDate > endDate){
$("#validated").text("Invalid code. Please enter a valid code.");
return;
}
// check time
// too soon
if (startDate > curDate){
$("#validated").text("This code is only valid for use between " + dateToString(startDate) + " and " + dateToString(endDate) + ". Please come back soon!");
// too late
} else if (endDate < curDate) {
$("#validated").text("This code expired on " + dateToString(endDate));
// just right!
} else {
if (turk.previewMode) {
$("#validated").text("This code is valid but cannot submit while in preview mode.");
$("#validated").attr("style", "color:green");
return;
}
showSlide("instructions");
}
})
// ## Prep data storage
var allData = {
fingerprintData: fingerprint,
trialData: [] // populated each trial
}
// ## Run experiment
var experiment = {
// Trials
// deep copy since we are using .shift() but want to retain record of trial order
trials: $.extend(true, [], trialOrder),
// The function that gets called when the sequence is finished.
end: function() {
showSlide("comments");
},
// The work horse of the sequence - what to do on every trial.
next: function() {
// If the number of remaining trials is 0, we're done, so call the end function.
if (experiment.trials.length == 0) {
allData.delayGroup = (code.slice(-1) == "s" ? "short" : "long");
experiment.end();
return;
}
// Get the current trial
var trial_img = experiment.trials.shift();
var trial_img_ul = trial_img + "/e1_s1.jpg";
var trial_img_ur = trial_img + "/e1_s2.jpg";
var trial_img_ll = trial_img + "/e2_s1.jpg";
var trial_img_lr = trial_img + "/e2_s2.jpg";
// Display the image stimulus.
showSlide("stage");
$(".upperleft").attr("src", trial_img_ul);
$(".upperright").attr("src", trial_img_ur);
$(".lowerleft").attr("src", trial_img_ll);
$(".lowerright").attr("src", trial_img_lr);
$(".upperleft, .upperright, .lowerleft, .lowerright").show();
// Get the current time so we can compute reaction time later.
var startTime = (new Date()).getTime();
// Define click handler
var clickHandler = function(event){
$("img").off("click"); // Binding with 'one' is not preventing multiple click events
// Record the reaction time (current time minus start time) and which image was selected
var endTime = (new Date()).getTime(),
trial = {
resp: $(this).attr("src"),
rt: endTime - startTime,
stimulus: trial_img
};
allData.trialData.push(trial);
// Temporarily clear the display
$("img").hide();
// Wait 500 milliseconds before starting the next trial.
setTimeout(experiment.next, 500);
};
// Bind the handler
$("img").one("click", clickHandler); //'one' is not working as intended
}
}
// ## Submit comments
$("form#commentform").submit( function (){
var comments = $("#commentform")[0].elements["comments"].value;
allData.comments = comments;
wrap_up();
})
// ## Wrap up function for end of experiment
function wrap_up() {
allData.submitTime = new Date();
allData.entrycode = code;
// display appropriate finish slide
if (allData.delayGroup == "long"){
$("#finish-yescheckin").hide();
allData.exitcode = "none";
// Show the finish slide.
showSlide("finished");
// user clicks button to submit
} else {
$("#finish-nocheckin").hide();
$("#timeframe").text(" between 60 hours and 84 hours from now ");
// careful with the order here
// or change to copy by value
var curDate = new Date();
var startret = curDate;
startret.setHours(startret.getHours() + 60)
$("#checkstart").text(dateToString(startret));
var startcode = dateToCode(startret);
var endret = startret;
endret.setHours(endret.getHours() + 24);
$("#checkend").text(dateToString(endret));
var endcode = dateToCode(endret);
$("#checkcode").text("0176" + startcode + endcode + "0198");
allData.exitcode = "0176" + startcode + endcode + "0198";
showSlide("finished");
// user clicks button to submit
}
}