How To: Timeout (Client Side) using postMessage (HTML5) with Countdown alert
It's my first Englis How To... I hope can help others. Sorry my English isn't very good. Corrections are welcome!
Finally I can do TimeOut at client side... you need a browser with postMessage (HTML5) compatibility.
My first implementation was create an mouse and keyboard detection. But I'm using tab panel, and any tab panel is an iFrame then my script only works in the master page, but not in any tab. Then I'm trying to catch mouse and keyboard events in any iFrame and send this to master and run the script in the master page, but this actions was blocked by browsers to prevent hacking actions.
Surfing into the web I found in HTML the postMessage that is used to send message between windows and iFrames.
Here an example how it works: http://robertnyman.com/2010/03/18/po...s-and-iframes/
Then now I can catch the events in any iFrame but the action is run directly in the master page.
NOTE: I'm working with MVC
1: Create a TimeOut.js into Scripts folder file with this content:
Code:
// Session Timeout client side. Master and Detail detection.
/**
* Detecting in Master and Detail, Mouse and Keyboard events.
* Using postMessage (HTML5)
* @autor Camilo Martinez [Equiman], http://gplus.to/equiman
* @created 2012-04-11
* @updated 2012-04-22
* @licence CC BY-SA http://creativecommons.org/licenses/by-sa/3.0/
*/
// Add this into Master Page (TabPanelContain):
// <DocumentReady Handler="masterTimeOut();" />
var masterTimeOut = function () {
//Convert minutes value indicated in TimeOut del Web.Config to seconds
var min = 0;
var sec = 0;
var timer = null;
var vis = false;
doTimer = function () {
// At least 1 min, show the countdown window
if ((min - sec) < 60) {
updateTime();
if (frmTimeOut.hidden) {
vis = true;
frmTimeOut.setVisible(true);
}
}
else {
if (!frmTimeOut.hidden) {
vis = false;
frmTimeOut.setVisible(false);
}
}
// Check the countdown counter
if ((min - sec) > 0) {
sec++;
// Repeat the process each minute
timer = setTimeout('doTimer()', 1000);
}
else {
// When countdown is finish, redirect to Login page
top.location.replace(GetNewPath('/Home/Login/'));
}
};
stopCount = function () {
if (vis === true) {
//2 seconds Idle (no detect events, because showing alert window is detected as mousemove)
if ((min - sec) < 58) {
vis = false;
}
}
else {
// Convert minutes to second, minus 10 to be sure Client TimeOut occurs first than Server Timeout
min = (document.getElementById('txtMinTimeOut').value * 60) - 10;
sec = 0;
clearTimeout(timer);
doTimer();
}
};
updateTime = function () {
var message = 'Inactivity was detected. Your session will expire in';
var time = (min - sec);
var unity = 'seconds.';
Ext.getCmp('lblText').setText(message + ' ' + time + ' ' + unity);
};
// Start counter on Load
document.onload = function () {
stopCount();
return false;
};
// Star counter when mouse move
document.onmousemove = function () {
stopCount();
return false;
};
// Star counter when key is pressed
document.onkeypress = function () {
stopCount();
return false;
};
// Read and event when is send from an iFrame
function displayMessage(e) {
if ((e.origin.split(":", 2)[0] + ":" + e.origin.split(":", 2)[1]) === (GetNewPath("/").split(":", 2)[0] + ":" + GetNewPath("/").split(":", 2)[1])) {
// If the iFrame send any of this events start counter
switch (e.data) {
case "onload":
case "onmousemove":
case "onkeypress":
stopCount();
}
}
};
if (window.addEventListener) {
// For standards-compliant web browsers
window.addEventListener("message", displayMessage, false);
}
else {
window.attachEvent("onmessage", displayMessage);
};
};
// Add this into any iFrame Page:
// <DocumentReady Handler="detailTimeOut();" />
var detailTimeOut = function () {
// Start counter on Load
document.onload = function () {
top.postMessage("onload", GetNewPath("/"));
return false;
};
// Star counter when mouse move
document.onmousemove = function () {
top.postMessage("onmousemove", GetNewPath("/"));
return false;
};
// Star counter when key is pressed
document.onkeypress = function () {
top.postMessage("onkeypress", GetNewPath("/"));
return false;
};
};
// Get the Path when use VirtualPath in .Net or IIS
var GetNewPath = function (relative_path) {
var url = window.location.href;
if (url.substring(url.length - 1, url.length) == '/') {
url = url.substring(0, url.length - 1);
}
var url_parts = url.split('/');
if (relative_path.substring(0, 1) != '/') {
url_parts[url_parts.length - 2] = relative_path;
url_parts[url_parts.length - 1] = '';
}
else {
url_parts[url_parts.length - 2] = relative_path.substring(1);
url_parts[url_parts.length - 1] = '';
}
var new_page_absolute_path = url_parts.join('/');
if (new_page_absolute_path.substring(new_page_absolute_path.length - 1, new_page_absolute_path.length) == '/') {
new_page_absolute_path = new_page_absolute_path.substring(0, new_page_absolute_path.length - 1);
}
return new_page_absolute_path;
};
2: Add the timeout to Web.Config (in minutes). Into <system.web> add:
Code:
<sessionState timeout="5"></sessionState>
3: Read into master page the TimeOutValue.
Add Namespace System.Web
Code:
<%@ Page Language="C#" Inherits="System.Web.Mvc.ViewPage<dynamic>" %>
<%@ Register Assembly="Ext.Net" Namespace="Ext.Net" TagPrefix="ext" %>
<%@ Import Namespace="System.Web" %>
Into <head> tag read the TimeOut time and send to Hidden TextField:
Code:
<script runat="server">
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack && !X.IsAjaxRequest)
{
txtMinTimeOut.Value = Session.Timeout;
}
}
</script>
Into <body><form> tags tead the TimeOut.js, when Document Ready load the masterTimeout() and create the Hidden Text Field:
Code:
<asp:ScriptManager ID="smmaster" EnableScriptLocalization="true" runat="server">
<Scripts>
<asp:ScriptReference Path="~/Scripts/TimeOut.js" />
</Scripts>
</asp:ScriptManager>
<ext:ResourceManager ID="ResourceManagerMaster2" runat="server">
<Listeners>
<DocumentReady Handler="masterTimeOut();" />
</Listeners>
</ext:ResourceManager>
<ext:Hidden ID="txtMinTimeOut" runat="server" />
Create a Window to show the countdown alert, before </form> tag:
Code:
<ext:Window
ID="frmTimeOut"
runat="server"
Width="235"
Height="50"
Modal="false"
Resizable="False"
Hidden="true"
Closable="false"
Layout="FormLayout"
Draggable="false"
Padding="12">
<Items>
<ext:Label ID="lblText" runat="server" HideLabel="true" Text="" AutoWidth="true" />
</Items>
</ext:Window>
4: In any iFrame (page loaded into Iframe or Tab Panel) add Into <body><form> tags tead the TimeOut.js, when Document Ready load the detailTimeout():
Code:
<asp:ScriptManager ID="smDetail" EnableScriptLocalization="true" runat="server">
<Scripts>
<asp:ScriptReference Path="~/Scripts/TimeOut.js" />
</Scripts>
</asp:ScriptManager>
<ext:ResourceManager ID="ResourceManager1" runat="server">
<Listeners>
<DocumentReady Handler="detailTimeOut();" />
</Listeners>
</ext:ResourceManager>
And it's Done!!!