3

In my web application I have a idle monitor which is triggered if a user is idle for 5 minutes. It will open a confirm dialog which will wait for 2 minutes; after that it will redirect to login page.

Requirement: I want to show a countdown timer with the time remaining before the user will be redirected to the login page.

baseTemplate.xhtml:

<h:form>

    <p:idleMonitor timeout="#{idleMonitorView.timeoutVal}"
        onidle="startTimer()" />

    <p:confirmDialog id="confirmDialog"
        message="You have been idle, Please click ok to remain logged in"
        header="Are you there?" severity="alert" widgetVar="idleDialog">                 
        <p:commandButton id="confirm" value="Ok" oncomplete="extendSession()" />

    </p:confirmDialog>

    <p:remoteCommand name="terminateIdleSession" actionListener="#{idleMonitorView.onIdle}" out="count" />

    <script type="text/javascript">
        var extend_session = 0;
        function startTimer() {

            extend_session = 0;
            setTimeout("timeout()", 120000);
            PF('idleDialog').show();
        }

        function timeout() {
            if (extend_session == 0) {
                terminateIdleSession();
            }
        }

        function extendSession() {
            extend_session = 1;
            PF('idleDialog').hide();
        }
    </script>
</h:form>

Problem: I don't know that how to achieve this requirement.

MostlyJava
  • 345
  • 3
  • 21

1 Answers1

1

You should create a JavaScript interval which updates a timer every second (or any other interval you need). You can update your timer using a bit of jQuery. I would recommend to add a span to the dialog message which you can use as a timer:

$("#myForm\\:confirmDialog .ui-confirm-dialog-message").append("<span id=logoffTimeout/>");

You should replace myForm with the ID you've used on your form here.

When the dialog is shown, calculate the time your logoff timer will expire and store it for example in window.logoffTime. Now you can use the following function to update the timer:

function updateTimer(){
  var seconds = Math.ceil((window.logoffTime - new Date().getTime()) / 1000);
  $("#logoffTimeout").html(seconds);
}

On your buttons and remote command I would suggest to use process="@this". See also: Understanding PrimeFaces process/update and JSF f:ajax execute/render attributes

What you should know is when you start a timeout in JavaScript, an ID is returned. You can use that ID to clear your timeout.

I ended up with this XHTML:

<p:confirmDialog id="confirmDialog"
                 message="Please click Ok before the timer runs out: "
                 header="Are you there?"
                 severity="alert"
                 closable="false"
                 widgetVar="idleDialog">
  <p:commandButton id="confirm"
                   value="Ok"
                   process="@this"
                   onclick="clearTimeout(window.logoffTimeoutId); PF('idleDialog').hide();"/>
</p:confirmDialog>

<p:remoteCommand name="terminateIdleSession"
                 actionListener="#{idleMonitorView.onIdle}"
                 process="@this"
                 out="count"/>

<p:idleMonitor timeout="#{5 * 60 * 1000}"
               onidle="startTimer()"/>

And this JavaScript:

function startTimer() {
  clearTimeout(window.logoffUpdaterId);
  PF('idleDialog').show();
  // Set timeout to 2 minutes
  var timeout = 2 * 60 * 1000;
  // Calculate when the time runs out
  window.logoffTime = new Date().getTime() + timeout;
  // Start timer which calls remote command
  window.logoffTimeoutId = setTimeout(terminateIdleSession, timeout);
  // Update timer every second
  window.logoffUpdaterId = setInterval(updateTimer, 1000);
  // Update timer now
  updateTimer();
}

// Update the timer
function updateTimer() {
  var seconds = Math.ceil((window.logoffTime - new Date().getTime()) / 1000);
  $("#logoffTimeout").html(seconds);
}

// Create span to contain the timer
$(function(){
  $("#myForm\\:confirmDialog .ui-confirm-dialog-message").append("<span id=logoffTimeout/>");
});

I've noted that you are using your JavaScript embedded in your XHTML. In that case add CDATA to prevent running into XML errors:

<script type="text/javascript">
//<![CDATA[
...
//]]>
</script>

I would suggest to load your script from a file / resource which will give you the benefit of caching.

Community
  • 1
  • 1
Jasper de Vries
  • 19,370
  • 6
  • 64
  • 102
  • I am getting this Error "Open quote is expected for attribute "id" associated with an element type "span". ". And Dialog box is also not coming up.But when i removed the function 'Create span to contain the timer' then dialog box come up without timer. – MostlyJava Apr 30 '17 at 08:52
  • @Narendra I've updated the answer. Please add CDATA to your script. – Jasper de Vries Apr 30 '17 at 08:56
  • I have one issue that,after click on Ok button, timeout is not being reset. to 5 minute.Explanation: Suppose i am idle for 5 minute,then Dialog box is coming up to wait for 2 minute,and if i click on OK Button after 50 seconds the Dialog Box is being Hide but after (120-50=70) seconds it's automatic redirecting to login Page ( Without any confirmation dialog).It seems it's not resetting timeoutVal to 5 minute.It's keep timeoutVal=2 minute – MostlyJava May 02 '17 at 09:13
  • My bad. `logoffTimeoutId` should have been cleared. See update. – Jasper de Vries May 02 '17 at 09:23
  • Now it's perfect. – MostlyJava May 02 '17 at 10:29
  • Maybe we should add this to `p:idleMonitor` and create a pull request... – Kukeltje May 02 '17 at 10:34
  • Now I am getting one problem if multiple Browser Tabs are open and one page is active and other are not still user is going to be logged out.In my application session is managed by Spring. – MostlyJava Jul 13 '17 at 05:17
  • in your `onIdle` you could check the http://docs.oracle.com/javaee/7/api/javax/servlet/http/HttpSession.html#getLastAccessedTime-- to detect activity in different tabs / windows. – Jasper de Vries Jul 13 '17 at 07:14