Notifying a user that they are leaving a form involves a few simple steps.
Adding some much needed jQuery goodness.
Add the javascript file via hook_form_alter
function phase2_form_alter(&$form, $form_state, $form_id) {
if (isset($form['type']) && isset($form['#node']) && $form['type']['#value'] . '_node_form' == $form_id) {
drupal_add_js(drupal_get_path('module', 'phase2') . '/node-edit-protection.js');
}
}Then in your javascript file, I called mine node-edit-protection.js you should define a reusable confirm function.
Drupal.phase2 = {};
Drupal.phase2.confirmNavigate = function() {
return confirm("You are about to leave the edit form.\nIf you need to save your work click cancel.");
};Catching any modification to a form element. This marks the form as dirty.
I am catching the blur event as a means of marking the form as dirty. So I want to grab each and every input item on the node form and when the blur event happens I want to set the dirty flag.
$(".node-form :input").each(function() {
$(this).blur(function() {
$(window).attr('phase2_confirm_edited', true);
});
});Allow node form submit button clicks to pass through
We don’t want to prompt the user to confirm a save/process on the page that they meant to do, so for all of the submit buttons on the node form, set a flag that tells all that would make us confirm that this was intended. We also add a processed class to the form buttons because we don’t want to attach a notification check (in the next step) to form submit buttons.
$(".node-form input[@type='submit']").each(function() {
$(this).addClass('processed');
$(this).click(function() {
$(window).attr('phase2_confirm_clicked', true);
});
});Catching any link or button click that may take them to another page, and if the form is dirty confirming the move with the user.
For all other links or buttons (or form buttons) on the page, if they are clicked and the form is dirty, confirm the request to load another page. Note the :not(.processed), this is how we tell it to ignore registering a click handler on the main form submit buttons themselves (that is why we added the class to them in the previous step).
$("a, button, input[@type='submit']:not(.processed)").each(function() {
$(this).click(function() {
var edited = $(window).attr('phase2_confirm_edited');
if(edited) {
$(window).attr('phase2_confirm_clicked', true);
return Drupal.phase2.confirmNavigate();
}
});
});As a last resort, catching a window unload event which is triggered when the browser is leaving the current URL and loading another.
If we miss something that is not a link or button and the form is dirty and it was not an allowed submit click, then we need to notify the user as well.
$(window).unload(function() {
var clicked = $(this).attr('phase2_confirm_clicked');
var edited = $(this).attr('phase2_confirm_edited');
if(edited && !clicked) {
return Drupal.phase2.confirmNavigate();
}
});Finally don’t forget to put the previously mentioned Javascript into the Drupal.behaviors setup as such:
Drupal.behaviors.nodeEditProtect = function (context) {
// Put all your junk here
};Hope this helps everyone and does not make your users want to put you in a burlap sack and beat you with reeds.


Delicious
Digg
StumbleUpon
Reddit
Technorati
Seems like a great candidate for a module… why not package it up and release it rather than having everyone have to roll their own?
http://drupal.org/project/node_edit_protection
I definitely want to do that. Just looking for a shred of time to make it happen. It will be out there soon. :)
nm. I see later down that we’re only working only with node-edit forms.
It might be an idea to prefix your window attributes to avoid namespace conflicts and to make it make sense when your viewing the page in firebug. i.e.
$(window).attr(‘phase2_confirm_close_edited’, true);
Yes, that is a smart idea. I added it to the content above. Thanks!
Just wondering what these acrobatics are for:
<?phpif (isset($form['type']) && isset($form['#node']) && $form['type']['#value'] . '_node_form' == $form_id) {
?>
Since the form id varys depending on which type of node you are editing, this hoop jumping is to determine if it is an actual node edit form you are attempting to alter. It says:
1. Is the node type set on the form
2. Is the node set on the form (are we actually editing a node)
3. And is the form id generally of the story_node_form, page_node_form variety.
This is a limitation of the current FAPI. This will be changing in D7. http://drupal.org/node/161301