2

Fiddle: http://jsfiddle.net/qfn04xzj/

var a, b;
$('input:not([type=password]), textarea, select').on('focus', function(event) {
    a = performance.now();
});
$('input:not([type=password]), textarea, select').on('blur', function(event) {
    b = performance.now();
    $('#console').append( $(this).attr('name') + ' took ' + (b - a) + ' ms.' + "<br/>");
});

... works but it measures time between focus and blur.

Is there any way I could measure the actual time — the time it took to type or time between two value changes?

eozzy
  • 66,048
  • 104
  • 272
  • 428
  • I am a little confused by your question. Isn't it already computing the time an user took to type the value? – jjk_charles Dec 21 '14 at 13:49
  • Do you mean something like [this](http://jsfiddle.net/L0thhzus/)? – raina77ow Dec 21 '14 at 13:50
  • No, it computes the time from `focus` to `blur`, so it includes the idle inactivity time which i want to eliminate. The user may have just focused the field and went away to have a cup of coffee, or switched the tab. – eozzy Dec 21 '14 at 13:51
  • @raina77ow on `input`? but its not accurate, try typing "hi there" and see the times it computes. – eozzy Dec 21 '14 at 13:58
  • Not sure what do you mean, to be honest. You can intercept `keydown` event instead, though; just check whether or not the key pressed will actually change the value of an input. – raina77ow Dec 21 '14 at 14:00
  • Check if [http://jsfiddle.net/qfn04xzj/2/](http://jsfiddle.net/qfn04xzj/2/) satisfies our requirement! I couldn't think of anything else! – jjk_charles Dec 21 '14 at 14:05
  • Just asking my-self how you measure the copy-paste activity? – Roko C. Buljan Dec 21 '14 at 14:17
  • Also (sadly) `performance.now` is not supported by Safari and IE<10 – Roko C. Buljan Dec 21 '14 at 14:20
  • @RokoC.Buljan I could use a polyfill for compatibility. I'm checking for paste event separately, yes it wont add to the time but thats fine. – eozzy Dec 21 '14 at 15:43

3 Answers3

2

You should first define what actual time means. If you mean the time between the first and last keystroke, then the following code should work. It creates an object for each time the user focuses on the input and listens for every keystroke, keeping record of the first and last keystrokes. When the input is blurred, it computes the difference between the two.

Of course, the user can still type a couple of characters, go for a cup of coffee and then return and type the others, which will result in a very long time of activity. There is no way to know how much time the user has spent actually staring at the input. You could, however, define a "timeout" or period of inactivity after which you assume that the user is idle.

Fiddle

$('input:not([type=password]), textarea, select').on('focus', function() {
    new EditingSession($(this));
});

/** 
 * Represents the period of time during which the user is focused on
 * the input.
 */
function EditingSession(input){

    var firstKeydownTime = null;
    var lastKeydownTime = null;
    var sessionId = makeRandomId();

    input.on("keydown." + sessionId, function(){
        // User typed something
        var time = performance.now();
        lastKeydownTime = time;
        if(firstKeydownTime === null){
            firstKeydownTime = time;
        }
    });

    input.on("blur." + sessionId, function(){
        // Editing session finished.

        // Detach all handlers
        input.off("." + sessionId);

        // Print time between first and last keydown
        var time;
        if(firstKeydownTime === null){
            time = 0;
        } else {
            time = lastKeydownTime - firstKeydownTime;
        }
        $('#console').append(input.attr('name') + ' took ' + time + ' ms.' + "<br/>");
    });

}

// Borrowed from http://stackoverflow.com/questions/1349404/generate-a-string-of-5-random-characters-in-javascript    
function makeRandomId() {
    var text = "";
    var possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";

    for( var i=0; i < 5; i++ )
        text += possible.charAt(Math.floor(Math.random() * possible.length));

    return text;
}
abl
  • 5,970
  • 4
  • 25
  • 44
1

Instead of getting the time difference between keydown and keyup (which is silly :)) you need to simply get one single performance.now() timestamp and store it into a b variable for a later "input" event time-difference comparison.

var $fields  = $('input:not([type=password]), textarea, select'),
    $console = $("#console"),
    $total   = $("#totTime"),
    tot=0, a=0, b=0;

$fields.on('input', function() {
    a = performance.now();
    var diff = (a - b)|0; // |0 prevents floated results (happens in FF)
    $console.append( this.name +" took "+ diff +" ms"+ this.value +"<br>");
    $total.text("Total time: "+ (tot+=diff) +" ms");
    b = a;                // Store a into b for later use.
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="totTime"></div>
<input type="text" name="" id="">
<div id="console"></div>

Performance-wise (since you're dealing with hopefully time accuracy) cache your Elements selectors into variables, that way you'll prevent parsing again the DOM in the search for your elements on every input event.
Also "input" as event is quite enough to handle all you need from copy-paste, change etc...

Roko C. Buljan
  • 196,159
  • 39
  • 305
  • 313
0

This will give you total time typing: Fiddle

<input type="text" name="" id="">
<div id="total"></div>
<div id="console"></div>

JS

$('input:not([type=password]), textarea, select').on('input change keyup', function (event) {
    if (event.type == 'input') {
        $('#console').append("input: " + $(this).val() + "<br/>");
    }
    if (event.type == 'change') {
        $('#console').append("change: " + $(this).val() + "<br/>");
    }
});

var a, b, total = 0;
$('input:not([type=password]), textarea, select').on('keydown', function (event) {
    a = performance.now();
});
$('input:not([type=password]), textarea, select').on('keyup', function (event) {
    b = performance.now();
    var net = (b - a);
    $('#console').append($(this).attr('name') + ' took ' + net + ' ms.' + "<br/>");
    var final = total += net;
    $('#total').text('Total time typing: ' + final + ' ms.');
});
Tomanow
  • 7,247
  • 3
  • 24
  • 52