Don't lose your changes in web forms when you accidentally close your browser window.
It's becoming more and more common for complex tasks to be performed on the Web. Of course, there is web-based email, and weblogging and wikis are also popular. Message boards are a great way to form a community, and there are many more online applications that are used every day by many people. One of the drawbacks, though, in not using a normal desktop program is losing that prompt, "Are you sure you wish to exit? You have unsaved work."
With Greasemonkey, we can restore this functionality and save the hassle caused by closing a window and losing your unsubmitted form data.
This script uses the power of the onbeforeunload
event to catch the browser just before it moves off the page. When the page loads, the script finds all <textarea>
elements and records the initial value of each one. Then, we register an onbeforeunload
event handler to call our function that checks the current value of each <textarea>
. If the current value differs from the previously recorded value, we display a dialog box to give the user the chance to save his work.
To make sure we don't interfere when the user actually submits the form, the script attaches an onsubmit
event handler to all forms. This handler sets an internal flag to record that the user submitted the form and that we should not bother checking for unsubmitted data, since the user just submitted it!
Save the following user script as protect-textarea.user.js:
// ==UserScript== // @name Protect Textarea // @namespace http://www.arantius.com/ // @description Confirm before closing a web page with modified textareas // @include * // @exclude http*://*mail.google.com/* // ==/UserScript== // based on code by Anthony Lieuallen // and included here with his gracious permission // http://www.arantius.com/article/arantius/protect+textarea/ //indicator to skip handler because the unload is caused by form submission var _pt_skip=false; var real_submit = null; //find all textarea elements and record their original value var els=document.evaluate('//textarea', document, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null); for (var el=null, i=0; el=els.snapshotItem(i); i++) { var real_el = el.wrappedJSObject || el; real_el._pt_orig_value=el.value; } //if i>0 we found textareas, so do the rest if (i == 0) { return; } //this function handles the case where we are submitting the form, //in this case, we do not want to bother the user about losing data var handleSubmit = function() { _pt_skip=true; return real_submit(); } //this function will handle the event when the page is unloaded and //check to see if any textareas have been modified var handleUnload = function() { if (_pt_skip) { return; } var els=document.getElementsByTagName('textarea'); for (var el=null, i=0; el=els[i]; i++) { var real_el = el.wrappedJSObject || el; if (real_el._pt_orig_value!=el.value) { return 'You have modified a textarea, and have not ' + 'submitted the form.'; } } } // trap form submit to set flag real_submit = HTMLFormElement.prototype.submit; HTMLFormElement.prototype.submit = handleSubmit; window.addEventListener('submit', handleSubmit, true); // trap unload to check for unmodified textareas unsafeWindow.onbeforeunload = handleUnload;
After installing the user script (Tools → Install This User Script), go to http://www.iupui.edu/~webtrain/tutorials/forms_sample.html . At the bottom of the form is a large box for entering additional comments. Enter some text, and then try to close the browser window. You will see a confirmation dialog, as shown in Figure 4-5.
If you press Cancel, you'll stay right where you are and can submit the form. If you press OK, the browser window will close.
This hack can easily be extended to monitor all form fields, not just <textarea>
elements. Instead of using document.getElementsByTagName
to find only <textarea>
elements, we can use an XPath expression to look for <input>
elements, too.
var els=document.evaluate('//textarea|//input'
, document, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null); for (var el=null, i=0;el=els.snapshotItem(i);
i++) { … }
This will cause the script to protect all form fields containing text boxes, checkboxes, and radio buttons. It will not handle drop-down select boxes, though, because they function differently. It's more complicated than just adding //select
to the XPath expression and examining the selectedIndex
attribute of the <select>
element, because some <select>
boxes have multiple selections.
—Anthony Lieuallen
Get Greasemonkey Hacks now with the O’Reilly learning platform.
O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.