Merge pull request #23487 from owncloud/core-globalajaxerrorwhengoingaway
Detect user navigating away, don't interpret as ajax error
This commit is contained in:
commit
8d11c3b87b
|
@ -740,13 +740,23 @@ var OC={
|
|||
* if an error/auth error status was returned.
|
||||
*/
|
||||
_processAjaxError: function(xhr) {
|
||||
var self = this;
|
||||
// purposefully aborted request ?
|
||||
if (xhr.status === 0 && (xhr.statusText === 'abort' || xhr.statusText === 'timeout')) {
|
||||
// this._userIsNavigatingAway needed to distinguish ajax calls cancelled by navigating away
|
||||
// from calls cancelled by failed cross-domain ajax due to SSO redirect
|
||||
if (xhr.status === 0 && (xhr.statusText === 'abort' || xhr.statusText === 'timeout' || self._reloadCalled)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (_.contains([0, 302, 307, 401], xhr.status)) {
|
||||
OC.reload();
|
||||
if (_.contains([0, 302, 303, 307, 401], xhr.status)) {
|
||||
// sometimes "beforeunload" happens later, so need to defer the reload a bit
|
||||
setTimeout(function() {
|
||||
if (!self._userIsNavigatingAway && !self._reloadCalled) {
|
||||
OC.reload();
|
||||
// only call reload once
|
||||
self._reloadCalled = true;
|
||||
}
|
||||
}, 100);
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -1438,6 +1448,29 @@ function initCore() {
|
|||
$('html').addClass('edge');
|
||||
}
|
||||
|
||||
$(window).on('unload.main', function() {
|
||||
OC._unloadCalled = true;
|
||||
});
|
||||
$(window).on('beforeunload.main', function() {
|
||||
// super-trick thanks to http://stackoverflow.com/a/4651049
|
||||
// in case another handler displays a confirmation dialog (ex: navigating away
|
||||
// during an upload), there are two possible outcomes: user clicked "ok" or
|
||||
// "cancel"
|
||||
|
||||
// first timeout handler is called after unload dialog is closed
|
||||
setTimeout(function() {
|
||||
OC._userIsNavigatingAway = true;
|
||||
|
||||
// second timeout event is only called if user cancelled (Chrome),
|
||||
// but in other browsers it might still be triggered, so need to
|
||||
// set a higher delay...
|
||||
setTimeout(function() {
|
||||
if (!OC._unloadCalled) {
|
||||
OC._userIsNavigatingAway = false;
|
||||
}
|
||||
}, 10000);
|
||||
},1);
|
||||
});
|
||||
$(document).on('ajaxError.main', function( event, request, settings ) {
|
||||
if (settings && settings.allowAuthErrors) {
|
||||
return;
|
||||
|
|
|
@ -20,6 +20,15 @@
|
|||
*/
|
||||
|
||||
describe('Core base tests', function() {
|
||||
afterEach(function() {
|
||||
// many tests call window.initCore so need to unregister global events
|
||||
// ideally in the future we'll need a window.unloadCore() function
|
||||
$(document).off('ajaxError.main');
|
||||
$(document).off('unload.main');
|
||||
$(document).off('beforeunload.main');
|
||||
OC._userIsNavigatingAway = false;
|
||||
OC._reloadCalled = false;
|
||||
});
|
||||
describe('Base values', function() {
|
||||
it('Sets webroots', function() {
|
||||
expect(OC.webroot).toBeDefined();
|
||||
|
@ -925,9 +934,10 @@ describe('Core base tests', function() {
|
|||
});
|
||||
});
|
||||
describe('global ajax errors', function() {
|
||||
var reloadStub, ajaxErrorStub;
|
||||
var reloadStub, ajaxErrorStub, clock;
|
||||
|
||||
beforeEach(function() {
|
||||
clock = sinon.useFakeTimers();
|
||||
reloadStub = sinon.stub(OC, 'reload');
|
||||
// unstub the error processing method
|
||||
ajaxErrorStub = OC._processAjaxError;
|
||||
|
@ -936,15 +946,17 @@ describe('Core base tests', function() {
|
|||
});
|
||||
afterEach(function() {
|
||||
reloadStub.restore();
|
||||
$(document).off('ajaxError');
|
||||
clock.restore();
|
||||
});
|
||||
|
||||
it('reloads current page in case of auth error', function () {
|
||||
it('reloads current page in case of auth error', function() {
|
||||
var dataProvider = [
|
||||
[200, false],
|
||||
[400, false],
|
||||
[0, true],
|
||||
[401, true],
|
||||
[302, true],
|
||||
[303, true],
|
||||
[307, true]
|
||||
];
|
||||
|
||||
|
@ -953,9 +965,13 @@ describe('Core base tests', function() {
|
|||
var expectedCall = dataProvider[i][1];
|
||||
|
||||
reloadStub.reset();
|
||||
OC._reloadCalled = false;
|
||||
|
||||
$(document).trigger(new $.Event('ajaxError'), xhr);
|
||||
|
||||
// trigger timers
|
||||
clock.tick(1000);
|
||||
|
||||
if (expectedCall) {
|
||||
expect(reloadStub.calledOnce).toEqual(true);
|
||||
} else {
|
||||
|
@ -963,6 +979,27 @@ describe('Core base tests', function() {
|
|||
}
|
||||
}
|
||||
});
|
||||
})
|
||||
it('reload only called once in case of auth error', function() {
|
||||
var xhr = { status: 401 };
|
||||
|
||||
$(document).trigger(new $.Event('ajaxError'), xhr);
|
||||
$(document).trigger(new $.Event('ajaxError'), xhr);
|
||||
|
||||
// trigger timers
|
||||
clock.tick(1000);
|
||||
|
||||
expect(reloadStub.calledOnce).toEqual(true);
|
||||
});
|
||||
it('does not reload the page if the user was navigating away', function() {
|
||||
var xhr = { status: 0 };
|
||||
OC._userIsNavigatingAway = true;
|
||||
clock.tick(100);
|
||||
|
||||
$(document).trigger(new $.Event('ajaxError'), xhr);
|
||||
|
||||
clock.tick(1000);
|
||||
expect(reloadStub.notCalled).toEqual(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
|
Loading…
Reference in New Issue