6

I'd like to be able to record then playback whatever happened in a textarea.

I've came across some solutions but they're not reliable, Like sending each keystroke via AJAX. In that case i'll end up having millions of rows in my DB.

The idea that i had in mind is to log the keystrokes to a variable in client side, updating that variable with the action, but keeping track of time between each keystoke. Also making sure that it supports deleting data as well.

At the end i'd send this whole variable to the db one time, then i can decode it later for playback.

Mind Map of what the variable would look like:

 hellooo[1.2][backspace][0.6][backspace]World![return]
Idle time __^ Removes one char __^

I believe that google docs is doing something like that to playback whatever users were typing.

Any Ideas?

asked Nov 9, 2011 at 20:45

3 Answers 3

10

Luckily JavaScript events already take care of all the encoding issues for you. You can just toss the whole event object that a keyup/keydown/keypress/whatever was directly into an array.

Each object contains:

  • Type of event
  • Timestamp
  • What key was used (or combination of keys)
  • What was in focus
  • Some other stuff that might end up being useful.

You can then just encode the array and send it off with your favourite ajax method to the server for storage.

So your code only needs a function that can store data. Don't use this exact function it's just for demonstration purposes.

var handler = function (e) { 
 handler.data.push(e);
 console.log(handler.data);
}
handler.data = [];
window.addEventListener("keyup", handler); 
window.addEventListener("keydown", handler); 
window.addEventListener("keypress", handler);

Since it's an array, they should all be in order, but in the odd event it goofs, you have timestamp data on each event (which also lets you find out the delay between events, which is AWESOME if you have mixed keypresses.).

You can then replay events however you wish to design them -- but now you don't have to invent your own spec because the lovely fokes at w3c did all the hard work for you when they designed the DOM event spec.

answered Nov 9, 2011 at 21:09
Sign up to request clarification or add additional context in comments.

5 Comments

I like your answer, very clear and in point, I forgot about serializing a javascript array of events. +1
Thanks @Ryan glad you found it helpful.
I'm trying to trigger the event by using: $('#playback').trigger(e); but it doesn't type in the character, I assume it only triggers the callback function, Any ideas? and how's your approach to moving cursor by mouse?
@Ryan My method fully records all data that happened and when it happened for any events you bind to the handler. I'm not overly familiar with jQuery's .trigger however.
I'm actually stuck at re firing the events on a new textarea, doesn't type in but seems to receive the events though.
5

Store the time of each action and the result of that action and when you are finished serialise the log and store that.
It is over-complicated to replay each action individually. Say a user moves back a few characters and adds new ones there. You will need to keep track of the cursor position.
Just remember the entire value of the textarea for each keystroke. There is no need to remember how that occurred is there?

Here's an implementation. fiddle

<textarea id="recorder"></textarea>
<textarea id="playback"></textarea>
<script type="text/javascript">
var Playback = {
 //store the time an action occured and the resulting state in an object
 //don't use an array because they are not sparce - interstitial keys
 //will have to be iterated over
 record: {},
 init: function( recorderId, playbackId ) {
 this.recorder = document.getElementById( recorderId );
 this.playback = document.getElementById( playbackId );
 this.recorder.addEventListener( 'focus', function() {
 Playback.record = {};
 this.value = '';
 }, false );
 this.recorder.addEventListener( 'keyup', function( e ) {
 Playback.record[ (new Date()).getTime() ] = this.value;
 }, false );
 this.recorder.addEventListener( 'blur', function( e ) {
 Playback.playback.value = '';
 //store the time the sequence started
 //so that we can subtract it from subsequent actions
 var mark = null;
 for( var t in Playback.record ) {
 if( mark ) {
 var timeout = t - mark;
 } else {
 var timeout = 0;
 mark = t;
 }
 // We need to create a callback which closes over the value of t
 // because t would have changed by the time this is run
 setTimeout( Playback.changeValueCallback( Playback.record[t] ), timeout );
 }
 }, false );
 },
 changeValueCallback: function( val ) {
 return function() { Playback.playback.value = val }
 }
}
Playback.init( 'recorder', 'playback' );
</script>

Caveat: The event handling is for compliant browsers only, you'd need to accommodate internet explorer yourself

answered Nov 9, 2011 at 22:08

1 Comment

Thanks @meouw, seems to be like a quick n dirty alternative, I like that too but it takes so much more storage because when the textarea's value gets bigger, it gets duplicated more and more until it becomes a huge 200MB file after a while of typing :D
0

Databases are made to handle millions of records, so that's not really a problem.

If you still don't want to do that you could encode all the data related to a session as JSON and store it in a text field in the database or as a file on the server. In this case if the data is really large it may take a while to load the data and send it to the browser, causing a delay for the user.

answered Nov 9, 2011 at 21:29

2 Comments

Servers AREN'T made to handle millions of ajax queries, Atleast my servers. +1 for Abusing the internet with useless requests.
I definitely wouldn't make one request for every event to log. Many events can be sent together in each request.

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.