mirror of
https://github.com/silverstripe/silverstripe-cms
synced 2024-10-22 08:05:56 +02:00
BUGFIX Updated jquery.changetracker behaviour in LeftAndMain javascript to properly respond to window.onbeforeunload events
git-svn-id: svn://svn.silverstripe.com/silverstripe/open/modules/cms/trunk@92688 467b73ca-7a2a-4603-9d3b-597d59a354a9
This commit is contained in:
parent
55ed72d2aa
commit
f267dac02c
@ -22,42 +22,47 @@
|
|||||||
ChangeTrackerOptions: {},
|
ChangeTrackerOptions: {},
|
||||||
|
|
||||||
onmatch: function() {
|
onmatch: function() {
|
||||||
|
var self = this;
|
||||||
|
|
||||||
this._setupChangeTracker();
|
this._setupChangeTracker();
|
||||||
|
|
||||||
|
// Can't bind this through jQuery
|
||||||
|
window.onbeforeunload = function(e) {return self._checkChangeTracker(false);};
|
||||||
|
|
||||||
$._super();
|
$._super();
|
||||||
},
|
},
|
||||||
|
|
||||||
_setupChangeTracker: function() {
|
_setupChangeTracker: function() {
|
||||||
var self = this;
|
|
||||||
|
|
||||||
// Don't bind any events here, as we dont replace the
|
// Don't bind any events here, as we dont replace the
|
||||||
// full <form> tag by any ajax updates they won't automatically reapply
|
// full <form> tag by any ajax updates they won't automatically reapply
|
||||||
this.changetracker(this.ChangeTrackerOptions());
|
this.changetracker(this.ChangeTrackerOptions());
|
||||||
|
},
|
||||||
var autoSaveOnUnload = function(e) {
|
|
||||||
// @todo TinyMCE coupling
|
/**
|
||||||
if(typeof tinyMCE != 'undefined') tinyMCE.triggerSave();
|
* Checks the jquery.changetracker plugin status for this form.
|
||||||
if(self.is('.changed') && confirm(ss.i18n._t('LeftAndMain.CONFIRMUNSAVED'))) {
|
* Usually bound to window.onbeforeunload.
|
||||||
// unloads can't be prevented, but we can delay it with a synchronous ajax request
|
*
|
||||||
self.ajaxSubmit(
|
* @param {boolean} doConfirm
|
||||||
self.find(':submit[name=action_save]'),
|
* @return Either a string with a confirmation message, or the result of a confirm() dialog,
|
||||||
null,
|
* based on the doConfirm parameter.
|
||||||
{async: false}
|
*/
|
||||||
);
|
_checkChangeTracker: function(doConfirm) {
|
||||||
}
|
var self = this;
|
||||||
};
|
|
||||||
|
// @todo TinyMCE coupling
|
||||||
// use custom IE 'onbeforeunload' event, as it destroys the DOM
|
if(typeof tinyMCE != 'undefined') tinyMCE.triggerSave();
|
||||||
// before going into 'unload'
|
if(self.is('.changed')) {
|
||||||
if(typeof window.onbeforeunload != 'undefined') {
|
var msg = ss.i18n._t('LeftAndMain.CONFIRMUNSAVED');
|
||||||
window.onbeforeunload = autoSaveOnUnload;
|
// returned string will trigger a confirm() dialog,
|
||||||
} else {
|
// but only if the method is triggered by an event
|
||||||
$(window).unload(autoSaveOnUnload);
|
return (doConfirm) ? confirm(msg) : msg;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Suppress submission unless it is handled through ajaxSubmit()
|
* Suppress submission unless it is handled through ajaxSubmit().
|
||||||
|
*
|
||||||
|
* @param {Event} e
|
||||||
*/
|
*/
|
||||||
onsubmit: function(e) {
|
onsubmit: function(e) {
|
||||||
return false;
|
return false;
|
||||||
@ -66,15 +71,17 @@
|
|||||||
/**
|
/**
|
||||||
* @param {DOMElement} button The pressed button (optional)
|
* @param {DOMElement} button The pressed button (optional)
|
||||||
* @param {Function} callback Called in complete() handler of jQuery.ajax()
|
* @param {Function} callback Called in complete() handler of jQuery.ajax()
|
||||||
|
* @param {Object} ajaxOptions Object literal to merge into $.ajax() call
|
||||||
|
* @param {boolean} loadResponse Render response through _loadResponse() (Default: true)
|
||||||
*/
|
*/
|
||||||
ajaxSubmit: function(button, callback, ajaxOptions) {
|
ajaxSubmit: function(button, callback, ajaxOptions, loadResponse) {
|
||||||
|
var self = this;
|
||||||
|
|
||||||
// look for save button
|
// look for save button
|
||||||
if(!button) button = this.find('.Actions :submit[name=action_save]');
|
if(!button) button = this.find('.Actions :submit[name=action_save]');
|
||||||
// default to first button if none given - simulates browser behaviour
|
// default to first button if none given - simulates browser behaviour
|
||||||
if(!button) button = this.find('.Actions :submit:first');
|
if(!button) button = this.find('.Actions :submit:first');
|
||||||
|
|
||||||
var self = this;
|
|
||||||
|
|
||||||
this.trigger('ajaxsubmit', {button: button});
|
this.trigger('ajaxsubmit', {button: button});
|
||||||
|
|
||||||
// set button to "submitting" state
|
// set button to "submitting" state
|
||||||
@ -97,17 +104,22 @@
|
|||||||
var formData = this.serializeArray();
|
var formData = this.serializeArray();
|
||||||
// add button action
|
// add button action
|
||||||
formData.push({name: $(button).attr('name'), value:'1'});
|
formData.push({name: $(button).attr('name'), value:'1'});
|
||||||
$.ajax($.extend({
|
jQuery.ajax(jQuery.extend({
|
||||||
url: this.attr('action'),
|
url: this.attr('action'),
|
||||||
data: formData,
|
data: formData,
|
||||||
type: 'POST',
|
type: 'POST',
|
||||||
complete: function(xmlhttp, status) {
|
complete: function(xmlhttp, status) {
|
||||||
$(button).removeClass('loading');
|
$(button).removeClass('loading');
|
||||||
|
|
||||||
|
// TODO This should be using the plugin API
|
||||||
|
self.removeClass('changed');
|
||||||
|
|
||||||
if(callback) callback(xmlhttp, status);
|
if(callback) callback(xmlhttp, status);
|
||||||
|
|
||||||
// pass along original form data to enable old/new comparisons
|
// pass along original form data to enable old/new comparisons
|
||||||
self._loadResponse(xmlhttp.responseText, status, xmlhttp, formData);
|
if(loadResponse !== false) {
|
||||||
|
self._loadResponse(xmlhttp.responseText, status, xmlhttp, formData);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
dataType: 'html'
|
dataType: 'html'
|
||||||
}, ajaxOptions));
|
}, ajaxOptions));
|
||||||
@ -131,19 +143,28 @@
|
|||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param String url
|
* @param {String} url
|
||||||
* @param Function callback (Optional)
|
* @param {Function} callback (Optional)
|
||||||
|
* @param {ajaxOptions} Object literal merged into the jQuery.ajax() call (Optional)
|
||||||
*/
|
*/
|
||||||
load: function(url, callback) {
|
load: function(url, callback, ajaxOptions) {
|
||||||
var self = this;
|
var self = this;
|
||||||
$.ajax({
|
|
||||||
|
// Alert when unsaved changes are present
|
||||||
|
if(!this._checkChangeTracker(true)) return false;
|
||||||
|
|
||||||
|
return jQuery.ajax(jQuery.extend({
|
||||||
url: url,
|
url: url,
|
||||||
complete: function(xmlhttp, status) {
|
complete: function(xmlhttp, status) {
|
||||||
self._loadResponse(xmlhttp.responseText, status, xmlhttp);
|
// TODO This should be using the plugin API
|
||||||
|
self.removeClass('changed');
|
||||||
|
|
||||||
if(callback) callback.apply(self, arguments);
|
if(callback) callback.apply(self, arguments);
|
||||||
|
|
||||||
|
self._loadResponse(xmlhttp.responseText, status, xmlhttp);
|
||||||
},
|
},
|
||||||
dataType: 'html'
|
dataType: 'html'
|
||||||
});
|
}, ajaxOptions));
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -206,6 +227,8 @@
|
|||||||
} else {
|
} else {
|
||||||
this.removeForm();
|
this.removeForm();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this._setupChangeTracker();
|
||||||
|
|
||||||
// Optionally get the form attributes from embedded fields, see Form->formHtmlContent()
|
// Optionally get the form attributes from embedded fields, see Form->formHtmlContent()
|
||||||
for(var overrideAttr in {'action':true,'method':true,'enctype':true,'name':true}) {
|
for(var overrideAttr in {'action':true,'method':true,'enctype':true,'name':true}) {
|
||||||
@ -245,7 +268,8 @@
|
|||||||
$('#Form_EditForm .Actions :submit').concrete('ss', function($){
|
$('#Form_EditForm .Actions :submit').concrete('ss', function($){
|
||||||
return/** @lends ss.Form_EditForm.Actions.submit */{
|
return/** @lends ss.Form_EditForm.Actions.submit */{
|
||||||
onmatch: function() {
|
onmatch: function() {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
// TODO Fix once concrete library is updated
|
// TODO Fix once concrete library is updated
|
||||||
this.bind('click', function(e) {return self.clickFake(e);});
|
this.bind('click', function(e) {return self.clickFake(e);});
|
||||||
},
|
},
|
||||||
|
@ -202,7 +202,7 @@ TreeNodeAPI.prototype = {
|
|||||||
if(this.getElementsByTagName('a')[0].href) {
|
if(this.getElementsByTagName('a')[0].href) {
|
||||||
_AJAX_LOADING = true;
|
_AJAX_LOADING = true;
|
||||||
if($('sitetree').notify('SelectionChanged', this)) {
|
if($('sitetree').notify('SelectionChanged', this)) {
|
||||||
jQuery('#Form_EditForm').concrete('ss').ajaxSubmit(null, this.getPageFromServer.bind(this));
|
this.getPageFromServer();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -210,9 +210,7 @@ TreeNodeAPI.prototype = {
|
|||||||
getPageFromServer : function() {
|
getPageFromServer : function() {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
this.addNodeClass('loading');
|
var xmlhttp = jQuery('#Form_EditForm').concrete('ss').load(
|
||||||
|
|
||||||
jQuery('#Form_EditForm').concrete('ss').load(
|
|
||||||
jQuery(this).find('a').attr('href'),
|
jQuery(this).find('a').attr('href'),
|
||||||
function(response) {
|
function(response) {
|
||||||
self.removeNodeClass('loading');
|
self.removeNodeClass('loading');
|
||||||
@ -223,6 +221,9 @@ TreeNodeAPI.prototype = {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if(xmlhttp) this.addNodeClass('loading');
|
||||||
|
|
||||||
_AJAX_LOADING = false;
|
_AJAX_LOADING = false;
|
||||||
},
|
},
|
||||||
ajaxExpansion : function() {
|
ajaxExpansion : function() {
|
||||||
|
@ -24,6 +24,6 @@ if(typeof(ss) == 'undefined' || typeof(ss.i18n) == 'undefined') {
|
|||||||
'ModelAdmin.DELETED': "Deleted",
|
'ModelAdmin.DELETED': "Deleted",
|
||||||
'ModelAdmin.VALIDATIONERROR': "Validation Error",
|
'ModelAdmin.VALIDATIONERROR': "Validation Error",
|
||||||
'LeftAndMain.PAGEWASDELETED': "This page was deleted. To edit a page, select it from the left.",
|
'LeftAndMain.PAGEWASDELETED': "This page was deleted. To edit a page, select it from the left.",
|
||||||
'LeftAndMain.CONFIRMUNSAVED': "You have unsaved changes. Are you sure you want to navigate away from this page?\n\nPress OK to save your changes automatically."
|
'LeftAndMain.CONFIRMUNSAVED': "Are you sure you want to navigate away from this page?\n\nWARNING: Your changes have not been saved.\n\nPress OK to continue, or Cancel to stay on the current page."
|
||||||
});
|
});
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user