Heartbeat:

- Use the page visibility API (when available) and document.hasFocus() instead of window.onfocus/onblur. Improves speeding up/slowing down the interval and works for iframes by default.
- Add a setting for minimal interval. Maximum value is 10 min. This overrides all other intervals and cannot be changed after setting it at initialization. Can be used to reduce the frequency of requests on hosts that have low limits for used CPU time, etc.
- Extend the setting of interval to support 120 sec. (60 sec, is still the default).
- Always suspend after one hour of keyboard/mouse/touch inactivity.
Fixes #29779.
Built from https://develop.svn.wordpress.org/trunk@30293


git-svn-id: http://core.svn.wordpress.org/trunk@30292 1a063a9b-81f0-0310-95a4-ce76da25c4cd
This commit is contained in:
Andrew Ozz 2014-11-10 01:47:24 +00:00
parent f572927353
commit ba10ab197b
3 changed files with 113 additions and 101 deletions

View File

@ -57,6 +57,9 @@
// Used when the interval is reset
originalInterval: 0,
// Used to limit the number of AJAX requests.
minimalInterval: 0,
// Used together with tempInterval
countdown: 0,
@ -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
*
@ -374,12 +438,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 +457,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 +486,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 +498,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 +521,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 +602,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 +625,9 @@
case 60:
newInterval = 60000;
break;
case 120:
newInterval = 120000;
break;
case 'long-polling':
// Allow long polling, (experimental)
settings.mainInterval = 0;
@ -628,6 +636,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;

File diff suppressed because one or more lines are too long

View File

@ -4,7 +4,7 @@
*
* @global string $wp_version
*/
$wp_version = '4.1-alpha-30292';
$wp_version = '4.1-alpha-30293';
/**
* Holds the WordPress DB revision, increments when changes are made to the WordPress DB schema.