Michael Winter wrote:
As an event property assignment:
window.onbeforeunload = function() {
return 'This is the prompt text.';
};
The documentation uses the proprietary event.returnValue property
instead of a return statement, but the result is the same.
Not quite. The return statement won't have the desired effect on IE, and
event.returnValue won't have any effect on Mozilla. To write code which
works on both you have to use both.
window.onbeforeunload = function(event) {
var msg = 'This is the prompt text.';
if (!event) event = window.event;
if (event) event.returnValue = msg;
return msg;
};
Also note that if you use Mozilla's addEventHandler method to add handler
function, Mozilla will ignore the return value totally (so the function
gets called, but nothing you can do will make it pop up the warning box).
Here's a longer example (but still self-contained) which implements a
warning box whenever you try to navigate away from a page with a modified
form.
The original is at
http://codespeak.net/svn/kupu/trunk/...eforeunload.js,
documentation at
http://codespeak.net/svn/kupu/trunk/...FOREUNLOAD.txt, license at
http://codespeak.net/svn/kupu/trunk/...oc/LICENSE.txt. Add a call to
window.onbeforeunload.tool.addForms() to enable checking.
/* BeforeUnload form processing */
if (!window.beforeunload) (function() {
var BeforeUnloadHandler = function() {
var self = this;
this.message = "Your form has not been saved. All changes you have
made will be lost";
if (window._) {
this.message = _("Your form has not been saved. All changes you
have made will be lost");
};
this.forms = [];
this.chkId = [];
this.chkType = new this.CheckType();
this.handlers = [this.isAnyFormChanged];
this.submitting = false;
this.execute = function(event) {
if (self.submitting) return;
if (!event) event = window.event;
for (var i = 0; i < self.handlers.length; i++) {
var fn = self.handlers[i];
var message = message || fn.apply(self);
}
if (message===true) message = self.message;
if (message===false) message = undefined;
if (event) event.returnValue = message;
return message;
}
this.execute.tool = this;
}
var Class = BeforeUnloadHandler.prototype;
// form checking code
Class.isAnyFormChanged = function() {
for (var i=0; i < this.forms.length; i++) {
var form = this.forms[i];
if (this.isElementChanged(form)) {
return true;
}
}
return false;
}
Class.addHandler = function(fn) {
this.handlers.push(fn);
}
Class.onsubmit = function() {
var tool = window.onbeforeunload && window.onbeforeunload.tool;
tool.submitting = true;
}
Class.addForm = function(form) {
for (var i = 0; i < this.forms.length; i++) {
if (this.forms[i]==form) return;
}
this.forms.push(form);
form.onsubmit = this.onsubmit;
var elements = form.getElementsByTagName('input');
for (var j = 0; j < elements.length; j++) {
var ele = elements[j];
if (ele.type=='hidden') {
ele.setAttribute('originalValue', ele.defaultValue);
}
}
}
Class.addForms = function() {
for (var i = 0; i < arguments.length; i++) {
var element = arguments[i];
if (!element) continue;
if (element.tagName=='FORM') {
this.addForm(element);
}
else {
var forms = element.getElementsByTagName('form');
for (var j = 0; j < forms.length; j++) {
this.addForm(forms[j]);
}
}
}
}
Class.removeForms = function() {
for (var i = 0; i < arguments.length; i++) {
var element = arguments[i];
if (!element) continue;
if (element.tagName=='FORM') {
for (var j = 0; j < arguments.length; j++) {
if (this.forms[j] == element) {
this.forms.splice(j--, 1);
element.onsubmit=null;
}
}
} else {
var forms = element.getElementsByTagName('form');
for (var j = 0; j < forms.length; j++) {
this.removeForms(forms[j]);
}
}
}
}
Class.CheckType = function() {};
var c = Class.CheckType.prototype;
c.checkbox = c.radio = function(ele) {
return ele.checked != ele.defaultChecked;
}
c.password = c.textarea = c.text = function(ele) {
return ele.value != ele.defaultValue;
}
// hidden: cannot tell on Mozilla without special treatment
c.hidden = function(ele) {
var orig = ele.getAttribute("originalValue");
return orig && (ele.value != orig);
}
c['select-one'] = function(ele) {
for (var i=0 ; i < ele.length; i++) {
var opt = ele.options[i];
if ( opt.selected != opt.defaultSelected) {
if (i===0 && opt.selected) continue; /* maybe no default */
return true;
}
}
return false;
}
c['select-multiple'] = function(ele) {
for (var i=0 ; i < ele.length; i++) {
var opt = ele.options[i];
if ( opt.selected != opt.defaultSelected) {
return true;
}
}
return false;
}
Class.chk_form = function(form) {
var elements = form.elements;
for (var i=0; i < elements.length; i++ ) {
var element = elements[i];
if (this.isElementChanged(element)) {
return true;
}
}
return false;
}
Class.isElementChanged = function(ele) {
var method = ele.id && this.chkId[ele.id];
if (!method && ele.type && ele.name)
method = this.chkType[ele.type];
if (!method && ele.tagName)
method = this['chk_'+ele.tagName.toLowerCase()];
return method? method.apply(this, [ele]) : false;
};
window.onbeforeunload = new BeforeUnloadHandler().execute;
})();