mirror of
https://github.com/silverstripe/silverstripe-framework
synced 2024-10-22 14:05:37 +02:00
Merge pull request #4458 from tractorcow/pulls/3.2/fix-change-detection-back
BUG Fix change detection on browser back button
This commit is contained in:
commit
8425a2b5a3
@ -129,13 +129,23 @@
|
|||||||
* Doesn't cancel any unload or form removal events, you'll need to implement this based on the return
|
* Doesn't cancel any unload or form removal events, you'll need to implement this based on the return
|
||||||
* value of this message.
|
* value of this message.
|
||||||
*
|
*
|
||||||
|
* If changes are confirmed for discard, the 'changed' flag is reset.
|
||||||
|
*
|
||||||
* Returns:
|
* Returns:
|
||||||
* (Boolean) FALSE if the user wants to abort with changes present, TRUE if no changes are detected
|
* (Boolean) FALSE if the user wants to abort with changes present, TRUE if no changes are detected
|
||||||
* or the user wants to discard them.
|
* or the user wants to discard them.
|
||||||
*/
|
*/
|
||||||
confirmUnsavedChanges: function() {
|
confirmUnsavedChanges: function() {
|
||||||
this.trigger('beforesubmitform');
|
this.trigger('beforesubmitform');
|
||||||
return (this.is('.changed')) ? confirm(ss.i18n._t('LeftAndMain.CONFIRMUNSAVED')) : true;
|
if(!this.is('.changed')) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
var confirmed = confirm(ss.i18n._t('LeftAndMain.CONFIRMUNSAVED'));
|
||||||
|
if(confirmed) {
|
||||||
|
// confirm discard changes
|
||||||
|
this.removeClass('changed');
|
||||||
|
}
|
||||||
|
return confirmed;
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -253,12 +253,13 @@ jQuery.noConflict();
|
|||||||
$('body').removeClass('loading');
|
$('body').removeClass('loading');
|
||||||
$(window).unbind('resize', positionLoadingSpinner);
|
$(window).unbind('resize', positionLoadingSpinner);
|
||||||
this.restoreTabState();
|
this.restoreTabState();
|
||||||
|
|
||||||
this._super();
|
this._super();
|
||||||
},
|
},
|
||||||
|
|
||||||
fromWindow: {
|
fromWindow: {
|
||||||
onstatechange: function(){ this.handleStateChange(); }
|
onstatechange: function(e){
|
||||||
|
this.handleStateChange(e);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
'onwindowresize': function() {
|
'onwindowresize': function() {
|
||||||
@ -359,6 +360,34 @@ jQuery.noConflict();
|
|||||||
this.find('.cms-content').redraw();
|
this.find('.cms-content').redraw();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Confirm whether the current user can navigate away from this page
|
||||||
|
*
|
||||||
|
* @param {array} selectors Optional list of selectors
|
||||||
|
* @returns {boolean} True if the navigation can proceed
|
||||||
|
*/
|
||||||
|
checkCanNavigate: function(selectors) {
|
||||||
|
// Check change tracking (can't use events as we need a way to cancel the current state change)
|
||||||
|
var contentEls = this._findFragments(selectors || ['Content']),
|
||||||
|
trackedEls = contentEls
|
||||||
|
.find(':data(changetracker)')
|
||||||
|
.add(contentEls.filter(':data(changetracker)')),
|
||||||
|
safe = true;
|
||||||
|
|
||||||
|
if(!trackedEls.length) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
trackedEls.each(function() {
|
||||||
|
// See LeftAndMain.EditForm.js
|
||||||
|
if(!$(this).confirmUnsavedChanges()) {
|
||||||
|
safe = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return safe;
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Proxy around History.pushState() which handles non-HTML5 fallbacks,
|
* Proxy around History.pushState() which handles non-HTML5 fallbacks,
|
||||||
* as well as global change tracking. Change tracking needs to be synchronous rather than event/callback
|
* as well as global change tracking. Change tracking needs to be synchronous rather than event/callback
|
||||||
@ -377,18 +406,9 @@ jQuery.noConflict();
|
|||||||
if(!title) title = "";
|
if(!title) title = "";
|
||||||
if (!forceReferer) forceReferer = History.getState().url;
|
if (!forceReferer) forceReferer = History.getState().url;
|
||||||
|
|
||||||
// Check change tracking (can't use events as we need a way to cancel the current state change)
|
// Check for unsaved changes
|
||||||
var contentEls = this._findFragments(data.pjax ? data.pjax.split(',') : ['Content']);
|
if(!this.checkCanNavigate(data.pjax ? data.pjax.split(',') : ['Content'])) {
|
||||||
var trackedEls = contentEls.find(':data(changetracker)').add(contentEls.filter(':data(changetracker)'));
|
return;
|
||||||
|
|
||||||
if(trackedEls.length) {
|
|
||||||
var abort = false;
|
|
||||||
|
|
||||||
trackedEls.each(function() {
|
|
||||||
if(!$(this).confirmUnsavedChanges()) abort = true;
|
|
||||||
});
|
|
||||||
|
|
||||||
if(abort) return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Save tab selections so we can restore them later
|
// Save tab selections so we can restore them later
|
||||||
@ -494,6 +514,16 @@ jQuery.noConflict();
|
|||||||
return false;
|
return false;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Last html5 history state
|
||||||
|
*/
|
||||||
|
LastState: null,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Flag to pause handleStateChange
|
||||||
|
*/
|
||||||
|
PauseState: false,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handles ajax loading of new panels through the window.History object.
|
* Handles ajax loading of new panels through the window.History object.
|
||||||
* To trigger loading, pass a new URL to window.History.pushState().
|
* To trigger loading, pass a new URL to window.History.pushState().
|
||||||
@ -517,6 +547,10 @@ jQuery.noConflict();
|
|||||||
* if the URL is loaded without ajax.
|
* if the URL is loaded without ajax.
|
||||||
*/
|
*/
|
||||||
handleStateChange: function() {
|
handleStateChange: function() {
|
||||||
|
if(this.getPauseState()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Don't allow parallel loading to avoid edge cases
|
// Don't allow parallel loading to avoid edge cases
|
||||||
if(this.getStateChangeXHR()) this.getStateChangeXHR().abort();
|
if(this.getStateChangeXHR()) this.getStateChangeXHR().abort();
|
||||||
|
|
||||||
@ -534,6 +568,30 @@ jQuery.noConflict();
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(!this.checkCanNavigate()) {
|
||||||
|
// If history is emulated (ie8 or below) disable attempting to restore
|
||||||
|
if(h.emulated.pushState) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var lastState = this.getLastState();
|
||||||
|
|
||||||
|
// Suppress panel loading while resetting state
|
||||||
|
this.setPauseState(true);
|
||||||
|
|
||||||
|
// Restore best last state
|
||||||
|
if(lastState) {
|
||||||
|
h.pushState(lastState.id, lastState.title, lastState.url);
|
||||||
|
} else {
|
||||||
|
h.back();
|
||||||
|
}
|
||||||
|
this.setPauseState(false);
|
||||||
|
|
||||||
|
// Abort loading of this panel
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.setLastState(state);
|
||||||
|
|
||||||
// If any of the requested Pjax fragments don't exist in the current view,
|
// If any of the requested Pjax fragments don't exist in the current view,
|
||||||
// fetch the "Content" view instead, which is the "outermost" fragment
|
// fetch the "Content" view instead, which is the "outermost" fragment
|
||||||
// that can be reloaded without reloading the whole window.
|
// that can be reloaded without reloading the whole window.
|
||||||
|
Loading…
Reference in New Issue
Block a user