Javascript: Click 'Next' only if a Qualtrics page has not been viewed - javascript

Background
I have implemented (code below) a countdown timer in Qualtrics using the Javascript and CSS found in this post: http://codejaxy.com/q/55868/javascript-timer-qualtrics-qualtrics-progress-to-next-block-when-time-is-up# The exact code I have produced (which simply implements the solution proposed in that post) is found in the 'Current Code' section below.
The code for the countdown timer automatically clicks Next and advances to a new screen when time is up. Which screen it advances to is based on the display logic of each question following that on the current screen (see items 3 and 4 in 'Current Code').
Problem
While this can successfully move someone to the end of a timed section of a survey (i.e. once time is up, you are moved out of the timed section to another, subsequent set of questions that are untimed), it also causes the screen to advance even if one is finished with the timed section. In other words, if the intent is to move a person from any question in the timed question set X to the first question in the untimed question set Y after Z time has passed, if one answers all of the questions in X before Z time has passed, one will be moved from a question in Y to a subsequent question in Y. Essentially, one might end up skipping a question you want a person to answer rather than skipping the remainder of the timed section.
Question
Is there any way to have the code click "Next" only if a certain question has not been viewed? Or maybe reaching a certain point of the survey causes the blockTimeFlag to = 0 and not be changed when time runs out?
In other words, my goal is to not cause the participant to be unable to answer a question in an untimed block of questions because the screen advances automatically upon the timer indicating time is up while the participant has already completed that part.
Current Code
(1) Added the following custom CSS in the survey Look and Feel:
.header-cont {
width:100%;
position:fixed;
top:0px;
z-index:1000;
}
.header {
height:75px;
background:#FFFFFF;
width:100%;
margin:0px auto;
}
.timer{
margin: auto;
text-align: center;
vertical-align: middle;
font-size: 200%;
font-family: Arial;
}
(2) Created a 'Timing' question and included the following in the Javascript (note: this incorporates the solution offered in that post):
Qualtrics.SurveyEngine.addOnload(function()
{
var headerCont = document.createElement("div");
headerCont.className = "header-cont";
headerCont.id = "header_container";
var header = document.createElement("div");
header.className = "header"
header.id = "header_1";
var timer = document.createElement("div");
timer.className = "timer";
timer.id = "timer_1";
timer.innerHTML = "Time Remaining: <span id='time'>00:10</span>";
headerCont.appendChild(header);
header.appendChild(timer);
document.body.insertBefore(headerCont, document.body.firstChild);
function startTimer(duration, display) {
var timer = duration, minutes, seconds;
var myTimer = setInterval(function() {
minutes = parseInt(timer / 60, 10)
seconds = parseInt(timer % 60, 10);
minutes = minutes < 10 ? "0" + minutes : minutes;
seconds = seconds < 10 ? "0" + seconds : seconds;
var text = ('innerText' in display)? 'innerText' : 'textContent';
display[text] = minutes + ":" + seconds;
if (--timer < 0) {
clearInterval(myTimer);
timeOver();
}
}, 1000);
}
var timerSeconds = 5,
display = document.querySelector('#time');
startTimer(timerSeconds, display);
var timeOver = function() {
document.getElementById("timer_1").innerHTML = "Time is up.";
Qualtrics.SurveyEngine.setEmbeddedData("blockTimeFlag", "1");
$('NextButton').click();}
});
(3) Created an embedded data field in the survey flow before the timer containing blockTimeFlag = 0.
(4) Set the display logic for items based on blockTimeFlag = 0 (i.e. if the blockTimeFlag = 1 - which occurs when time is up - then the item is skipped0

I'm assuming your JavaScript is in the survey header or footer. If that is the case, you can put your code in an if statement that checks the value of an embedded variable. This would allow you to turn the timer on or off on a block by block basis by setting the value of the embedded variable.
Qualtrics.SurveyEngine.addOnload(function()
{
if("${e://Field/timerOnOff}" == "on"} {
var headerCont = document.createElement("div");
/* the rest of your code here... */
}
});

This feels like it has two solutions. One is rethinking the architecture of your code to make this an easier issue to solve, but I'm gonna post the quick and dirty solution that comes to my mind at the moment.
From what I understand, the user is advanced once the timer is up, even when they are already past the timed section, and you cannot interfere with the timer itself once it is set. Therefore, the easiest solution i can think of is:
Once the user hits the first question of section Y as you called it, alter the function timeOver(). Make it do whatever, just be careful not to set it to null, since it will still be called and would then throw an error.
If you want a more...structured solution, I would suggest making your timer globally available (or rather as far out as it has to be, global state isn't a good thing from what I know). Then, you can call clearInterval() as soon as the user proceeds to the first question of section Y.

Related

How do threads take up stack space?

So to start and avoid confusion, the code below is what sparked my thought, it doesn't necessarily have much to do much with my question except for an example to explain where my question is coming from.
I was just looking at some code in javascript here:
https://jsfiddle.net/Daniel_Hug/pvk6p/
var h1 = document.getElementsByTagName('h1')[0],
start = document.getElementById('start'),
stop = document.getElementById('stop'),
clear = document.getElementById('clear'),
seconds = 0, minutes = 0, hours = 0,
t;
function add() {
seconds++;
if (seconds >= 60) {
seconds = 0;
minutes++;
if (minutes >= 60) {
minutes = 0;
hours++;
}
}
h1.textContent = (hours ? (hours > 9 ? hours : "0" + hours) : "00") + ":" + (minutes ? (minutes > 9 ? minutes : "0" + minutes) : "00") + ":" + (seconds > 9 ? seconds : "0" + seconds);
timer();
}
function timer() {
t = setTimeout(add, .1);
}
timer();
/* Start button */
start.onclick = timer;
/* Stop button */
stop.onclick = function() {
clearTimeout(t);
}
/* Clear button */
clear.onclick = function() {
h1.textContent = "00:00:00";
seconds = 0; minutes = 0; hours = 0;
}
The person seemed to use recursion to make a stop watch, in timer and add.
If I do it recursively, by changing this function to this:
function timer() {
add();
}
it takes up stack space, and eventually breaks, stops some where under 3:00:00.
But then I realized in the original code they used setInterval(), which just creates a separate thread then ends the thread, releasing the stack space. The code just does this repeatedly which is why the stack doesn't seem to overflow.
What I am having a hard time understanding is how does this work on a lower level? In one of my courses I took, I was required to make my own memory allocator(which i understand takes up heap space), but we never had to worry about threads and am wondering how I will do it with this.
So lets say I have a thread, and then the kernel switches to another thread, and then another, then one thread ends and another one begins, I am assuming there is going to be gaps in the stack in between threads ending and being created, correct?. I read in another post (more related to java, not sure if programming language matters) that each thread takes its own space on the stack. So I was wondering, each time I make a thread, does it just fill in gaps like a memory allocator does? What if a thread ends up taking up too much space? Does the program know to realloc memory somewhere else? Am I thinking of this wrong?
Javascript is single threaded. See, for example, https://stackoverflow.com/questions/13504811. The main and the single javascript thread has one queue of ready tasks, and one queue of timed tasks. It cycles over the first queue until it is empty, then over the second queue until all timed tasks with exceeded time limit are executed, and the sleeps until new ready task appear, or time comes of some timed tasks.
Expression setTimeout(add, .1) just adds a task to the queue of timed tasks. It will be executed when the .1 timeout exceeded, and the main thread is able to execute next tasks.

display timer for every page starting from(00sec) in javascript

I created a quiz application using PHP. In that application I display one question per page. When user clicks on the next button, it displays the next question, one chosen randomly from database. So for that I want to display time.
But my problem is:
I want to display a timer from starting only seconds. When user clicks on the next button, first question timer is going to be stored in database and the timer will start(from 00:00) for the second question.
I tried a lot, but I don't have any idea how to do this.
It is better to use window.setInterval() in order for the timer to not rely on the system time. .setInterval will fire every n milliseconds. You can just increment using that
You can have:
var secondsCounter = 0;
function quizTimer(){
secondsCounter++;
}
window.setInterval(quizTimer, 1000);
Then you can display the time easily by using
myTimerElement.innerHTML = "Seconds Passed: " + secondsCounter;
Now you just have to do a little tweaking to make it appear in time format MM:SS
it could be
myTimerElement.innerHTML = minutesCounter + " : " + secondsCounter;
now just do some formatting methods or conditions to make the counter variables display two digits.
EDIT:
Check this snippet:
var secondsCounter = 0;
var startTime;
function restartTimer(){
secondsCounter = 0;
window.clearInterval(startTime);
startTime = window.setInterval(quizTimer, 1000);
}
function quizTimer(){
secondsCounter++;
document.getElementById('timer').innerHTML = "Seconds Passed: " + secondsCounter;
}
document.getElementById('btnsub').addEventListener('click', restartTimer);
<span id='timer'></span>
<button id='btnsub'>Submit</button>

Add a countdown in my scoring script (javascript/jquery)

I have the following script in a js file:
// Ad score
var score = 0;
//$('#score').text(score);
function foundMatchingBlocks(event, params) {
params.elements.remove();
score += 100;
$('#score').text(score);
};
Now on each matching, 100 points are added to var score. This all works. Now I want to extend this a bit. As soon as the page loads I want to start a countdown to reduce the number of points (starting with 100) with 1 point a second for 60 seconds. So the minimum number of points a user can get is 40. When someone gets the points, the counter should reset and countdown again.
Example:
Page loads (timer starts from 100)
User has a match after 10 seconds (+90 points are added)
Counter resets and countdown from 100 again
User found a match after 35 sec (+65 points are added)
etc etc
Problem is, I have no idea how to do this :( Hope someone can help me with this.
The above is fixed, thanks all for helping!!!
The big picture is, you'll need to become pretty familiar with timeouts and intervals in javascript. This is the reference page I keep going back to when I need to refresh my memory: http://www.elated.com/articles/javascript-timers-with-settimeout-and-setinterval/
For your specific task, you'll probably want to use an Interval that triggers every 1000 milliseconds to calculate the second-by-second point reduction, and a separate Timeout for failure that resets every time the user completes their challenge.
Here are a few tips for working with timeouts and intervals that usually lead to followup questions:
When you set a timeout, always capture the return value (I think it's basically a random integer). Save it to some global var for convenience.
var failureTimer; // global var high up in your scope
failureTimer = setTimeout ( "gameOver()", 100000 ); // 100 seconds * 1000ms
Then in whichever method gets called when the player completes their challenge, you call this:
clearTimeout (failureTimer); // resets the timer and gives them another 100 seconds
failureTimer = setTimeout ( "gameOver()", 100000 ); // yes call this again, to start the 100 sec countdown all over again.
The second pain point you're likely to encounter when working with Timeouts and Intervals is how to pass parameters to the functions like gameOver() in my example above. You have to use anonymous functions, as described here:
Pass parameters in setInterval function
For more on anonymous functions, this is a good overview:
http://helephant.com/2008/08/23/javascript-anonymous-functions/
Good luck with your project! Let me know if you have any questions.
Here's some code without the use of timers. Call startCountdown() every time you want to re-initialize the count-down. Call getAvailableScore() when you want to fetch the current available score. You will have to decide what to do when the available score goes to zero.
var beginCountDownTime;
function startCountdown() {
beginCountDownTime = new Date();
}
function getAvailableScore {
var now = new Date();
var delta = (now.getTime() - beginCountDownTime.getTime()) * 1000; // time elapsed in seconds
var points = 100 - (delta / 60);
return(Math.round(Math.max(points, 0))); // return integer result >= 0
}
Maybe something like:
// Ad score
var score = 0;
var pointsAvailable = 100;
//$('#score').text(score);
function foundMatchingBlocks(event, params) {
params.elements.remove();
score += pointsAvailable;
$('#score').text(score);
pointsAvailable = 100;
};
$(document).ready(function() {doTimer();});
function doTimer() {
setTimeout('reducePoints()',1000);
}
function reducePoints() {
if(pointsAvailable>40) {
pointsAvailable--;
}
doTimer();
}

Canvas scroll animation not working correctly

I'm building a gantt chart style timeline using html canvas element.
I am currently attempting to add the functionality which allows the user to click a next/prev button to have the gantt chart scroll to display earlier or later times.
The way I am doing this is to have a span.adjustTime where the id holds a value in seconds for the time to be adjusted (eg 86400 for one day).
I am trying to animate the scrolling so it looks like a scroll, rather than jumping ahead by one day.
I have a small problem in my timing calculation, but the script below is not animating, but rather jumping directly to the final time.
I do have the draw function running on a separate setInterval which updates every second, so I'm hoping it isn't an issue of conflicting timers on the same function on the same element and data.
jQuery('span.adjustTime').click(function() {
var adjustBy = parseInt(jQuery(this).attr('id').replace('a', ''));
var data = jQuery('img#logo').data();
for(var m = 1; m >= 30; m++) {
gantt.startUnixTime = gantt.startUnixTime + (adjustBy * (m * 0.001));
var moveTimer = setTimeout(function() {
draw(document.getElementById('gantt'), data, gantt);
}, 1000);
if (m == 30) {
clearTimeout(moveTimer);
}
}
});
In the for loop you are calling setTimeout 30 times, each time with the same timeout value of 1000. So after 1000 milliseconds 30 scheduled functions will execute at almost the same time. I suppose this is not what you intended. If you wanted an animation of 30 frames over 1000 milliseconds, the setTimeout should look something like:
setTimeout(function() { ... }, 1000 / 30 * m)
Also note that all 30 scheduled functions will see the same gantt.startUnixTime value, since the same object (gantt) is passed to all of them, and when they execute, the for loop has finished already long ago.

Counting down for x to 0 in Javascript?

I have from the backend a time on the format 00:12:54 and I display it to the screen. But, I would like to have this time to continue to go down. I have though to create a variable in javascript that will old the time and with setTimeout to loop to display with document.getElementById the new value. I think it can be problematic if I have many time to go down in same time. I might require an array?
How would you do that? If I have no other suggestion, I will try my way, but I am curious to know if it does have a more secure way to do it.
Do you know jQuery Framework? It's a Javascript framework that have a lot of utilities methods and functions that let you do Javascript stuff more easily.
Here is a count down plugin (haven't tested it).
I suggest you to download JQuery than download the plugin . Check the sample of code from the "relative" tab on the website. You can have something like :
$('#until2d4h').countdown({until: '+12M +54S'});
*The only drawback with what I suggest you is that you will require 2 .js to be added. Try to add them only when needed and you will be find.
General algorithm:
Read time from server.
Read the current time.
Call a function.
In your function, read the current time, get the delta from the initial time you read in step 2.
Subtract the delta from the initial time you read from the server in step 1 and display the remainder.
The function should call window.setTimeout to call itself in 1000ms (or adjust according to time elapsed within the function), if you want to continue counting down.
Here's a rough cut:
window.onload = function () {
var countdown_start_in_ms = 6000; // from server
function tick() {
var now = new Date().getTime();
var disp = start - now;
if (disp < 0) {
disp = 0;
}
var el = document.getElementById("countdown");
el.innerHTML =
// quick hack to format time
/(\d\d:\d\d:\d\d) ...$/.exec(new Date(disp).toUTCString())[1];
if (disp > 1000) {
var elapsed = new Date().getTime() - now;
window.setTimeout(tick, 1000 - elapsed);
} else {
// stop countdown and set color to light grey
el.style.color = "#ccc";
}
}
var start = new Date().getTime() + countdown_start_in_ms;
tick();
}
You won't like the taste of this one, but it'll do you good:
Google for 'javascript timer' and get your hands dirty reading through the various examples and tutorials returned by that search.
You'll learn a lot more than just how to write a count-down timer. :-)
Good luck!
Take a look at Grab hands and set your own time. and inspect its code. While it is written with Dojo, the "clock" part is in plain JavaScript. In your case the only difference is how to advance the counter — decrease rather than increase it.

Categories

Resources