X-Git-Url: https://scripts.mit.edu/gitweb/autoinstalls/wordpress.git/blobdiff_plain/41578db67d72562346e4dbb2a14889b23d522813..9441756a895fb4fdc4bcf20e0d228cef622663ca:/wp-includes/js/heartbeat.js diff --git a/wp-includes/js/heartbeat.js b/wp-includes/js/heartbeat.js index c097973f..9f025823 100644 --- a/wp-includes/js/heartbeat.js +++ b/wp-includes/js/heartbeat.js @@ -57,13 +57,16 @@ // Used when the interval is reset originalInterval: 0, + // Used to limit the number of AJAX requests. + minimalInterval: 0, + // Used together with tempInterval countdown: 0, // Whether a connection is currently in progress connecting: false, - // Whether a connection error occured + // Whether a connection error occurred connectionError: false, // Used to track non-critical errors @@ -81,10 +84,8 @@ // Flags whether events tracking user activity were set userActivityEvents: false, - // References to various timeouts - beatTimer: 0, - winBlurTimer: 0, - frameBlurTimer: 0 + checkFocusTimer: 0, + beatTimer: 0 }; /** @@ -95,6 +96,8 @@ * @return void */ function initialize() { + var options, hidden, visibilityState, visibilitychange; + if ( typeof window.pagenow === 'string' ) { settings.screenId = window.pagenow; } @@ -105,24 +108,39 @@ // Pull in options passed from PHP if ( typeof window.heartbeatSettings === 'object' ) { - var options = window.heartbeatSettings; + options = window.heartbeatSettings; // The XHR URL can be passed as option when window.ajaxurl is not set if ( ! settings.url && options.ajaxurl ) { settings.url = options.ajaxurl; } - // The interval can be from 15 to 60 sec. and can be set temporarily to 5 sec. + // The interval can be from 15 to 120 sec. and can be set temporarily to 5 sec. + // It can be set in the initial options or changed later from JS and/or from PHP. if ( options.interval ) { settings.mainInterval = options.interval; if ( settings.mainInterval < 15 ) { settings.mainInterval = 15; - } else if ( settings.mainInterval > 60 ) { - settings.mainInterval = 60; + } else if ( settings.mainInterval > 120 ) { + settings.mainInterval = 120; } } + // Used to limit the number of AJAX requests. Overrides all other intervals if they are shorter. + // Needed for some hosts that cannot handle frequent requests and the user may exceed the allocated server CPU time, etc. + // The minimal interval can be up to 600 sec. however setting it to longer than 120 sec. will limit or disable + // some of the functionality (like post locks). + // Once set at initialization, minimalInterval cannot be changed/overriden. + if ( options.minimalInterval ) { + options.minimalInterval = parseInt( options.minimalInterval, 10 ); + settings.minimalInterval = options.minimalInterval > 0 && options.minimalInterval <= 600 ? options.minimalInterval * 1000 : 0; + } + + if ( settings.minimalInterval && settings.mainInterval < settings.minimalInterval ) { + settings.mainInterval = settings.minimalInterval; + } + // 'screenId' can be added from settings on the front-end where the JS global 'pagenow' is not set if ( ! settings.screenId ) { settings.screenId = options.screenId || 'front'; @@ -137,16 +155,47 @@ settings.mainInterval = settings.mainInterval * 1000; settings.originalInterval = settings.mainInterval; - // Set focus/blur events on the window - $(window).on( 'blur.wp-heartbeat-focus', function() { - setFrameFocusEvents(); - // We don't know why the 'blur' was fired. Either the user clicked in an iframe or outside the browser. - // Running blurred() after some timeout lets us cancel it if the user clicked in an iframe. - settings.winBlurTimer = window.setTimeout( function(){ blurred(); }, 500 ); - }).on( 'focus.wp-heartbeat-focus', function() { - removeFrameFocusEvents(); - focused(); - }).on( 'unload.wp-heartbeat', function() { + // Switch the interval to 120 sec. by using the Page Visibility API. + // If the browser doesn't support it (Safari < 7, Android < 4.4, IE < 10), the interval + // will be increased to 120 sec. after 5 min. of mouse and keyboard inactivity. + if ( typeof document.hidden !== 'undefined' ) { + hidden = 'hidden'; + visibilitychange = 'visibilitychange'; + visibilityState = 'visibilityState'; + } else if ( typeof document.msHidden !== 'undefined' ) { // IE10 + hidden = 'msHidden'; + visibilitychange = 'msvisibilitychange'; + visibilityState = 'msVisibilityState'; + } else if ( typeof document.webkitHidden !== 'undefined' ) { // Android + hidden = 'webkitHidden'; + visibilitychange = 'webkitvisibilitychange'; + visibilityState = 'webkitVisibilityState'; + } + + if ( hidden ) { + if ( document[hidden] ) { + settings.hasFocus = false; + } + + $document.on( visibilitychange + '.wp-heartbeat', function() { + if ( document[visibilityState] === 'hidden' ) { + blurred(); + window.clearInterval( settings.checkFocusTimer ); + } else { + focused(); + if ( document.hasFocus ) { + settings.checkFocusTimer = window.setInterval( checkFocus, 10000 ); + } + } + }); + } + + // Use document.hasFocus() if available. + if ( document.hasFocus ) { + settings.checkFocusTimer = window.setInterval( checkFocus, 10000 ); + } + + $(window).on( 'unload.wp-heartbeat', function() { // Don't connect any more settings.suspend = true; @@ -157,7 +206,7 @@ }); // Check for user activity every 30 seconds. - window.setInterval( function(){ checkUserActivity(); }, 30000 ); + window.setInterval( checkUserActivity, 30000 ); // Start one tick after DOM ready $document.ready( function() { @@ -206,6 +255,21 @@ return false; } + /** + * Check if the document's focus has changed + * + * @access private + * + * @return void + */ + function checkFocus() { + if ( settings.hasFocus && ! document.hasFocus() ) { + blurred(); + } else if ( ! settings.hasFocus && document.hasFocus() ) { + focused(); + } + } + /** * Set error state and fire an event on XHR errors or timeout * @@ -325,7 +389,6 @@ if ( response.nonces_expired ) { $document.trigger( 'heartbeat-nonces-expired' ); - return; } // Change the interval from PHP @@ -374,12 +437,16 @@ } } + if ( settings.minimalInterval && interval < settings.minimalInterval ) { + interval = settings.minimalInterval; + } + window.clearTimeout( settings.beatTimer ); if ( delta < interval ) { settings.beatTimer = window.setTimeout( function() { - connect(); + connect(); }, interval - delta ); @@ -389,26 +456,24 @@ } /** - * Set the internal state when the browser window looses focus + * Set the internal state when the browser window becomes hidden or loses focus * * @access private * * @return void */ function blurred() { - clearFocusTimers(); settings.hasFocus = false; } /** - * Set the internal state when the browser window is focused + * Set the internal state when the browser window becomes visible or is in focus * * @access private * * @return void */ function focused() { - clearFocusTimers(); settings.userActivity = time(); // Resume if suspended @@ -420,68 +485,6 @@ } } - /** - * Add focus/blur events to all local iframes - * - * Used to detect when focus is moved from the main window to an iframe - * - * @access private - * - * @return void - */ - function setFrameFocusEvents() { - $('iframe').each( function( i, frame ) { - if ( ! isLocalFrame( frame ) ) { - return; - } - - if ( $.data( frame, 'wp-heartbeat-focus' ) ) { - return; - } - - $.data( frame, 'wp-heartbeat-focus', 1 ); - - $( frame.contentWindow ).on( 'focus.wp-heartbeat-focus', function() { - focused(); - }).on('blur.wp-heartbeat-focus', function() { - setFrameFocusEvents(); - // We don't know why 'blur' was fired. Either the user clicked in the main window or outside the browser. - // Running blurred() after some timeout lets us cancel it if the user clicked in the main window. - settings.frameBlurTimer = window.setTimeout( function(){ blurred(); }, 500 ); - }); - }); - } - - /** - * Remove the focus/blur events to all local iframes - * - * @access private - * - * @return void - */ - function removeFrameFocusEvents() { - $('iframe').each( function( i, frame ) { - if ( ! isLocalFrame( frame ) ) { - return; - } - - $.removeData( frame, 'wp-heartbeat-focus' ); - $( frame.contentWindow ).off( '.wp-heartbeat-focus' ); - }); - } - - /** - * Clear the reset timers for focus/blur events on the window and iframes - * - * @access private - * - * @return void - */ - function clearFocusTimers() { - window.clearTimeout( settings.winBlurTimer ); - window.clearTimeout( settings.frameBlurTimer ); - } - /** * Runs when the user becomes active after a period of inactivity * @@ -494,11 +497,9 @@ $document.off( '.wp-heartbeat-active' ); $('iframe').each( function( i, frame ) { - if ( ! isLocalFrame( frame ) ) { - return; + if ( isLocalFrame( frame ) ) { + $( frame.contentWindow ).off( '.wp-heartbeat-active' ); } - - $( frame.contentWindow ).off( '.wp-heartbeat-active' ); }); focused(); @@ -519,25 +520,28 @@ function checkUserActivity() { var lastActive = settings.userActivity ? time() - settings.userActivity : 0; + // Throttle down when no mouse or keyboard activity for 5 min. if ( lastActive > 300000 && settings.hasFocus ) { - // Throttle down when no mouse or keyboard activity for 5 min blurred(); } - if ( settings.suspendEnabled && lastActive > 1200000 ) { - // Suspend after 20 min. of inactivity + // Suspend after 10 min. of inactivity when suspending is enabled. + // Always suspend after 60 min. of inactivity. This will release the post lock, etc. + if ( ( settings.suspendEnabled && lastActive > 600000 ) || lastActive > 3600000 ) { settings.suspend = true; } if ( ! settings.userActivityEvents ) { - $document.on( 'mouseover.wp-heartbeat-active keyup.wp-heartbeat-active', function(){ userIsActive(); } ); + $document.on( 'mouseover.wp-heartbeat-active keyup.wp-heartbeat-active touchend.wp-heartbeat-active', function() { + userIsActive(); + }); $('iframe').each( function( i, frame ) { - if ( ! isLocalFrame( frame ) ) { - return; + if ( isLocalFrame( frame ) ) { + $( frame.contentWindow ).on( 'mouseover.wp-heartbeat-active keyup.wp-heartbeat-active touchend.wp-heartbeat-active', function() { + userIsActive(); + }); } - - $( frame.contentWindow ).on( 'mouseover.wp-heartbeat-active keyup.wp-heartbeat-active', function(){ userIsActive(); } ); }); settings.userActivityEvents = true; @@ -597,7 +601,7 @@ * In this case the number of 'ticks' can be passed as second argument. * If the window doesn't have focus, the interval slows down to 2 min. * - * @param mixed speed Interval: 'fast' or 5, 15, 30, 60 + * @param mixed speed Interval: 'fast' or 5, 15, 30, 60, 120 * @param string ticks Used with speed = 'fast' or 5, how many ticks before the interval reverts back * @return int Current interval in seconds */ @@ -620,6 +624,9 @@ case 60: newInterval = 60000; break; + case 120: + newInterval = 120000; + break; case 'long-polling': // Allow long polling, (experimental) settings.mainInterval = 0; @@ -628,6 +635,10 @@ newInterval = settings.originalInterval; } + if ( settings.minimalInterval && newInterval < settings.minimalInterval ) { + newInterval = settings.minimalInterval; + } + if ( 5000 === newInterval ) { ticks = parseInt( ticks, 10 ) || 30; ticks = ticks < 1 || ticks > 30 ? 30 : ticks;