Saving data in case of brower crashes
So a few days ago I posted a question on the BlogCFC blog about whether I should add "crash protection" to the BlogCFC entry editor. What did I mean by that? As much as I love Firefox, it isn't the most stable beast in the world. That wouldn't matter so much except that I tend to get a bit worried when writing a particularly long blog entry. In the past I've used Word to write long entries since I know Word will automatically save my text even if I forget to. While BlogCFC does support XML-RPC clients, none of them have really caught on with my writing style so I haven't been using them.
Over on cf-talk, Jacob Munson mentioned that Blogger (I think that's some other blogware product - anyone heard of it? ;) will automatically save a draft of your blog entry every few seconds. I decided to take a look at how hard this would be to add to BlogCFC. Turns out it wasn't hard at all. I figured other people may benefit from this as a possible feature they could add to their own products.
So first off - let me talk a bit about the technique. The idea is simple: Every N seconds store the contents of the blog entry to a JavaScript cookie. Add code on the server side to check for this cookie when first displaying the form. Also add code to clean up the cookies when an entry has been stored.
For BlogCFC I decided to be lazy and only store two things - the title and body of the blog entry. Here is the JavaScript code I ended up using:
//used to save your form info (title/body) in case your browser crashes
function saveText() {
var titleField = $("title");
var bodyField = $("body");
var expire = new Date();
expire.setDate(expire.getDate()+7);
//write title to cookie
var cookieString = 'savedtitle=' + escape(titleField.value)+'; expires=' + expire.toGMTString() + '; path=/';
document.cookie = cookieString;
cookieString = 'savedbody=' + escape(bodyField.value) + '; expires=' + expire.toGMTString() + '; path=/';
document.cookie = cookieString;
window.setTimeout('saveText()',5000);
}
window.setTimeout('saveText()',5000);
The first thing I want to point out are these two lines:
var titleField = $("title");
var bodyField = $("body");
These are Spry (copied from Prototype) shorthands for:
var titleField = document.getElementById("title");
var bodyField = document.getElementById("body");
Outside of that - everything else is vanilla JavaScript. JavaScript lets you add cookies by simply setting the document.cookie value. Also note that document.cookie isn't a simple string. If you run document.cookie = something multiple times, you end up with multiple cookies.
The format for a cookie string is name=value; expires=DATE; path=PATH. In my case I simply used a cookie that expires in 7 days and a path of /.
Lastly I have a window.setTimeout, both outside of the function and inside, that will run this code every 5 seconds. Any duration is fine really.
To restore the values, I used this set of code on the server side:
<cfif not structKeyExists(form, "title") and structKeyExists(cookie, "savedtitle")>
<cfset form.title = cookie.savedtitle>
</cfif>
<cfif not structKeyExists(form, "body") and structKeyExists(cookie, "savedbody")>
<cfset form.body = cookie.savedbody>
</cfif>
Basically I simply ensure that I'm not already posting and see if I have anything in the cookie. I clear out the cookies using this code:
<cfcookie name="savedtitle" value="" expires="now">
<cfcookie name="savedbody" value="" expires="now">
As you can see, this is a pretty trivial implementation. Anyone else using something like this in their applications?
Comments
Just remember that there's a 4k cookie limit per domain (the total size of the document.cookie can not be more than 4k.) So, your techinique is going to cause problems for large blog entries.
I'd actually recommend just posting the data back to the server (either via AJAX or an IFRAME) and then have the server store the data. You could do this in the db or just use a persistant variable.
As soon as user actually saves the entry, delete the auto-save copy from the server.
The universe is back in order! ;)
Just remember that any embedded HTML in the blog entry will quickly add to the total size of the cookie. Also, remember that the 4K limit isn't per cookie, it's for all the cookies on the domain.
I'm not sure how much markup you have in this blog entry, but the text alone is about 3.7K. While I'm sure most posts are well under 4K, any extensive blog entry w/lots of source code or examples is probably going to break the 4K limit.
It's really not that much work to simply post the data back to the server using AJAX or an IFRAME. It's actually really easy w/an IFRAME. Just add an IFRAME and setTimeout() to your page to automatically submit the form to the IFRAME every XX seconds or so.
If you're gonna make it with Spry, I'd like it if you put an option in the admin to set the time limit, and possible to turn it off. The management at my job are a bunch of Nazis when it comes to Internet usage, and I'd prefer to just turn that feature off if I'm at work (every http hit adds 3 min to my 'bill'). :)


We had problems with cookie length and people screwing with the cookie settings on their browser, so when I implemented the feature, cookies weren't even an option.