Prevent js alert() from pausing timers

So I made some timers for a quiz. The thing is, I just realized when I put

javascript: alert("blah");

in the address, the popup alert box pauses my timer. Which is very unwanted in a quiz.

I don't think there is any way to stop this behaviour... but I'll ask anyway.

If there is not, mind suggesting what should I do?

Answers:

Answer

Apparently the preview rendering differs from the posted rendering. This paragraph is here to make sure the next two lines show up as code.

// Preserve native alert() if you need it for something special
window.nativeAlert = window.alert;

window.alert = function(msg) {
    // Do something with msg here. I always write mine to console.log,
    // but then I have rarely found a use for a real modal dialog,
    // and most can be handled by the browser (like window.onbeforeunload).
};
Answer

Never, ever rely on javascript (or any other client-side time) to calculate elapsed times for operations done between postbacks, or different pages.

If you always compare server dates, it will be hard for people to cheat:

  1. first page request, store the server time
  2. ping with javascript calls each N seconds, compare the 2 server times, and return the elapsed (just for show)
  3. when the user submits the form, compare the 2 server times, calculate the elapsed time, and discard the ones which took too long (ie: possible cheaters)
Answer

No, there is no way to prevent alert from stopping the single thread in JavaScript. Probably you can use some other way of user notification, for example a floating layer.

Answer

It's modal and stops execution. Consider an alternative which does not pause execution like a Lightbox technique.

Answer

I think the question asker is trying to prevent cheating. Since a user can type javascript: alert("paused"); into the address bar, or make a bookmarklet to do that, it's easy to pause the quiz and cheat.

The only thing I can think of is to use Date() to get the current time, and check it again when the timer fires. Then if the time difference is not reasonably close to the intended timer duration, show an admonishment and disqualify the answer to that question or let them flunk the quiz. There is no way to prevent the user from pausing your quiz, but it should be possible to catch them.

Of course with any cheat-proofing, you motivate people to become better cheaters. A person could change the system time on their PC, and fool the javascript Date() constructor which gets the time from the operating system.

You can use an interval to do a repeated clock comparison against a one second interval length. The interval handler can also update a time-remaining field on the user's display. Then the users can feel the pressure build as time runs out on their quiz. Fun times!

Answer

The feedback loop on SyaZ's question has clarified the issues at stake.

Here's an attempt to summarize the good answers so far:

  • Client scripts are by nature are easy to manipulate to cheat an online quiz. SEE @Filini 's Server-side approach

  • window.alert = function(msg) {} will overriding alert() and perhaps defeat the low hanging fruit of putting in the addressbar: javascript:alert('Pausing page so I can google the answer') or I'll use my Phone-A-Friend now. Courtesy of @eyelidlessness

  • If you must use a client-side approach, instead of using setTimeOut(), you could use a custom date-compare-based pause function like this (concept by @Mnebuerquo, code example by me (@micahwittman)):

Example:

var beginDate = new Date();

function myTimeout(milsecs){
  do { curDate = new Date(); }
    while((curDate-beginDate) < milsecs);
}

function putDownYourPencils(milsecs){
  myTimeout(milsecs);
  var seconds = milsecs / 1000;
  alert('Your '  + seconds + ' seconds are up. Quiz is over.');
}

putDownYourPencils(3000);
Answer

Ultimately, you cannot trust user input. Without keeping track of the time elapsed on the server, there's just no guarantee the data hasn't been manipulated.

However, if you're confident your quiz-takers aren't JavaScript-savvy, and are merely relying on a "trick" they found somewhere, you could test for cheating (pausing) with the following code, which doesn't require modifying window.alert:

var timer = {
    startDatetime: null,
    startSec: 0,
    variance: 1,
    exitOnPause: true,
    count: function (config) {
        var that = this;

        if (typeof config == "object" && typeof parseInt(config.seconds) == "number" && !isNaN(parseInt(config.seconds)))
        {
            if (typeof parseFloat(config.variance) == "number" && !isNaN(parseFloat(config.variance))) this.variance = config.variance;
            if (typeof config.exitOnPause == "boolean") this.exitOnPause = config.exitOnPause;

            if (config.seconds > 0)
            {
                if (!this.startSec) this.startSec = config.seconds;
                if (!this.startDatetime) this.startDatetime = new Date();
                var currentDatetime = new Date();

                if (currentDatetime.getTime() - this.startDatetime.getTime() > (this.startSec - config.seconds) * this.variance * 1000)
                {
                    if (typeof config.onPause == "function") config.onPause();

                    if (!this.exitOnPause)
                    {
                        this.startDatetime = new Date();
                        this.startSec = config.seconds--;
                        window.setTimeout(function () { that.count(config); }, 1000);
                    }
                }
                else
                {
                    config.seconds--;
                    window.setTimeout(function () { that.count(config); }, 1000);
                }
            }
            else
            {
                if (typeof config.onFinish == "function") config.onFinish();
            }
        }
    }
};

This timer object has a single method, count(), which accepts an object as input. It expects a seconds property in the input object at minimum.

For some reason, window.setTimeout doesn't always work as expected. Sometimes, on my machine, window.setTimeout(x, 1000), which should execute the code after 1 second, took more than 2 seconds. So, in a case like this, you should allow a variance, so people who aren't cheating don't get flagged as cheaters. The variance defaults to 1, but it can be overridden in the input object. Here's an example of how to use this code, which allows 2.5 seconds of "wiggle room" for slow-pokes:

timer.count({
    seconds: 10,
    onPause: function () { alert("You cheated!"); window.location.replace("cheatersAreBad.html"); },
    onFinish: function () { alert("Time's up!"); },
    variance: 2.5
});

With a solution like this, you could use Ajax to tell a server-side script that the user has paused the timer or redirect the user to a page explaining they were caught cheating, for example. If, for some reason, you wanted to allow the user to continue taking the quiz after they've been caught cheating, you could set exitOnPause to false:

timer.count({
    seconds: 10,
    exitOnPause: false,
    onPause: function () { recordCheaterViaAjax(); },
    onFinish: function () { alert("Time's up!"); },
    variance: 2.5
});
Answer

The server session could be set to expire at say 1 hour. The javascript could be used as only a display tool for the user to know how much time is left. If he decides to cheat by pausing the timer, then he might be suprised when posting his test that his session has timed out.

Tags

Recent Questions

Top Questions

Home Tags Terms of Service Privacy Policy DMCA Contact Us

©2020 All rights reserved.