You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@atlas.apache.org by ni...@apache.org on 2021/08/31 15:25:46 UTC
[atlas] 02/02: ATLAS-4378: UI - Implement session timeout on Atlas
UI.
This is an automated email from the ASF dual-hosted git repository.
nixon pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/atlas.git
commit 5deac6277cb5e0676e811f682da2a7692a9f628e
Author: prasad pawar <pr...@freestoneinfotech.com>
AuthorDate: Thu Aug 26 18:59:12 2021 +0530
ATLAS-4378: UI - Implement session timeout on Atlas UI.
---
dashboardv2/public/css/scss/override.scss | 6 +
.../js/external_lib/idealTimeout/store.min.js | 2 +
dashboardv2/public/js/main.js | 27 +-
dashboardv2/public/js/utils/Globals.js | 1 +
dashboardv2/public/js/utils/Utils.js | 271 ++++++++++++++++++++-
dashboardv3/public/css/scss/override.scss | 6 +
.../js/external_lib/idealTimeout/store.min.js | 2 +
dashboardv3/public/js/main.js | 27 +-
dashboardv3/public/js/utils/Globals.js | 1 +
dashboardv3/public/js/utils/Utils.js | 267 +++++++++++++++++++-
10 files changed, 604 insertions(+), 6 deletions(-)
diff --git a/dashboardv2/public/css/scss/override.scss b/dashboardv2/public/css/scss/override.scss
index c24b0c6..549ae3b 100644
--- a/dashboardv2/public/css/scss/override.scss
+++ b/dashboardv2/public/css/scss/override.scss
@@ -575,4 +575,10 @@ div.columnmanager-dropdown-container {
ul {
list-style: disc;
}
+}
+
+.ideal-timeout {
+ .modal-content {
+ border-radius: 0px !important;
+ }
}
\ No newline at end of file
diff --git a/dashboardv2/public/js/external_lib/idealTimeout/store.min.js b/dashboardv2/public/js/external_lib/idealTimeout/store.min.js
new file mode 100644
index 0000000..7334a7e
--- /dev/null
+++ b/dashboardv2/public/js/external_lib/idealTimeout/store.min.js
@@ -0,0 +1,2 @@
+/* Copyright (c) 2010-2013 Marcus Westin */
+"use strict";(function(e,t){typeof define=="function"&&define.amd?define([],t):typeof exports=="object"?module.exports=t():e.store=t()})(this,function(){function o(){try{return r in t&&t[r]}catch(e){return!1}}var e={},t=window,n=t.document,r="localStorage",i="script",s;e.disabled=!1,e.version="1.3.17",e.set=function(e,t){},e.get=function(e,t){},e.has=function(t){return e.get(t)!==undefined},e.remove=function(e){},e.clear=function(){},e.transact=function(t,n,r){r==null&&(r=n,n=null),n==nu [...]
\ No newline at end of file
diff --git a/dashboardv2/public/js/main.js b/dashboardv2/public/js/main.js
index 7c8bbb4..f2ea1d8 100644
--- a/dashboardv2/public/js/main.js
+++ b/dashboardv2/public/js/main.js
@@ -178,7 +178,8 @@ require.config({
'jstree': 'libs/jstree/jstree.min',
'jquery-steps': 'libs/jquery-steps/jquery.steps.min',
'dropzone': 'libs/dropzone/js/dropzone-amd-module',
- 'lossless-json': 'libs/lossless-json/lossless-json'
+ 'lossless-json': 'libs/lossless-json/lossless-json',
+ 'store': 'external_lib/idealTimeout/store.min'
},
/**
@@ -199,11 +200,12 @@ require(['App',
'collection/VEntityList',
'collection/VTagList',
'utils/Enums',
+ 'utils/Utils',
'utils/Overrides',
'bootstrap',
'd3',
'select2'
-], function(App, Router, Helper, CommonViewFunction, Globals, UrlLinks, VEntityList, VTagList, Enums) {
+], function(App, Router, Helper, CommonViewFunction, Globals, UrlLinks, VEntityList, VTagList, Enums, Utils) {
var that = this;
this.asyncFetchCounter = 5 + (Enums.addOnEntities.length + 1);
// entity
@@ -286,6 +288,27 @@ require(['App',
if (response['atlas.tasks.enabled'] !== undefined) {
Globals.isTasksEnabled = response['atlas.tasks.enabled'];
}
+ if (response['atlas.session.timeout.secs']) { Globals.idealTimeoutSeconds = response['atlas.session.timeout.secs']; }
+ /* Atlas idealTimeout
+ redirectUrl: url to redirect after timeout
+ idealTimeLimit: timeout in seconds
+ activityEvents: ideal keyboard mouse events
+ dialogDisplayLimit: show popup before timeout in seconds
+ */
+ $(document).ready(function() {
+ $(document).idleTimeout({
+ redirectUrl: Utils.getBaseUrl(window.location.pathname) + '/index.html?action=timeout', // redirect to this url
+ idleTimeLimit: Globals.idealTimeoutSeconds, // 900 seconds
+ activityEvents: 'click keypress scroll wheel mousemove', // separate each event with a space
+ dialogDisplayLimit: 10, // Time to display the warning dialog before logout (and optional callback) in seconds
+ sessionKeepAliveTimer: false, // Set to false to disable pings.
+ onModalKeepAlive: function() {
+ CommonViewFunction.userDataFetch({
+ url: UrlLinks.sessionApiUrl()
+ })
+ }
+ });
+ });
}
--that.asyncFetchCounter;
startApp();
diff --git a/dashboardv2/public/js/utils/Globals.js b/dashboardv2/public/js/utils/Globals.js
index b0dc5cd..8fe8ebc 100644
--- a/dashboardv2/public/js/utils/Globals.js
+++ b/dashboardv2/public/js/utils/Globals.js
@@ -49,6 +49,7 @@ define(["require"], function(require) {
Globals.isDebugMetricsEnabled = false;
Globals.isTasksEnabled = false;
+ Globals.idealTimeoutSeconds = 900;
return Globals;
});
\ No newline at end of file
diff --git a/dashboardv2/public/js/utils/Utils.js b/dashboardv2/public/js/utils/Utils.js
index f426b6c..f2498d8 100644
--- a/dashboardv2/public/js/utils/Utils.js
+++ b/dashboardv2/public/js/utils/Utils.js
@@ -16,7 +16,7 @@
* limitations under the License.
*/
-define(['require', 'utils/Globals', 'pnotify', 'utils/Messages', 'utils/Enums', 'moment', 'moment-timezone', 'pnotify.buttons', 'pnotify.confirm'], function(require, Globals, pnotify, Messages, Enums, moment) {
+define(['require', 'utils/Globals', 'pnotify', 'utils/Messages', 'utils/Enums', 'moment', 'store', 'modules/Modal', 'moment-timezone', 'pnotify.buttons', 'pnotify.confirm'], function(require, Globals, pnotify, Messages, Enums, moment, store, Modal) {
'use strict';
var Utils = {};
@@ -952,5 +952,274 @@ define(['require', 'utils/Globals', 'pnotify', 'utils/Messages', 'utils/Enums',
}
return dateValue;
}
+ //------------------------------------------------idleTimeout-----------------------------
+ $.fn.idleTimeout = function(userRuntimeConfig) {
+
+ //##############################
+ //## Public Configuration Variables
+ //##############################
+ var defaultConfig = {
+ redirectUrl: Utils.getBaseUrl(window.location.pathname) + '/index.html?action=timeout', // redirect to this url on logout. Set to "redirectUrl: false" to disable redirect
+
+ // idle settings
+ idleTimeLimit: Globals.idealTimeoutSeconds, // 'No activity' time limit in seconds. 1200 = 20 Minutes
+ idleCheckHeartbeat: 2, // Frequency to check for idle timeouts in seconds
+
+ // optional custom callback to perform before logout
+ customCallback: false, // set to false for no customCallback
+ // customCallback: function () { // define optional custom js function
+ // perform custom action before logout
+ // },
+
+ // configure which activity events to detect
+ // http://www.quirksmode.org/dom/events/
+ // https://developer.mozilla.org/en-US/docs/Web/Reference/Events
+ activityEvents: 'click keypress scroll wheel mousewheel mousemove', // separate each event with a space
+
+ // warning dialog box configuration
+ enableDialog: true, // set to false for logout without warning dialog
+ dialogDisplayLimit: 10, // Time to display the warning dialog before logout (and optional callback) in seconds. 180 = 3 Minutes
+ dialogTitle: 'Your session is about to expire!', // also displays on browser title bar
+ dialogText: 'Your session is about to expire.',
+ dialogTimeRemaining: 'You will be logged out in ',
+ dialogStayLoggedInButton: 'Stay Logged In',
+ dialogLogOutNowButton: 'Logout',
+
+ // error message if https://github.com/marcuswestin/store.js not enabled
+ errorAlertMessage: 'Please disable "Private Mode", or upgrade to a modern browser. Or perhaps a dependent file missing. Please see: https://github.com/marcuswestin/store.js',
+
+ // server-side session keep-alive timer
+ sessionKeepAliveTimer: 600, // ping the server at this interval in seconds. 600 = 10 Minutes. Set to false to disable pings
+ sessionKeepAliveUrl: window.location.href // set URL to ping - does not apply if sessionKeepAliveTimer: false
+ },
+
+ //##############################
+ //## Private Variables
+ //##############################
+ currentConfig = $.extend(defaultConfig, userRuntimeConfig), // merge default and user runtime configuration
+ origTitle = document.title, // save original browser title
+ activityDetector,
+ startKeepSessionAlive, stopKeepSessionAlive, keepSession, keepAlivePing, // session keep alive
+ idleTimer, remainingTimer, checkIdleTimeout, checkIdleTimeoutLoop, startIdleTimer, stopIdleTimer, // idle timer
+ openWarningDialog, dialogTimer, checkDialogTimeout, startDialogTimer, stopDialogTimer, isDialogOpen, destroyWarningDialog, countdownDisplay, // warning dialog
+ logoutUser;
+
+ //##############################
+ //## Public Functions
+ //##############################
+ // trigger a manual user logout
+ // use this code snippet on your site's Logout button: $.fn.idleTimeout().logout();
+ this.logout = function() {
+ store.set('idleTimerLoggedOut', true);
+ };
+
+ //##############################
+ //## Private Functions
+ //##############################
+
+ //----------- KEEP SESSION ALIVE FUNCTIONS --------------//
+ startKeepSessionAlive = function() {
+
+ keepSession = function() {
+ $.get(currentConfig.sessionKeepAliveUrl);
+ startKeepSessionAlive();
+ };
+
+ keepAlivePing = setTimeout(keepSession, (currentConfig.sessionKeepAliveTimer * 1000));
+ };
+
+ stopKeepSessionAlive = function() {
+ clearTimeout(keepAlivePing);
+ };
+
+ //----------- ACTIVITY DETECTION FUNCTION --------------//
+ activityDetector = function() {
+
+ $('body').on(currentConfig.activityEvents, function() {
+
+ if (!currentConfig.enableDialog || (currentConfig.enableDialog && isDialogOpen() !== true)) {
+ startIdleTimer();
+ $('#activity').effect('shake'); // added for demonstration page
+ }
+ });
+ };
+
+ //----------- IDLE TIMER FUNCTIONS --------------//
+ checkIdleTimeout = function() {
+
+ var timeIdleTimeout = (store.get('idleTimerLastActivity') + (currentConfig.idleTimeLimit * 1000));
+
+ if ($.now() > timeIdleTimeout) {
+
+ if (!currentConfig.enableDialog) { // warning dialog is disabled
+ logoutUser(); // immediately log out user when user is idle for idleTimeLimit
+ } else if (currentConfig.enableDialog && isDialogOpen() !== true) {
+ openWarningDialog();
+ startDialogTimer(); // start timing the warning dialog
+ }
+ } else if (store.get('idleTimerLoggedOut') === true) { //a 'manual' user logout?
+ logoutUser();
+ } else {
+
+ if (currentConfig.enableDialog && isDialogOpen() === true) {
+ destroyWarningDialog();
+ stopDialogTimer();
+ }
+ }
+ };
+
+ startIdleTimer = function() {
+ stopIdleTimer();
+ store.set('idleTimerLastActivity', $.now());
+ checkIdleTimeoutLoop();
+ };
+
+ checkIdleTimeoutLoop = function() {
+ checkIdleTimeout();
+ idleTimer = setTimeout(checkIdleTimeoutLoop, (currentConfig.idleCheckHeartbeat * 1000));
+ };
+
+ stopIdleTimer = function() {
+ clearTimeout(idleTimer);
+ };
+
+ //----------- WARNING DIALOG FUNCTIONS --------------//
+ openWarningDialog = function() {
+
+
+ var dialogContent = "<div id='idletimer_warning_dialog'><p>" + currentConfig.dialogText + "</p><p style='display:inline'>" + currentConfig.dialogTimeRemaining + ": <div style='display:inline' id='countdownDisplay'></div> secs.</p></div>";
+
+ var that = this,
+ modalObj = {
+ title: currentConfig.dialogTitle,
+ htmlContent: dialogContent,
+ okText: "Stay Signed-in",
+ cancelText: 'Logout',
+ mainClass: 'modal-lg',
+ allowCancel: true,
+ okCloses: false,
+ escape: false,
+ cancellable: true,
+ width: "500px",
+ mainClass: "ideal-timeout"
+ };
+ var modal = new Modal(modalObj);
+ modal.open();
+ modal.on('ok', function() {
+ if (userRuntimeConfig && userRuntimeConfig.onModalKeepAlive) {
+ userRuntimeConfig.onModalKeepAlive(); //hit session API
+ }
+ destroyWarningDialog();
+ modal.close();
+ stopDialogTimer();
+ startIdleTimer();
+ CommonViewFunction.userDataFetch({
+ url: UrlLinks.sessionApiUrl()
+ })
+
+ });
+ modal.on('closeModal', function() {
+ logoutUser();
+ });
+
+ countdownDisplay();
+
+ // document.title = currentConfig.dialogTitle;
+
+ if (currentConfig.sessionKeepAliveTimer) {
+ stopKeepSessionAlive();
+ }
+ };
+
+ checkDialogTimeout = function() {
+ var timeDialogTimeout = (store.get('idleTimerLastActivity') + (currentConfig.idleTimeLimit * 1000) + (currentConfig.dialogDisplayLimit * 1000));
+
+ if (($.now() > timeDialogTimeout) || (store.get('idleTimerLoggedOut') === true)) {
+ logoutUser();
+ }
+ };
+
+ startDialogTimer = function() {
+ dialogTimer = setInterval(checkDialogTimeout, (currentConfig.idleCheckHeartbeat * 1000));
+ };
+
+ stopDialogTimer = function() {
+ clearInterval(dialogTimer);
+ clearInterval(remainingTimer);
+ };
+
+ isDialogOpen = function() {
+ var dialogOpen = $("#idletimer_warning_dialog").is(":visible");
+
+ if (dialogOpen === true) {
+ return true;
+ }
+ return false;
+ };
+
+ destroyWarningDialog = function() {
+ if (currentConfig.sessionKeepAliveTimer) {
+ startKeepSessionAlive();
+ }
+ };
+
+ countdownDisplay = function() {
+ var dialogDisplaySeconds = currentConfig.dialogDisplayLimit,
+ mins, secs;
+
+ remainingTimer = setInterval(function() {
+ mins = Math.floor(dialogDisplaySeconds / 60); // minutes
+ if (mins < 10) { mins = '0' + mins; }
+ secs = dialogDisplaySeconds - (mins * 60); // seconds
+ if (secs < 10) { secs = '0' + secs; }
+ $('#countdownDisplay').html(mins + ':' + secs);
+ dialogDisplaySeconds -= 1;
+ }, 1000);
+ };
+
+ //----------- LOGOUT USER FUNCTION --------------//
+ logoutUser = function() {
+ store.set('idleTimerLoggedOut', true);
+
+ if (currentConfig.sessionKeepAliveTimer) {
+ stopKeepSessionAlive();
+ }
+
+ if (currentConfig.customCallback) {
+ currentConfig.customCallback();
+ }
+
+ if (currentConfig.redirectUrl) {
+ window.location.href = currentConfig.redirectUrl;
+ }
+ };
+
+ //###############################
+ // Build & Return the instance of the item as a plugin
+ // This is your construct.
+ //###############################
+ return this.each(function() {
+
+ if (store.enabled) {
+
+ store.set('idleTimerLastActivity', $.now());
+ store.set('idleTimerLoggedOut', false);
+
+ activityDetector();
+
+ if (currentConfig.sessionKeepAliveTimer) {
+ startKeepSessionAlive();
+ }
+
+ startIdleTimer();
+
+ } else {
+ alert(currentConfig.errorAlertMessage);
+ }
+
+ });
+ };
+
+ //------------------------------------------------
return Utils;
});
\ No newline at end of file
diff --git a/dashboardv3/public/css/scss/override.scss b/dashboardv3/public/css/scss/override.scss
index c1841eb..2c3ea78 100644
--- a/dashboardv3/public/css/scss/override.scss
+++ b/dashboardv3/public/css/scss/override.scss
@@ -577,4 +577,10 @@ div.columnmanager-dropdown-container {
ul {
list-style: disc;
}
+}
+
+.ideal-timeout {
+ .modal-content {
+ border-radius: 0px !important;
+ }
}
\ No newline at end of file
diff --git a/dashboardv3/public/js/external_lib/idealTimeout/store.min.js b/dashboardv3/public/js/external_lib/idealTimeout/store.min.js
new file mode 100644
index 0000000..7334a7e
--- /dev/null
+++ b/dashboardv3/public/js/external_lib/idealTimeout/store.min.js
@@ -0,0 +1,2 @@
+/* Copyright (c) 2010-2013 Marcus Westin */
+"use strict";(function(e,t){typeof define=="function"&&define.amd?define([],t):typeof exports=="object"?module.exports=t():e.store=t()})(this,function(){function o(){try{return r in t&&t[r]}catch(e){return!1}}var e={},t=window,n=t.document,r="localStorage",i="script",s;e.disabled=!1,e.version="1.3.17",e.set=function(e,t){},e.get=function(e,t){},e.has=function(t){return e.get(t)!==undefined},e.remove=function(e){},e.clear=function(){},e.transact=function(t,n,r){r==null&&(r=n,n=null),n==nu [...]
\ No newline at end of file
diff --git a/dashboardv3/public/js/main.js b/dashboardv3/public/js/main.js
index 374641e..97e177c 100644
--- a/dashboardv3/public/js/main.js
+++ b/dashboardv3/public/js/main.js
@@ -207,7 +207,8 @@ require.config({
'jstree': 'libs/jstree/jstree.min',
'jquery-steps': 'libs/jquery-steps/jquery.steps.min',
'dropzone': 'libs/dropzone/js/dropzone-amd-module',
- 'lossless-json': 'libs/lossless-json/lossless-json'
+ 'lossless-json': 'libs/lossless-json/lossless-json',
+ 'store': 'external_lib/idealTimeout/store.min'
},
/**
@@ -228,11 +229,12 @@ require(['App',
'collection/VEntityList',
'collection/VTagList',
'utils/Enums',
+ 'utils/Utils',
'utils/Overrides',
'bootstrap',
'd3',
'select2'
-], function(App, Router, Helper, CommonViewFunction, Globals, UrlLinks, VEntityList, VTagList, Enums) {
+], function(App, Router, Helper, CommonViewFunction, Globals, UrlLinks, VEntityList, VTagList, Enums, Utils) {
var that = this;
this.asyncFetchCounter = 5 + (Enums.addOnEntities.length + 1);
// entity
@@ -315,6 +317,27 @@ require(['App',
if (response['atlas.tasks.enabled'] !== undefined) {
Globals.isTasksEnabled = response['atlas.tasks.enabled'];
}
+ if (response['atlas.session.timeout.secs']) { Globals.idealTimeoutSeconds = response['atlas.session.timeout.secs']; }
+ /* Atlas idealTimeout
+ redirectUrl: url to redirect after timeout
+ idealTimeLimit: timeout in seconds
+ activityEvents: ideal keyboard mouse events
+ dialogDisplayLimit: show popup before timeout in seconds
+ */
+ $(document).ready(function() {
+ $(document).idleTimeout({
+ redirectUrl: Utils.getBaseUrl(window.location.pathname) + '/index.html?action=timeout', // redirect to this url
+ idleTimeLimit: Globals.idealTimeoutSeconds, // 900 seconds
+ activityEvents: 'click keypress scroll wheel mousemove', // separate each event with a space
+ dialogDisplayLimit: 10, // Time to display the warning dialog before logout (and optional callback) in seconds
+ sessionKeepAliveTimer: false, // Set to false to disable pings.
+ onModalKeepAlive: function() {
+ CommonViewFunction.userDataFetch({
+ url: UrlLinks.sessionApiUrl()
+ })
+ }
+ });
+ });
}
--that.asyncFetchCounter;
startApp();
diff --git a/dashboardv3/public/js/utils/Globals.js b/dashboardv3/public/js/utils/Globals.js
index b0dc5cd..8fe8ebc 100644
--- a/dashboardv3/public/js/utils/Globals.js
+++ b/dashboardv3/public/js/utils/Globals.js
@@ -49,6 +49,7 @@ define(["require"], function(require) {
Globals.isDebugMetricsEnabled = false;
Globals.isTasksEnabled = false;
+ Globals.idealTimeoutSeconds = 900;
return Globals;
});
\ No newline at end of file
diff --git a/dashboardv3/public/js/utils/Utils.js b/dashboardv3/public/js/utils/Utils.js
index 1a73b7c..c3122fc 100644
--- a/dashboardv3/public/js/utils/Utils.js
+++ b/dashboardv3/public/js/utils/Utils.js
@@ -16,7 +16,7 @@
* limitations under the License.
*/
-define(['require', 'utils/Globals', 'pnotify', 'utils/Messages', 'utils/Enums', 'moment', 'moment-timezone', 'pnotify.buttons', 'pnotify.confirm'], function(require, Globals, pnotify, Messages, Enums, moment) {
+define(['require', 'utils/Globals', 'pnotify', 'utils/Messages', 'utils/Enums', 'moment', 'store', 'modules/Modal', 'moment-timezone', 'pnotify.buttons', 'pnotify.confirm'], function(require, Globals, pnotify, Messages, Enums, moment, store, Modal) {
'use strict';
var Utils = {};
@@ -964,5 +964,270 @@ define(['require', 'utils/Globals', 'pnotify', 'utils/Messages', 'utils/Enums',
}
return dateValue;
}
+ //------------------------------------------------idleTimeout-----------------------------
+ $.fn.idleTimeout = function(userRuntimeConfig) {
+
+ //##############################
+ //## Public Configuration Variables
+ //##############################
+ var defaultConfig = {
+ redirectUrl: Utils.getBaseUrl(window.location.pathname) + '/index.html?action=timeout', // redirect to this url on logout. Set to "redirectUrl: false" to disable redirect
+
+ // idle settings
+ idleTimeLimit: Globals.idealTimeoutSeconds, // 'No activity' time limit in seconds. 1200 = 20 Minutes
+ idleCheckHeartbeat: 2, // Frequency to check for idle timeouts in seconds
+
+ // optional custom callback to perform before logout
+ customCallback: false, // set to false for no customCallback
+ // customCallback: function () { // define optional custom js function
+ // perform custom action before logout
+ // },
+
+ // configure which activity events to detect
+ // http://www.quirksmode.org/dom/events/
+ // https://developer.mozilla.org/en-US/docs/Web/Reference/Events
+ activityEvents: 'click keypress scroll wheel mousewheel mousemove', // separate each event with a space
+
+ // warning dialog box configuration
+ enableDialog: true, // set to false for logout without warning dialog
+ dialogDisplayLimit: 10, // Time to display the warning dialog before logout (and optional callback) in seconds. 180 = 3 Minutes
+ dialogTitle: 'Your session is about to expire!', // also displays on browser title bar
+ dialogText: 'Your session is about to expire.',
+ dialogTimeRemaining: 'You will be logged out in ',
+ dialogStayLoggedInButton: 'Stay Logged In',
+ dialogLogOutNowButton: 'Logout',
+
+ // error message if https://github.com/marcuswestin/store.js not enabled
+ errorAlertMessage: 'Please disable "Private Mode", or upgrade to a modern browser. Or perhaps a dependent file missing. Please see: https://github.com/marcuswestin/store.js',
+
+ // server-side session keep-alive timer
+ sessionKeepAliveTimer: 600, // ping the server at this interval in seconds. 600 = 10 Minutes. Set to false to disable pings
+ sessionKeepAliveUrl: window.location.href // set URL to ping - does not apply if sessionKeepAliveTimer: false
+ },
+
+ //##############################
+ //## Private Variables
+ //##############################
+ currentConfig = $.extend(defaultConfig, userRuntimeConfig), // merge default and user runtime configuration
+ origTitle = document.title, // save original browser title
+ activityDetector,
+ startKeepSessionAlive, stopKeepSessionAlive, keepSession, keepAlivePing, // session keep alive
+ idleTimer, remainingTimer, checkIdleTimeout, checkIdleTimeoutLoop, startIdleTimer, stopIdleTimer, // idle timer
+ openWarningDialog, dialogTimer, checkDialogTimeout, startDialogTimer, stopDialogTimer, isDialogOpen, destroyWarningDialog, countdownDisplay, // warning dialog
+ logoutUser;
+
+ //##############################
+ //## Public Functions
+ //##############################
+ // trigger a manual user logout
+ // use this code snippet on your site's Logout button: $.fn.idleTimeout().logout();
+ this.logout = function() {
+ store.set('idleTimerLoggedOut', true);
+ };
+
+ //##############################
+ //## Private Functions
+ //##############################
+
+ //----------- KEEP SESSION ALIVE FUNCTIONS --------------//
+ startKeepSessionAlive = function() {
+
+ keepSession = function() {
+ $.get(currentConfig.sessionKeepAliveUrl);
+ startKeepSessionAlive();
+ };
+
+ keepAlivePing = setTimeout(keepSession, (currentConfig.sessionKeepAliveTimer * 1000));
+ };
+
+ stopKeepSessionAlive = function() {
+ clearTimeout(keepAlivePing);
+ };
+
+ //----------- ACTIVITY DETECTION FUNCTION --------------//
+ activityDetector = function() {
+
+ $('body').on(currentConfig.activityEvents, function() {
+
+ if (!currentConfig.enableDialog || (currentConfig.enableDialog && isDialogOpen() !== true)) {
+ startIdleTimer();
+ $('#activity').effect('shake'); // added for demonstration page
+ }
+ });
+ };
+
+ //----------- IDLE TIMER FUNCTIONS --------------//
+ checkIdleTimeout = function() {
+
+ var timeIdleTimeout = (store.get('idleTimerLastActivity') + (currentConfig.idleTimeLimit * 1000));
+
+ if ($.now() > timeIdleTimeout) {
+
+ if (!currentConfig.enableDialog) { // warning dialog is disabled
+ logoutUser(); // immediately log out user when user is idle for idleTimeLimit
+ } else if (currentConfig.enableDialog && isDialogOpen() !== true) {
+ openWarningDialog();
+ startDialogTimer(); // start timing the warning dialog
+ }
+ } else if (store.get('idleTimerLoggedOut') === true) { //a 'manual' user logout?
+ logoutUser();
+ } else {
+
+ if (currentConfig.enableDialog && isDialogOpen() === true) {
+ destroyWarningDialog();
+ stopDialogTimer();
+ }
+ }
+ };
+
+ startIdleTimer = function() {
+ stopIdleTimer();
+ store.set('idleTimerLastActivity', $.now());
+ checkIdleTimeoutLoop();
+ };
+
+ checkIdleTimeoutLoop = function() {
+ checkIdleTimeout();
+ idleTimer = setTimeout(checkIdleTimeoutLoop, (currentConfig.idleCheckHeartbeat * 1000));
+ };
+
+ stopIdleTimer = function() {
+ clearTimeout(idleTimer);
+ };
+
+ //----------- WARNING DIALOG FUNCTIONS --------------//
+ openWarningDialog = function() {
+
+
+ var dialogContent = "<div id='idletimer_warning_dialog'><p>" + currentConfig.dialogText + "</p><p style='display:inline'>" + currentConfig.dialogTimeRemaining + ": <div style='display:inline' id='countdownDisplay'></div> secs.</p></div>";
+
+ var that = this,
+ modalObj = {
+ title: currentConfig.dialogTitle,
+ htmlContent: dialogContent,
+ okText: "Stay Signed-in",
+ cancelText: 'Logout',
+ mainClass: 'modal-lg',
+ allowCancel: true,
+ okCloses: false,
+ escape: false,
+ cancellable: true,
+ width: "500px",
+ mainClass: "ideal-timeout"
+ };
+ var modal = new Modal(modalObj);
+ modal.open();
+ modal.on('ok', function() {
+ if (userRuntimeConfig && userRuntimeConfig.onModalKeepAlive) {
+ userRuntimeConfig.onModalKeepAlive(); //hit session API
+ }
+ destroyWarningDialog();
+ modal.close();
+ stopDialogTimer();
+ startIdleTimer();
+ });
+ modal.on('closeModal', function() {
+ logoutUser();
+ });
+
+ countdownDisplay();
+
+ // document.title = currentConfig.dialogTitle;
+
+ if (currentConfig.sessionKeepAliveTimer) {
+ stopKeepSessionAlive();
+ }
+ };
+
+ checkDialogTimeout = function() {
+ var timeDialogTimeout = (store.get('idleTimerLastActivity') + (currentConfig.idleTimeLimit * 1000) + (currentConfig.dialogDisplayLimit * 1000));
+
+ if (($.now() > timeDialogTimeout) || (store.get('idleTimerLoggedOut') === true)) {
+ logoutUser();
+ }
+ };
+
+ startDialogTimer = function() {
+ dialogTimer = setInterval(checkDialogTimeout, (currentConfig.idleCheckHeartbeat * 1000));
+ };
+
+ stopDialogTimer = function() {
+ clearInterval(dialogTimer);
+ clearInterval(remainingTimer);
+ };
+
+ isDialogOpen = function() {
+ var dialogOpen = $("#idletimer_warning_dialog").is(":visible");
+
+ if (dialogOpen === true) {
+ return true;
+ }
+ return false;
+ };
+
+ destroyWarningDialog = function() {
+ if (currentConfig.sessionKeepAliveTimer) {
+ startKeepSessionAlive();
+ }
+ };
+
+ countdownDisplay = function() {
+ var dialogDisplaySeconds = currentConfig.dialogDisplayLimit,
+ mins, secs;
+
+ remainingTimer = setInterval(function() {
+ mins = Math.floor(dialogDisplaySeconds / 60); // minutes
+ if (mins < 10) { mins = '0' + mins; }
+ secs = dialogDisplaySeconds - (mins * 60); // seconds
+ if (secs < 10) { secs = '0' + secs; }
+ $('#countdownDisplay').html(mins + ':' + secs);
+ dialogDisplaySeconds -= 1;
+ }, 1000);
+ };
+
+ //----------- LOGOUT USER FUNCTION --------------//
+ logoutUser = function() {
+ store.set('idleTimerLoggedOut', true);
+
+ if (currentConfig.sessionKeepAliveTimer) {
+ stopKeepSessionAlive();
+ }
+
+ if (currentConfig.customCallback) {
+ currentConfig.customCallback();
+ }
+
+ if (currentConfig.redirectUrl) {
+ window.location.href = currentConfig.redirectUrl;
+ }
+ };
+
+ //###############################
+ // Build & Return the instance of the item as a plugin
+ // This is your construct.
+ //###############################
+ return this.each(function() {
+
+ if (store.enabled) {
+
+ store.set('idleTimerLastActivity', $.now());
+ store.set('idleTimerLoggedOut', false);
+
+ activityDetector();
+
+ if (currentConfig.sessionKeepAliveTimer) {
+ startKeepSessionAlive();
+ }
+
+ startIdleTimer();
+
+ } else {
+ alert(currentConfig.errorAlertMessage);
+ }
+
+ });
+ };
+
+ //------------------------------------------------
return Utils;
});
\ No newline at end of file