Skip to content

Commit d1dc587

Browse files
authored
Example of syncing tabs
1 parent 65ca9b9 commit d1dc587

File tree

1 file changed

+250
-0
lines changed

1 file changed

+250
-0
lines changed

demos/autolougoutsync.html

Lines changed: 250 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,250 @@
1+
<!DOCTYPE html>
2+
<html>
3+
4+
<head>
5+
<meta charset='utf-8' />
6+
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
7+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
8+
<meta name="description" content="Jquery-idletimer : provides you a way to monitor user activity with a page." />
9+
<title>Jquery-idletimer</title>
10+
11+
<!-- jQuery and idleTimer -->
12+
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
13+
<script type="text/javascript" src="../src/idle-timer.js"></script>
14+
15+
<!-- Bootstrap and moment -->
16+
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
17+
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"></script>
18+
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script>
19+
<script src="https://momentjs.com/downloads/moment.min.js"></script>
20+
21+
<style>
22+
body {
23+
padding-top: 5rem;
24+
}
25+
</style>
26+
</head>
27+
28+
<body>
29+
<nav class="navbar navbar-expand-md navbar-dark bg-dark fixed-top">
30+
<a class="navbar-brand" href="index.html">Jquery-idletimer</a>
31+
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarsExampleDefault" aria-controls="navbarsExampleDefault" aria-expanded="false" aria-label="Toggle navigation">
32+
<span class="navbar-toggler-icon"></span>
33+
</button>
34+
35+
<div class="collapse navbar-collapse" id="navbarsExampleDefault">
36+
<ul class="navbar-nav mr-auto">
37+
<li class="nav-item"><a class="nav-link" href="index.html">Main Demo</a></li>
38+
<li class="nav-item"><a class="nav-link" href="autologout.html">Auto Logout</a></li>
39+
<li class="nav-item"><a class="nav-link" href="defaultbinding.html">Default Binding</a></li>
40+
<li class="nav-item"><a class="nav-link" href="https://github.com/thorst/jquery-idletimer">Documentation</a></li>
41+
</ul>
42+
<ul class="navbar-nav">
43+
<li class="nav-item"><a class="nav-link" href="https://github.com/thorst/jquery-idletimer/zipball/master">Zip</a></li>
44+
<li class="nav-item"><a class="nav-link" href="https://github.com/thorst/jquery-idletimer/tarball/master">Tar</a></li>
45+
<li class="nav-item"><a class="nav-link" href="https://github.com/thorst/jquery-idletimer">Github</a>
46+
</li>
47+
</ul>
48+
</div>
49+
</nav>
50+
<div class="container">
51+
<h2>Concept</h2>
52+
<p>
53+
Wait 10 seconds, you will see a expiring warning. Wait 10 more seconds and you will see that you have been logged out.
54+
</p>
55+
<p>
56+
In the real world I forward them to the logout url, which intern fowards them to login screen, instead of showing the 2nd dialog. You can modify the app.session.logout function.
57+
</p>
58+
<p>
59+
We could use the active.idleTimer event to clearTimeout, however I prefer the user to explicitly say they want to keep the session open by clicking ok, not just moving the mouse on the screen.
60+
</p>
61+
<p>
62+
This demo takes into account when a mobile device closes the browser, and after the idle timeout expires, launches the browser again. Instead of displaying the warning, it will jump straight to the logged out dialog.
63+
</p>
64+
<p>
65+
For this demo we've enabled localStorage to sync accross tabs of the same browser. This will keep the client side happy, but we still need a keepAlive service to keep the server side session active.
66+
</p>
67+
<p>
68+
For the sake of complete demo, I've included the code needed to call a keepalive url to keep the server side session valid.
69+
</p>
70+
</div>
71+
<div class="modal fade" id="mdlExpirationWarning" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true" data-backdrop="static" data-keyboard="false">
72+
<div class="modal-dialog" role="document">
73+
<div class="modal-content">
74+
<div class="modal-header">
75+
<h5 class="modal-title" id="exampleModalLabel">Session Expiration Warning</h5>
76+
77+
</div>
78+
<div class="modal-body">
79+
<p>You've been inactive for a while. For your security, we'll log you out automatically. Click "Stay Online" to continue your session. </p>
80+
<p>Your session will expire in <span class="bold" id="sessionSecondsRemaining">120</span> seconds.
81+
</p>
82+
</div>
83+
<div class="modal-footer">
84+
<button id="extendSession" type="button" class="btn btn-primary" data-dismiss="modal">Stay
85+
Online</button>
86+
<button id="logoutSession" type="button" class="btn btn-secondary">Logout</button>
87+
</div>
88+
</div>
89+
</div>
90+
</div>
91+
92+
<div class="modal fade" id="mdlLoggedOut" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true" data-backdrop="static" data-keyboard="false">
93+
<div class="modal-dialog" role="document">
94+
<div class="modal-content">
95+
<div class="modal-header">
96+
<h5 class="modal-title" id="exampleModalLabel">You have been logged out</h5>
97+
</div>
98+
<div class="modal-body">
99+
<p>Your session has expired.</p>
100+
</div>
101+
</div>
102+
</div>
103+
</div>
104+
105+
<script>
106+
// You could pull this out to its own file very easily
107+
window.app = window.app || {};
108+
109+
app.session = {
110+
111+
//Settings
112+
warningTimeout: 10000, //(ms) The time we give them to say they want to stay signed in
113+
inactiveTimeout: 20000, //(ms) The time until we display a warning message
114+
minWarning: 5000, //(ms) If they come back to page (on mobile), The minumum amount, before we just log them out
115+
timerSyncId: "SomethingUnique", //The key idleTimer will use to write to localStorage
116+
logoutUrl: "/logout", //Your url to log out, if you want you could build the url to pass a referal param
117+
keepAliveUrl: "api/user/KeepAlive", // The url for the keepalive api
118+
keepaliveInterval: 5000, //(ms) the interval to call keep alive url
119+
//From here down you shouldnt have to alter anything
120+
warningStart: null, //Date time the warning was started
121+
warningTimer: null, //Timer running every second to countdown to logout
122+
keepaliveTimer: null, //Timer for independent ping to keep session alive
123+
logout: function() {
124+
//Write to storage to tell other tab its time to sign out
125+
if (typeof(localStorage) !== "undefined") {
126+
localStorage.setItem(app.session.timerSyncId, 0);
127+
}
128+
129+
//Send this page to the logout url, that will destroy session and forward to login
130+
//window.location = app.session.logoutUrl;
131+
132+
//To simulate logout we are just showing the logout dialog and locking the screen
133+
$("#mdlExpirationWarning").modal("hide");
134+
$("#mdlLoggedOut").modal("show");
135+
},
136+
keepAlive: function() {
137+
//Hide logout modal
138+
$("#mdlExpirationWarning").modal("hide");
139+
140+
//Clear the timer
141+
clearTimeout(app.session.warningTimer);
142+
app.session.warningTimer = null;
143+
144+
//Restart the idleTimer
145+
$(document).idleTimer("reset");
146+
},
147+
startKeepAliveTimer: function() {
148+
// Basically I just poll the server half way through the session life
149+
// to make sure the servers session stays valid
150+
clearTimeout(app.session.keepaliveTimer);
151+
app.session.keepaliveTimer = setInterval(function() {
152+
app.session.sendKeepAlive();
153+
}, (app.session.inactiveTimeout / 2));
154+
},
155+
sendKeepAlive: function() {
156+
// Write a new date to storage so any other tabs are informed that this tab
157+
// sent the keepalive
158+
if (typeof(localStorage) !== "undefined") {
159+
localStorage.setItem(app.session.timerSyncId + "_keepalive", +new Date());
160+
}
161+
162+
// The actual call to the keep alive api
163+
//$.post(app.session.keepAliveUrl).fail(function (jqXHR) {
164+
// if (jqXHR.status == 500 || jqXHR.status == 0) {
165+
// app.session.logout();
166+
// }
167+
//});
168+
},
169+
showWarning: function(obj) {
170+
//Get time when user was last active
171+
var diff = (+new Date()) - obj.lastActive - obj.timeout,
172+
warning = (+new Date()) - diff;
173+
174+
// Destroy idleTimer so users are forced to click the extend button
175+
$(document).idleTimer("pause");
176+
177+
//On mobile js is paused, so see if this was triggered while we were sleeping
178+
if (diff >= app.session.warningTimeout || warning <= app.session.minWarning) {
179+
app.session.logout();
180+
} else {
181+
182+
//Show dialog, and note the time
183+
$('#sessionSecondsRemaining').html(Math.round((app.session.warningTimeout - diff) / 1000));
184+
$("#mdlExpirationWarning").modal("show");
185+
app.session.warningStart = (+new Date()) - diff;
186+
187+
//Update counter downer every second
188+
app.session.warningTimer = setInterval(function() {
189+
var remaining = Math.round((app.session.warningTimeout / 1000) - (((+new Date()) - app.session.warningStart) / 1000));
190+
191+
if (remaining >= 0) {
192+
$('#sessionSecondsRemaining').html(remaining);
193+
} else {
194+
app.session.logout();
195+
}
196+
}, 1000)
197+
}
198+
},
199+
localWrite: function(e) {
200+
201+
if (typeof(localStorage) !== "undefined" && e.originalEvent.key == app.session.timerSyncId && app.session.warningTimer != null) {
202+
// If another tab has written to cache then
203+
if (e.originalEvent.newValue == 0) {
204+
// If they wrote a 0 that means they chose to logout when prompted
205+
app.session.logout();
206+
} else {
207+
// They chose to stay online, so hide the dialog
208+
app.session.keepAlive();
209+
}
210+
211+
} else if (typeof(localStorage) !== "undefined" && e.originalEvent.key == app.session.timerSyncId + "_keepalive") {
212+
// If the other tab sent a keepAlive poll to the server, reset the time here so we dont send two updates
213+
// This isnt really needed per se but it will save some server load
214+
app.session.startKeepAliveTimer();
215+
}
216+
}
217+
};
218+
219+
$(function() {
220+
//This will fire at X after page load, to show an inactive warning
221+
$(document).on("idle.idleTimer", function(event, elem, obj) {
222+
app.session.showWarning(obj);
223+
});
224+
225+
//Create a timer to keep server session alive, independent of idleTimer
226+
app.session.startKeepAliveTimer();
227+
228+
//User clicked ok to extend session
229+
$("#extendSession").click(function() {
230+
app.session.keepAlive(); //Remove the warning dialog etc
231+
});
232+
233+
//User clicked logout
234+
$("#logoutSession").click(function() {
235+
app.session.logout();
236+
});
237+
238+
//Set up the idleTimer, if inactive for X seconds log them out
239+
$(document).idleTimer({
240+
timeout: app.session.inactiveTimeout - app.session.warningTimeout,
241+
timerSyncId: app.session.timerSyncId
242+
});
243+
244+
// Monitor writes by other tabs
245+
$(window).bind("storage", app.session.localWrite);
246+
});
247+
</script>
248+
</body>
249+
250+
</html>

0 commit comments

Comments
 (0)