Jquery plugins 在多个选项卡中同步jQuery空闲超时

Jquery plugins 在多个选项卡中同步jQuery空闲超时,jquery-plugins,Jquery Plugins,我正在使用 我的问题很简单,但我知道不会有任何简单的答案 当网站只在一个选项卡中打开时,插件工作得很好。我想做的是,当用户打开任何数量的标签网站,它应该只有一个后台计时器,但信息信息应该显示在所有标签上 例如,考虑用户在3个不同的选项卡中打开一个网站,但只主动使用一个选项卡(显然),因此当前插件感觉到用户在指定的时间内在该选项卡上处于非活动状态,并将其注销,这是不正确的,因为用户仍在积极使用其他选项卡。 我知道我必须把一些黑客放在某个地方,但我真的不明白在哪里,如何。如果有人已经这样做了,那对我

我正在使用

我的问题很简单,但我知道不会有任何简单的答案

当网站只在一个选项卡中打开时,插件工作得很好。我想做的是,当用户打开任何数量的标签网站,它应该只有一个后台计时器,但信息信息应该显示在所有标签上

例如,考虑用户在3个不同的选项卡中打开一个网站,但只主动使用一个选项卡(显然),因此当前插件感觉到用户在指定的时间内在该选项卡上处于非活动状态,并将其注销,这是不正确的,因为用户仍在积极使用其他选项卡。
我知道我必须把一些黑客放在某个地方,但我真的不明白在哪里,如何。如果有人已经这样做了,那对我真的会有很大帮助。此外,欢迎提出任何建议。请帮帮忙。

我也有同样的问题!空闲计时器可以使用localStorage变量跨多个窗口和选项卡进行通信(保持同步)。大多数现代浏览器都支持此功能。在github上,marcuswestin/store.js为旧浏览器提供了良好的功能和“回退”行为

以下是idleTimer插件的“测试”代码,该插件提供了同步的窗口/选项卡(必须全部位于同一域中)。它设置2个localStorage变量来跟踪用户会话的状态

您可以在这里看到此代码的演示。打开多个窗口/选项卡并观察。

/**
*这部作品是根据麻省理工学院许可证授权的
*
*jQuery的可配置空闲(无活动)计时器和注销重定向。
*跨同一域的多个窗口、选项卡和iFrame工作。
*
*依赖项:jqueryv1.7+、jqueryui、store.js fromhttps://github.com/marcuswestin/store.js -v1.3.4+
*
*注释并记录控制台,以便使用Firefox和Firebug或类似工具进行调试
*版本1.0.6
**/
/*全局jQuery:false,文档:false,存储:false,clearInterval:false,setInterval:false,setTimeout:false,窗口:false,警报:false,控制台:false*/
/*jslint缩进:2,sloppy:true,plusplus:true*/
(函数($){
$.fn.idleTimeout=函数(选项){
console.log('start');
//##############################
//##配置变量
//##############################
var默认值={
idleTimeLimit:30000,//30秒用于测试。“无活动”时间限制(毫秒)。1200000=20分钟
dialogDisplayLimit:20000,//20秒用于测试。在重定向(和可选回调)之前显示警告对话框的时间(毫秒)。180000=3分钟
redirectUrl:'/logout',//在超时注销时重定向到此url。设置为“redirectUrl:false”可禁用重定向
//在重定向之前执行的可选自定义回调
customCallback:false,//设置为false表示没有customCallback
//customCallback:function(){//定义可选的自定义js函数
//在注销前执行自定义操作
// },
//配置要检测的活动事件
// http://www.quirksmode.org/dom/events/
// https://developer.mozilla.org/en-US/docs/Web/Reference/Events
activityEvents:'单击按键滚动滚轮鼠标滚轮',//用空格分隔每个事件
//对话框配置
dialogTitle:“会话过期警告”,
dialogText:'因为您一直处于非活动状态,您的会话即将过期。',
//服务器端会话保持活动计时器
sessionKeepAliveTimer:600000//以毫秒为单位在此间隔Ping服务器。600000=10分钟
//sessionKeepAliveTimer:false//设置为false以禁用ping
},
//##############################
//##私有变量
//##############################
opts=$.extend(默认值、选项),
checkHeartbeat=2000,//检查超时的频率-2000=2秒
origTitle=document.title,//保存原始浏览器标题
sessionKeepAliveUrl=window.location.href,//将URL设置为ping到用户的当前窗口
保持会话活动,活动检测器,
idleTimer、remainingTimer、checkIdleTimeout、idleTimerLastActivity、StartItemer、stopIdleTimer、,
openWarningDialog、dialogTimer、checkDialogTimeout、startDialogTimer、stopDialogTimer、isDialogOpen、destroyWarningDialog、,
倒计时显示,注销用户,
检查iframes,includeFrames,attachEventFrame;//iframe功能
//##############################
//##私人职能
//##############################
keepSessionAlive=函数(){
if(选择sessionKeepAliveTimer){
var keepSession=函数(){
if(idletimerastactivity===store.get('idletimerastactivity')){
log('keep session alive function');
$.get(sessionKeepAliveUrl);
}
};
setInterval(keepSession,opts.sessionKeepAliveTimer);
}
};
activityDetector=函数(){
$('body')。on(opts.activityEvents,function(){
如果(isDialogOpen()!==true){
console.log(“检测到的活动”);
startIdleTimer();
}否则{
console.log('dialog open.activity ignored');
}
});
};
checkIdleTimeout=函数(){
var timeNow=$.now(),timeIdleTimeout=(store.get('idletimerastactivity')+opts.idleTimeLimit);
if(timeNow>timeIdleTimeout){
log('timeNow:'+timeNow+'>idle'+timeIdleTimeout);
如果(isDialogOpen()!==true){
log('对话框未打开&将打开');
openWarningDialog();
startDialogTimer();
}
}else if(store.get('idleTimerLoggedOut')==true){//a‘手动’用户注销?
logoutUser();
}否则{
log('idle not timeout');
如果(isDialogOpen()==真){
log('对话框已打开并将关闭');
销毁警告对话框();
停止对话时间
/**
 * 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));