Reputation: 1
I am new at this (both StackOverflow and non-statistics coding), so my apologies if I screw this question up.
I have participants taking an online experiment (using Qualtrics, a survey platform) where I ask them to watch a video. I need them to watch the video and not just listen to it because what I'm manipulating is the nonverbal behavior of the person in the video.
As one quality check, I want to count whether they defocus from the browser page with the video in it (i.e., switch to another window or tab). I found code on Github that counts page defocus and refocus events. However, the code does not seem to be designed for Qualtrics integration (recording the data), and it displays the page focus data on the screen.
I was able to modify the code to get it to record to embedded data in Qualtrics, but it only works when the PageFocus counter is displayed. I am hoping for any suggestions on how to make the counter invisible while still recording the data.
tl;dr -- I want to count how often participants switch to another tab/window when asked to watch a video in Qualtrics. I found code that will count page defocus events, but the data only record when the counter is visible on the screen. Can I make the counter invisible but still record the data?
<!DOCTYPE html>
<html>
<head>
<title>PageFocus Demo</title>
<style type="text/css">
body {
font-family: sans-serif;
}
.numeric_input {
text-align: right;
}
.footnote {
font-size: 0.8em;
}
#popup_warning {
display: none;
width: 500px;
height: 180px;
position: absolute;
background-color: #fff;
z-index: 255;
text-align: center;
padding: 0 20px 20px;
border: 5px solid red;
top: 50%;
left: 50%;
margin-left: -250px;
margin-top: -90px;
}
#popup_warning .ok_button {
margin-top: 20px;
}
#popup_warning .ok_button button {
width: 100px;
height: 30px;
}
#disabled {
display: none;
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
background: #707070;
filter:alpha(opacity=75);
opacity: 0.75;
z-index: 253;
}
</style>
</head>
<body>
<p><label>Page defocusing (D) and refocusing events (R):
<input type="text" id="events_input" name="events_input" size="80" readonly></label></p>
<p><label>Number of page defocusing events: <input class="numeric_input" type="text" id="defocus_count_input" name="defocus_count_input" size="4" value="0" readonly></label></p>
<p><label>Number of page refocusing events:
<input class="numeric_input" type="text" id="refocus_count_input" name="refocus_count_input" size="4" value="0" readonly></label></p>
<p><label>Duration between last page defocusing and last refocusing event (Duration of last absence):
<input class="numeric_input" type="text" id="last_duration_input" name="last_duration_input" size="10" value="0" readonly> seconds</label></p>
<p><label>Sum of all durations between page defocusing and refocusing events (Sum of all absence durations):
<input class="numeric_input" type="text" id="duration_sum_input" name="duration_sum_input" size="10" value="0" readonly> seconds</label></p>
<p></p>
<div id="popup_warning">
<h3>PageFocus warning</h3>
<p>You have just left this window which is not allowed while participating on the test. Please return to the test by confirming this message, and do not leave the test page again.</p>
<div class="ok_button"><button onclick='toggle_popup_warning("none"); regained_focus(); return false;'>OK</button></div>
</div>
<div id="disabled"></div>
<script type="text/javascript">
// PageFocus version 1.3-1 demo
var focus_data; // all page defocusing and refocusing events as one string
var defocusing_count; // number of page defocusing events
var refocusing_count; // number of page refocusing events
var last_duration; // duration between the last page defocusing and refocusing events
var duration_sum; // sum of all durations between page defocusing and refocusing events
var defocus_timestamp; // timestamp of last page defocusing event
var refocus_timestamp; // timestamp of last page refocusing event
var pagefocus = true; // does the current page have the focus?
var popup_visible = false; // is the popup currently being shown?
// input elements
var popup_checkbox = document.getElementById("popup_warning_checkbox");
var events_input = document.getElementById("events_input");
var defocus_count_input = document.getElementById("defocus_count_input");
var refocus_count_input = document.getElementById("refocus_count_input");
var last_duration_input = document.getElementById("last_duration_input");
var duration_sum_input = document.getElementById("duration_sum_input");
reset()
record_timestamp = function(type, timestamp) {
focus_data = focus_data + type + timestamp + ";"; // add new page focusing event to the data record
events_input.value = focus_data;
events_input.scrollLeft = events_input.scrollWidth; // scroll input field to the right
}
function lost_focus() { // page defocusing event detected
if(!popup_visible) {
pagefocus = false;
defocus_timestamp = new Date().getTime();
record_timestamp("D", defocus_timestamp);
defocusing_count++; // count the number of defocusing events
defocus_count_input.value = defocusing_count;
if(popup_checkbox.checked) toggle_popup_warning("block");
}
}
function regained_focus() { // page refocusing event detected
if(!pagefocus && !popup_visible) {
pagefocus = true;
refocus_timestamp = new Date().getTime();
record_timestamp("R", refocus_timestamp);
refocusing_count++; // count the number of refocusing events
refocus_count_input.value = refocusing_count;
last_duration = refocus_timestamp - defocus_timestamp; // calculate the duration between the last page defocusing and refocusing events
duration_sum += last_duration; // sum durations between page defocusing and refocusing events
last_duration_input.value = last_duration/1000;
duration_sum_input.value = duration_sum/1000;
}
}
function onfocusout() { // workaround for Internet Explorer < version 11
clearTimeout(timer);
timer = setTimeout(lost_focus,100);
}
function onfocusin() { // workaround for Internet Explorer < version 11
clearTimeout(timer);
regained_focus();
}
function reset() { // reset captured data
events_input.value = focus_data = '';
defocus_count_input.value = defocusing_count = 0;
refocus_count_input.value = refocusing_count = 0;
last_duration_input.value = last_duration = 0;
duration_sum_input.value = duration_sum = 0;
}
function toggle_popup_warning(state) { // show/hide popup warning
document.getElementById("popup_warning").style.display = state;
document.getElementById("disabled").style.display = state;
popup_visible = state == "block";
}
if("onfocusin" in document) { // check for Internet Explorer version < 11
var timer;
document.onfocusin = onfocusin;
document.onfocusout = onfocusout;
} else if("onpageshow" in window) {
// use onpageshow and onpagehide for mobile Safari
window.onfocus = window.onpageshow = regained_focus;
window.onblur = window.onpagehide = lost_focus;
}
</script>
</body>
</html>
Modified from this StackOverflow post.
Qualtrics.SurveyEngine.addOnload(function()
{
/*Place your JavaScript here to run when the page loads*/
$('NextButton').onclick = function (event) {
Qualtrics.SurveyEngine.setEmbeddedData("duration_sum", duration_sum);
Qualtrics.SurveyEngine.setEmbeddedData("focus_data", focus_data);
Qualtrics.SurveyEngine.setEmbeddedData("defocusing_count", defocusing_count);
Qualtrics.SurveyEngine.setEmbeddedData("refocusing_count", refocusing_count);
Qualtrics.SurveyEngine.setEmbeddedData("last_duration", last_duration);
Qualtrics.SurveyEngine.setEmbeddedData("defocus_timestamp", defocus_timestamp);
Qualtrics.SurveyEngine.setEmbeddedData("refocus_timestamp", refocus_timestamp);
// and now run the event that the normal next button is supposed to do
Qualtrics.SurveyEngine.navClick(event, 'NextButton')
}
});
The above code successfully records the objects/variables from the PageFocus code to Qualtrics embedded data, but only when I don't delete this section of the PageFocus code below (which seems odd to me, given that I think this segment just displays things on the page, but I could be wrong about that):
<p><label>Page defocusing (D) and refocusing events (R):
<input type="text" id="events_input" name="events_input" size="80" readonly></label></p>
<p><label>Number of page defocusing events: <input class="numeric_input" type="text" id="defocus_count_input" name="defocus_count_input" size="4" value="0" readonly></label></p>
<p><label>Number of page refocusing events:
<input class="numeric_input" type="text" id="refocus_count_input" name="refocus_count_input" size="4" value="0" readonly></label></p>
<p><label>Duration between last page defocusing and last refocusing event (Duration of last absence):
<input class="numeric_input" type="text" id="last_duration_input" name="last_duration_input" size="10" value="0" readonly> seconds</label></p>
<p><label>Sum of all durations between page defocusing and refocusing events (Sum of all absence durations):
<input class="numeric_input" type="text" id="duration_sum_input" name="duration_sum_input" size="10" value="0" readonly> seconds</label></p>
<p></p>
I'd appreciate any suggestions. Thank you!
Upvotes: 0
Views: 127
Reputation: 22247
You just need to change the record_timestamp
function to do your Qualtrics calls, and delete all the UI stuff (there's a popup that it produces - I dont know if that is needed but I assume not).
The final line of the record_timestamp
function below will throw an error. You'll need to find the best trigger method to use for sending all the embedded data to qualtrics, as Qualtrics.SurveyEngine.navClick might not be the right one.
// put all the data variables into a separate object
var fd = {};
function reset() { // reset captured data
fd.focus_data = '';
fd.defocusing_count = 0;
fd.refocusing_count = 0;
fd.last_duration = 0;
fd.duration_sum = 0;
fd.pagefocus = true;
}
reset();
record_timestamp = function(type, timestamp) {
fd.focus_data += type + timestamp + ";"; // add new page focusing event to the data record
console.log(fd);
// send collected data
/* this will break on SO snippet so commented out */
/*
Qualtrics.SurveyEngine.setEmbeddedData("duration_sum", fd.duration_sum);
Qualtrics.SurveyEngine.setEmbeddedData("focus_data", fd.focus_data);
Qualtrics.SurveyEngine.setEmbeddedData("defocusing_count", fd.defocusing_count);
Qualtrics.SurveyEngine.setEmbeddedData("refocusing_count", fd.refocusing_count);
Qualtrics.SurveyEngine.setEmbeddedData("last_duration", fd.last_duration);
if (type == "D")
Qualtrics.SurveyEngine.setEmbeddedData("defocus_timestamp", timestamp);
else if (type == "R")
Qualtrics.SurveyEngine.setEmbeddedData("refocus_timestamp", timestamp);
Qualtrics.SurveyEngine.navClick(event, 'NextButton')
*/
}
function lost_focus() { // page defocusing event detected
fd.pagefocus = false;
fd.defocusing_count++; // count the number of defocusing events
fd.defocus_timestamp = new Date().getTime();
record_timestamp("D", fd.defocus_timestamp);
}
function regained_focus() { // page refocusing event detected
if(!fd.pagefocus) {
fd.pagefocus = true;
fd.refocus_timestamp = new Date().getTime();
fd.refocusing_count++; // count the number of refocusing events
fd.last_duration = fd.refocus_timestamp - fd.defocus_timestamp; // calculate the duration between the last page defocusing and refocusing events
fd.duration_sum += fd.last_duration; // sum durations between page defocusing and refocusing events
record_timestamp("R", fd.refocus_timestamp);
}
}
function onfocusout() { // workaround for Internet Explorer < version 11
clearTimeout(timer);
timer = setTimeout(lost_focus,100);
}
function onfocusin() { // workaround for Internet Explorer < version 11
clearTimeout(timer);
regained_focus();
}
if("onfocusin" in document) { // check for Internet Explorer version < 11
var timer;
document.onfocusin = onfocusin;
document.onfocusout = onfocusout;
} else if("onpageshow" in window) {
// use onpageshow and onpagehide for mobile Safari
window.onfocus = window.onpageshow = regained_focus;
window.onblur = window.onpagehide = lost_focus;
}
Upvotes: 1