jquery-idle-timeout-plugin多选项卡浏览

时间:2013-05-15 21:13:40

标签: jquery-plugins

我一直在尝试集成jquery-idle-timeout-plugin来显示当用户空闲一段时间时会话超时弹出警告。

除了浏览器的新标签之外,一切正常。当我移动到新选项卡或其他选项卡然后或任何回发后,会话变为活动并重新设置该特定选项卡的计时器,但不重新设置其他选项卡或页面的计时器。

请查看以下代码

    <script type="text/javascript">
    var idleTime = 12000; // number of miliseconds until the user is considered idle
    var initialSessionTimeoutMessage = 'Your session will expire in <span id="sessionTimeoutCountdown"></span>&nbsp;seconds.<br/><br />Click on <b>OK</b> to continue your session.';
    var sessionTimeoutCountdownId = 'sessionTimeoutCountdown';
    var redirectAfter = 10; // number of seconds to wait before redirecting the user
    var path = getPath();
    var redirectTo = "logout.aspx";
    var keepAliveURL = 'Default.aspx'; // URL to call to keep the session alive
    var expiredMessage = 'Your session has expired.  You are being logged out for  security reasons.'; // message to show user when the countdown reaches 0
    var running = false; // var to check if the countdown is running
    var timer; // reference to the setInterval timer so it can be stopped
    $(document).ready(function () {
        var path = window.location.pathname;
        var file = path.split('/')[1];
        if (file == 'Login.aspx') {
            return;
        }
        // create the warning window and set autoOpen to false
        var sessionTimeoutWarningDialog = $("#sessionTimeoutWarning");
        $(sessionTimeoutWarningDialog).html(initialSessionTimeoutMessage);
        $(sessionTimeoutWarningDialog).dialog({
            title: 'Session Expiration Warning',
            autoOpen: false, // set this to false so we can manually open it
            closeOnEscape: false,
            draggable: false,
            width: 460,
            minHeight: 50,
            modal: true,
            beforeclose: function () { // bind to beforeclose so if the user clicks on the "X" or escape to close the dialog, it will work too
                // stop the timer
                clearInterval(timer);
                // stop countdown
                running = false;
                // ajax call to keep the server-side session alive
                $.ajax({
                    url: keepAliveURL,
                    async: true
                });
            },
            buttons: {
                OK: function () {
                    // close dialog
                    $(this).dialog('close');
                }
            },
            resizable: false,
            open: function () {
                // scrollbar fix for IE
                $('body').css('overflow', 'hidden');
            },
            close: function () {
                // reset overflow
                $('body').css('overflow', 'auto');
            }
        }); // end of dialog
        // start the idle timer
        $.idleTimer(idleTime);
        // bind to idleTimer's idle.idleTimer event
        $(document).bind("idle.idleTimer", function () {
            // if the user is idle and a countdown isn't already running
            if ($.data(document, 'idleTimer') === 'idle' && !running) {
                var counter = redirectAfter;
                running = true;
                // intialisze timer
                $('#' + sessionTimeoutCountdownId).html(redirectAfter);
                // open dialog
                $(sessionTimeoutWarningDialog).dialog('open');
                // create a timer that runs every second
                timer = setInterval(function () {
                    counter -= 1;

                    // if the counter is 0, redirect the user
                    if (counter == 0) {
                        $(sessionTimeoutWarningDialog).html(expiredMessage);
                        $(sessionTimeoutWarningDialog).dialog('disable');
                        window.location = redirectTo;
                    } else {
                        $('#' + sessionTimeoutCountdownId).html(counter);
                    };
                }, 1000);
            };
        });
    });

   </script>

请告诉我如何解决其他标签的问题(同步所有页面的计时器)

由于

2 个答案:

答案 0 :(得分:3)

我明白了你的观点,使用jQuery的Idle超时插件只是识别它没有与多个选项卡或窗口选项集成的超时。但你可以像下面那样以一种棘手的方式实现这一目标。

jQuery(window).blur(function(){
//your code here to stop the finding idle time check
});
jQuery(window).focus(function(){
//your code here to start idle time check
});

请参阅:http://www.walkswithme.net/idle-timeout-plugin-using-jquery

答案 1 :(得分:3)

您的空闲计时器可以跨多个窗口进行通信(保持同步)。使用localStorage变量的选项卡。在github上,marcuswestin / store.js提供了多种浏览器类型的良好功能。请注意,某些浏览器/设备不支持localStorage,但大多数现代浏览器都支持localStorage。

这是idleTimer插件的'测试'代码,它提供了同步窗口和放大器。标签,只要它们都在同一个域中。它设置了2个localStorage变量,idleTimerLastActivity&amp; idleTimerLoggedOut,用于跟踪用户会话的“状态”。

