diff --git a/README.md b/README.md index 9ffc25a..cdff4a8 100644 --- a/README.md +++ b/README.md @@ -136,6 +136,14 @@ Default: `false` If `true`, this will launch the Bootstrap warning dialog / redirect (or callback functions) in a set amounts of time regardless of user activity. This in turn makes the plugin act much like the [jquery-sessionTimeout-bootstrap by maxfierke](https://github.com/maxfierke/jquery-sessionTimeout-bootstrap) plugin. +**clearWarningOnUserActivity** + +Type: `Boolean` + +Default: `true` + +If `true` and `ignoreUserActivity === true`, when user activity is detected on the page during the warning period, the warning dialog will be dismissed. Otherwise, the warning dialog will remain on the page until the user either selects an option or is logged out due to inactivity. + **countdownSmart** Type: `Boolean` @@ -188,6 +196,14 @@ Default: `false` Custom callback you can use instead of redirecting the user to `redirUrl`. Takes options object as the only argument. +**useLocalStorageSynchronization** + +Type: `Boolean` + +Default: false + +Enables cross-tab synchronization to prevent inactive tabs from logging users out during periods of activity in other tabs. The `localStorageSynchronizationKey` option can be customized to change the storage key used (default: `sessionkeepalive__lastkeepalive`). + ## Examples You can play around with the examples in the `/examples` directory. @@ -204,7 +220,8 @@ $.sessionTimeout({ logoutUrl: 'login.html', redirUrl: 'locked.html', warnAfter: 60000, - redirAfter: 120000 + redirAfter: 120000, + useLocalStorageSynchronization: true // ensure multiple tabs do not conflict with one another }); ``` diff --git a/dist/bootstrap-session-timeout.js b/dist/bootstrap-session-timeout.js index 1d65189..c2db4ab 100644 --- a/dist/bootstrap-session-timeout.js +++ b/dist/bootstrap-session-timeout.js @@ -25,12 +25,15 @@ keepAliveInterval: 5000, keepAlive: true, ignoreUserActivity: false, + clearWarningOnUserActivity: true, onStart: false, onWarn: false, onRedir: false, countdownMessage: false, countdownBar: false, - countdownSmart: false + countdownSmart: false, + useLocalStorageSynchronization: false, + localStorageSynchronizationKey: "sessionkeepalive__lastkeepalive" }; var opt = defaults, @@ -109,18 +112,23 @@ // If they moved the mouse not only reset the counter // but remove the modal too! - if ($('#session-timeout-dialog').length > 0 && - $('#session-timeout-dialog').data('bs.modal') && - $('#session-timeout-dialog').data('bs.modal').isShown) { - // http://stackoverflow.com/questions/11519660/twitter-bootstrap-modal-backdrop-doesnt-disappear - $('#session-timeout-dialog').modal('hide'); - $('body').removeClass('modal-open'); - $('div.modal-backdrop').remove(); - + if (opt.clearWarningOnUserActivity && modalIsDisplayed()) { + removeWarningModal(); } }); } + function modalIsDisplayed() { + return $('#session-timeout-dialog').is(':visible'); + } + + function removeWarningModal() { + // http://stackoverflow.com/questions/11519660/twitter-bootstrap-modal-backdrop-doesnt-disappear + $('#session-timeout-dialog').modal('hide'); + $('body').removeClass('modal-open'); + $('div.modal-backdrop').remove(); + } + // Keeps the server side connection live, by pingin url set in keepAliveUrl option. // KeepAlivePinged is a helper var to ensure the functionality of the keepAliveInterval option var keepAlivePinged = false; @@ -134,6 +142,11 @@ data: opt.ajaxData }); keepAlivePinged = true; + + if (opt.useLocalStorageSynchronization) { + refreshLastKeepAliveSynchronizationValue(); + } + setTimeout(function() { keepAlivePinged = false; }, opt.keepAliveInterval); @@ -172,7 +185,7 @@ function startDialogTimer() { // Clear session timer clearTimeout(timer); - if (!$('#session-timeout-dialog').hasClass('in') && (opt.countdownMessage || opt.countdownBar)) { + if (!modalIsDisplayed() && (opt.countdownMessage || opt.countdownBar)) { // If warning dialog is not already open and either opt.countdownMessage // or opt.countdownBar are set start countdown startCountdownTimer('dialog', true); @@ -188,6 +201,21 @@ }, (opt.redirAfter - opt.warnAfter)); } + function refreshLastKeepAliveSynchronizationValue() { + localStorage.setItem(opt.localStorageSynchronizationKey, new Date()); + } + + function setupLocalStorageEventObservation() { + window.addEventListener('storage', function (e) { + if (e.key === opt.localStorageSynchronizationKey) { + startSessionTimer(); + if (modalIsDisplayed()) { + removeWarningModal(); + } + } + }, ); + } + function startCountdownTimer(type, reset) { // Clear countdown timer clearTimeout(countdown.timer); @@ -238,5 +266,9 @@ // Start session timer startSessionTimer(); + if (opt.useLocalStorageSynchronization) { + setupLocalStorageEventObservation(); + } + }; })(jQuery);