演示页面。打开多个窗口/标签,您可以看到它是如何工作的。 http://jillelaine.github.io/jquery-idleTimeout/

/**
 * This work is licensed under the MIT License
 *
 * Configurable idle (no activity) timer and logout redirect for jQuery.
 * Works across multiple windows, tabs and iframes from the same domain.
 *
 * Dependencies: JQuery v1.7+, JQuery UI, store.js from https://github.com/marcuswestin/store.js - v1.3.4+
 *
 * Commented and console logged for debugging with Firefox & Firebug or similar
 * version 1.0.6
 **/

/*global jQuery: false, document: false, store: false, clearInterval: false, setInterval: false, setTimeout: false, window: false, alert: false, console: false*/
/*jslint indent: 2, sloppy: true, plusplus: true*/

(function ($) {

  $.fn.idleTimeout = function (options) {
    console.log('start');
    //##############################
    //## Configuration Variables
    //##############################
    var defaults = {
      idleTimeLimit: 30000,         // 30 seconds for testing. 'No activity' time limit in milliseconds. 1200000 = 20 Minutes
      dialogDisplayLimit: 20000,    // 20 seconds for testing. Time to display the warning dialog before redirect (and optional callback) in milliseconds. 180000 = 3 Minutes
      redirectUrl: '/logout',       // redirect to this url on timeout logout. Set to "redirectUrl: false" to disable redirect

      // optional custom callback to perform before redirect
      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', // separate each event with a space

      //dialog box configuration
      dialogTitle: 'Session Expiration Warning',
      dialogText: 'Because you have been inactive, your session is about to expire.',

      // server-side session keep-alive timer
      sessionKeepAliveTimer: 600000 // Ping the server at this interval in milliseconds. 600000 = 10 Minutes
      // sessionKeepAliveTimer: false // Set to false to disable pings
    },

    //##############################
    //## Private Variables
    //##############################
      opts = $.extend(defaults, options),
      checkHeartbeat = 2000, // frequency to check for timeouts - 2000 = 2 seconds
      origTitle = document.title, // save original browser title
      sessionKeepAliveUrl = window.location.href, // set URL to ping to user's current window
      keepSessionAlive, activityDetector,
      idleTimer, remainingTimer, checkIdleTimeout, idleTimerLastActivity, startIdleTimer, stopIdleTimer,
      openWarningDialog, dialogTimer, checkDialogTimeout, startDialogTimer, stopDialogTimer, isDialogOpen, destroyWarningDialog,
      countdownDisplay, logoutUser,
      checkForIframes, includeIframes, attachEventIframe; // iframe functionality

    //##############################
    //## Private Functions
    //##############################
    keepSessionAlive = function () {

      if (opts.sessionKeepAliveTimer) {
        var keepSession = function () {
          if (idleTimerLastActivity === store.get('idleTimerLastActivity')) {
            console.log('keep session alive function');
            $.get(sessionKeepAliveUrl);
          }
        };

        setInterval(keepSession, opts.sessionKeepAliveTimer);
      }
    };

    activityDetector = function () {

      $('body').on(opts.activityEvents, function () {

        if (isDialogOpen() !== true) {
          console.log('activity detected');
          startIdleTimer();
        } else {
          console.log('dialog open. activity ignored');
        }
      });
    };

    checkIdleTimeout = function () {
      var timeNow = $.now(), timeIdleTimeout = (store.get('idleTimerLastActivity') + opts.idleTimeLimit);

      if (timeNow > timeIdleTimeout) {
        console.log('timeNow: ' + timeNow + ' > idle ' + timeIdleTimeout);
        if (isDialogOpen() !== true) {
          console.log('dialog is not open & will be opened');
          openWarningDialog();
          startDialogTimer();
        }
      } else if (store.get('idleTimerLoggedOut') === true) { //a 'manual' user logout?
        logoutUser();
      } else {
        console.log('idle not yet timed out');
        if (isDialogOpen() === true) {
          console.log('dialog is open & will be closed');
          destroyWarningDialog();
          stopDialogTimer();
        }
      }
    };

    startIdleTimer = function () {
      stopIdleTimer();
      idleTimerLastActivity = $.now();
      store.set('idleTimerLastActivity', idleTimerLastActivity);
      console.log('start idle timer: ' + idleTimerLastActivity);
      idleTimer = setInterval(checkIdleTimeout, checkHeartbeat);
    };

    stopIdleTimer = function () {
      clearInterval(idleTimer);
    };

    openWarningDialog = function () {
      var dialogContent = "<div id='idletimer_warning_dialog'><p>" + opts.dialogText + "</p><p style='display:inline'>Time remaining: <div style='display:inline' id='countdownDisplay'></div></p></div>";

      $(dialogContent).dialog({
        buttons: {
          "Stay Logged In": function () {
            console.log('Stay Logged In button clicked');
            destroyWarningDialog();
            stopDialogTimer();
            startIdleTimer();
          },
          "Log Out Now": function () {
            console.log('Log Out Now button clicked');
            logoutUser();
          }
        },
        closeOnEscape: false,
        modal: true,
        title: opts.dialogTitle
      });

      // hide the dialog's upper right corner "x" close button
      $('.ui-dialog-titlebar-close').css('display', 'none');

      // start the countdown display
      countdownDisplay();

      // change title bar to warning message
      document.title = opts.dialogTitle;
    };

    checkDialogTimeout = function () {
      var timeNow = $.now(), timeDialogTimeout = (store.get('idleTimerLastActivity') + opts.idleTimeLimit + opts.dialogDisplayLimit);

      if ((timeNow > timeDialogTimeout) || (store.get('idleTimerLoggedOut') === true)) {
        console.log('timeNow: ' + timeNow + ' > dialog' + timeDialogTimeout);
        logoutUser();
      } else {
        console.log('dialog not yet timed out');
      }
    };

    startDialogTimer = function () {
      dialogTimer = setInterval(checkDialogTimeout, checkHeartbeat);
    };

    stopDialogTimer = function () {
      clearInterval(dialogTimer);
      clearInterval(remainingTimer);
    };

    isDialogOpen = function () {
      var dialogOpen = $("#idletimer_warning_dialog").is(":visible");

      if (dialogOpen === true) {
        return true;
      }
      return false;
    };

    destroyWarningDialog = function () {
      console.log('dialog destroyed');
      $(".ui-dialog-content").dialog('destroy').remove();
      document.title = origTitle;
    };

    // display remaining time on warning dialog
    countdownDisplay = function () {
      var dialogDisplaySeconds = opts.dialogDisplayLimit / 1000, 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);
    };

    logoutUser = function () {
      console.log('logout function');
      store.set('idleTimerLoggedOut', true);

      if (opts.customCallback) {
        console.log('logout function custom callback');
        opts.customCallback();
      }

      if (opts.redirectUrl) {
        console.log('logout function redirect to URL');
        window.location.href = opts.redirectUrl;
      }
    };

    // document must be in readyState 'complete' before looking for iframes
    checkForIframes = function () {

      var docReadyCheck, isDocReady;

      docReadyCheck = function () {
        if (document.readyState === "complete") {
          console.log('check for iframes, now that the document is complete');
          clearInterval(isDocReady);
          includeIframes();
        }
      };

      isDocReady = setInterval(docReadyCheck, 1000);
    };

    // look for iframes
    includeIframes = function () {
      console.log('include iframes start');

      var foundIframes = document.getElementsByTagName('iframe'), index, iframeItem;

      if (foundIframes.length > 0) { //at least one iframe found
        console.log('iframes found: ' + foundIframes.length);
        // attach events to each iframe found
        for (index = 0; index < foundIframes.length; index++) {

          iframeItem = foundIframes.item(index);

          if (iframeItem.attachEvent) { // IE < 11. Returns a boolean true/false
            console.log('attach event to iframe. Browser IE < 11');
            iframeItem.attachEvent('onload', attachEventIframe(index));
          } else { // IE >= 11 and FF, etc.
            console.log('attach event to iframe. Browser NOT IE < 11');
            iframeItem.addEventListener('load', attachEventIframe(index), false);
          }

        } // end for loop

      } // end if any iframes
    };

    // attach events to each iframe
    attachEventIframe = function (index) {

      var iframe = $('iframe:eq(' + index + ')').contents().find('html');

      iframe.on(opts.activityEvents, function (event) {
        console.log('bubbling iframe activity event to body of page');
        $('body').trigger(event);
      });
    };

    //###############################
    // Build & Return the instance of the item as a plugin
    // This is your construct.
    //###############################
    return this.each(function () {

      if (store.enabled) {
        idleTimerLastActivity = $.now();
        store.set('idleTimerLastActivity', idleTimerLastActivity);
        store.set('idleTimerLoggedOut', false);
      } else {
        alert('Please disable "Private Mode", or upgrade to a modern browser. Or perhaps a dependent file missing. Please see: https://github.com/marcuswestin/store.js');
      }

      activityDetector();

      keepSessionAlive();

      startIdleTimer();

      checkForIframes();
    });
  };
}(jQuery));