From 162037903da779ec9b18f2996c47eef48149eb4e Mon Sep 17 00:00:00 2001 From: Andrew Ozz Date: Wed, 27 Nov 2013 01:56:10 +0000 Subject: [PATCH] Heartbeat: introduce "suspend" functionality and enable it after 20 min. of inactivity, see #25073. Built from https://develop.svn.wordpress.org/trunk@26428 git-svn-id: http://core.svn.wordpress.org/trunk@26328 1a063a9b-81f0-0310-95a4-ce76da25c4cd --- wp-admin/includes/misc.php | 16 ++++++++++++ wp-includes/js/heartbeat.js | 44 +++++++++++++++++++++++++++++---- wp-includes/js/heartbeat.min.js | 2 +- 3 files changed, 56 insertions(+), 6 deletions(-) diff --git a/wp-admin/includes/misc.php b/wp-admin/includes/misc.php index 2a8eba2d63..8b0549dea6 100644 --- a/wp-admin/includes/misc.php +++ b/wp-admin/includes/misc.php @@ -739,3 +739,19 @@ function wp_refresh_post_nonces( $response, $data, $screen_id ) { return $response; } add_filter( 'heartbeat_received', 'wp_refresh_post_nonces', 10, 3 ); + +/** + * Disable suspending of Heartbeat on the Add/Edit Post screens + * + * @since 3.8 + */ +function wp_disable_heartbeat_suspend( $settings ) { + global $pagenow; + + if ( 'post.php' === $pagenow || 'post-new.php' === $pagenow ) { + $settings['suspend'] = 'disable'; + } + + return $settings; +} +add_filter( 'heartbeat_settings', 'wp_disable_heartbeat_suspend' ); diff --git a/wp-includes/js/heartbeat.js b/wp-includes/js/heartbeat.js index 3f5e64adee..bc0faa4b5a 100644 --- a/wp-includes/js/heartbeat.js +++ b/wp-includes/js/heartbeat.js @@ -34,8 +34,11 @@ var Heartbeat = function() { var $document = $(document), settings = { - // Used to stop the "beat" - isRunning: true, + // Suspend/resume + suspend: false, + + // Whether suspending is enabled + suspendEnabled: true, // Current screen id, defaults to the JS global 'pagenow' when present (in the admin) or 'front' screenId: '', @@ -128,6 +131,10 @@ if ( ! settings.screenId ) { settings.screenId = options.screenId || 'front'; } + + if ( options.suspend === 'disable' ) { + settings.suspendEnabled = false; + } } // Convert to milliseconds @@ -145,7 +152,12 @@ focused(); }).on( 'unload.wp-heartbeat', function() { // Don't connect any more - settings.isRunning = false; + settings.suspend = true; + + // Abort the last request if not completed + if ( settings.xhr && settings.xhr.readyState !== 4 ) { + settings.xhr.abort(); + } }); // Check for user activity every 30 seconds. @@ -274,7 +286,7 @@ // If the connection to the server is slower than the interval, // heartbeat connects as soon as the previous connection's response is received. - if ( settings.connecting ) { + if ( settings.connecting || settings.suspend ) { return; } @@ -351,7 +363,7 @@ var delta = time() - settings.lastTick, interval = settings.mainInterval; - if ( ! settings.isRunning ) { + if ( settings.suspend ) { return; } @@ -403,6 +415,9 @@ clearFocusTimers(); settings.userActivity = time(); + // Resume if suspended + settings.suspend = false; + if ( ! settings.hasFocus ) { settings.hasFocus = true; scheduleNextTick(); @@ -513,6 +528,11 @@ blurred(); } + if ( settings.suspendEnabled && lastActive > 1200000 ) { + // Suspend after 20 min. of inactivity + settings.suspend = true; + } + if ( ! settings.userActivityEvents ) { $document.on( 'mouseover.wp-heartbeat-active keyup.wp-heartbeat-active', function(){ userIsActive(); } ); @@ -561,6 +581,19 @@ scheduleNextTick(); } + /** + * Disable suspending + * + * Should be used only when Heartbeat is performing critical tasks like autosave, post-locking, etc. + * Using this on many screens may overload the user's hosting account if several + * browser windows/tabs are left open for a long time. + * + * @return void + */ + function disableSuspend() { + settings.suspendEnabled = false; + } + /** * Get/Set the interval * @@ -691,6 +724,7 @@ return { hasFocus: hasFocus, connectNow: connectNow, + disableSuspend: disableSuspend, setInterval: setInterval, hasConnectionError: hasConnectionError, enqueue: enqueue, diff --git a/wp-includes/js/heartbeat.min.js b/wp-includes/js/heartbeat.min.js index e83924c652..481e7fbcb0 100644 --- a/wp-includes/js/heartbeat.min.js +++ b/wp-includes/js/heartbeat.min.js @@ -1 +1 @@ -!function(a,b,c){var d=function(){function d(){if("string"==typeof b.pagenow&&(A.screenId=b.pagenow),"string"==typeof b.ajaxurl&&(A.url=b.ajaxurl),"object"==typeof b.heartbeatSettings){var c=b.heartbeatSettings;!A.url&&c.ajaxurl&&(A.url=c.ajaxurl),c.interval&&(A.mainInterval=c.interval,A.mainInterval<15?A.mainInterval=15:A.mainInterval>60&&(A.mainInterval=60)),A.screenId||(A.screenId=c.screenId||"front")}A.mainInterval=1e3*A.mainInterval,A.originalInterval=A.mainInterval,a(b).on("blur.wp-heartbeat-focus",function(){m(),A.winBlurTimer=b.setTimeout(function(){k()},500)}).on("focus.wp-heartbeat-focus",function(){n(),l()}).on("unload.wp-heartbeat",function(){A.isRunning=!1}),b.setInterval(function(){q()},3e4),z.ready(function(){A.lastTick=e(),j()})}function e(){return(new Date).getTime()}function f(a){var c,d=a.src;if(d&&/^https?:\/\//.test(d)&&(c=b.location.origin?b.location.origin:b.location.protocol+"//"+b.location.host,0!==d.indexOf(c)))return!1;try{if(a.contentWindow.document)return!0}catch(e){}return!1}function g(a,b){var c;if(a){switch(a){case"abort":break;case"timeout":c=!0;break;case"error":if(503===b&&A.hasConnected){c=!0;break}case"parsererror":case"empty":case"unknown":A.errorcount++,A.errorcount>2&&A.hasConnected&&(c=!0)}c&&!s()&&(A.connectionError=!0,z.trigger("heartbeat-connection-lost",[a,b]))}}function h(){A.hasConnected=!0,s()&&(A.errorcount=0,A.connectionError=!1,z.trigger("heartbeat-connection-restored"))}function i(){var c,d;A.connecting||(A.lastTick=e(),d=a.extend({},A.queue),A.queue={},z.trigger("heartbeat-send",[d]),c={data:d,interval:A.tempInterval?A.tempInterval/1e3:A.mainInterval/1e3,_nonce:"object"==typeof b.heartbeatSettings?b.heartbeatSettings.nonce:"",action:"heartbeat",screen_id:A.screenId,has_focus:A.hasFocus},A.connecting=!0,A.xhr=a.ajax({url:A.url,type:"post",timeout:3e4,data:c,dataType:"json"}).always(function(){A.connecting=!1,j()}).done(function(a,b,c){var d;return a?(h(),a.nonces_expired?(z.trigger("heartbeat-nonces-expired"),void 0):(a.heartbeat_interval&&(d=a.heartbeat_interval,delete a.heartbeat_interval),z.trigger("heartbeat-tick",[a,b,c]),d&&u(d),void 0)):(g("empty"),void 0)}).fail(function(a,b,c){g(b||"unknown",a.status),z.trigger("heartbeat-error",[a,b,c])}))}function j(){var a=e()-A.lastTick,c=A.mainInterval;A.isRunning&&(A.hasFocus?A.countdown>0&&A.tempInterval&&(c=A.tempInterval,A.countdown--,A.countdown<1&&(A.tempInterval=0)):c=12e4,b.clearTimeout(A.beatTimer),c>a?A.beatTimer=b.setTimeout(function(){i()},c-a):i())}function k(){o(),A.hasFocus=!1}function l(){o(),A.userActivity=e(),A.hasFocus||(A.hasFocus=!0,j())}function m(){a("iframe").each(function(c,d){f(d)&&(a.data(d,"wp-heartbeat-focus")||(a.data(d,"wp-heartbeat-focus",1),a(d.contentWindow).on("focus.wp-heartbeat-focus",function(){l()}).on("blur.wp-heartbeat-focus",function(){m(),A.frameBlurTimer=b.setTimeout(function(){k()},500)})))})}function n(){a("iframe").each(function(b,c){f(c)&&(a.removeData(c,"wp-heartbeat-focus"),a(c.contentWindow).off(".wp-heartbeat-focus"))})}function o(){b.clearTimeout(A.winBlurTimer),b.clearTimeout(A.frameBlurTimer)}function p(){A.userActivityEvents=!1,z.off(".wp-heartbeat-active"),a("iframe").each(function(b,c){f(c)&&a(c.contentWindow).off(".wp-heartbeat-active")}),l()}function q(){var b=A.userActivity?e()-A.userActivity:0;b>3e5&&A.hasFocus&&k(),A.userActivityEvents||(z.on("mouseover.wp-heartbeat-active keyup.wp-heartbeat-active",function(){p()}),a("iframe").each(function(b,c){f(c)&&a(c.contentWindow).on("mouseover.wp-heartbeat-active keyup.wp-heartbeat-active",function(){p()})}),A.userActivityEvents=!0)}function r(){return A.hasFocus}function s(){return A.connectionError}function t(){A.lastTick=0,j()}function u(a,b){var c,d=A.tempInterval?A.tempInterval:A.mainInterval;if(a){switch(a){case"fast":case 5:c=5e3;break;case 15:c=15e3;break;case 30:c=3e4;break;case 60:c=6e4;break;case"long-polling":return A.mainInterval=0,0;default:c=A.originalInterval}5e3===c?(b=parseInt(b,10)||30,b=1>b||b>30?30:b,A.countdown=b,A.tempInterval=c):(A.countdown=0,A.tempInterval=0,A.mainInterval=c),c!==d&&j()}return A.tempInterval?A.tempInterval/1e3:A.mainInterval/1e3}function v(a,b,c){return a?c&&this.isQueued(a)?!1:(A.queue[a]=b,!0):!1}function w(a){return a?A.queue.hasOwnProperty(a):void 0}function x(a){a&&delete A.queue[a]}function y(a){return a?this.isQueued(a)?A.queue[a]:c:void 0}var z=a(document),A={isRunning:!0,screenId:"",url:"",lastTick:0,queue:{},mainInterval:60,tempInterval:0,originalInterval:0,countdown:0,connecting:!1,connectionError:!1,errorcount:0,hasConnected:!1,hasFocus:!0,userActivity:0,userActivityEvents:!1,beatTimer:0,winBlurTimer:0,frameBlurTimer:0};return d(),{hasFocus:r,connectNow:t,setInterval:u,hasConnectionError:s,enqueue:v,dequeue:x,isQueued:w,getQueuedItem:y}};b.wp=b.wp||{},b.wp.heartbeat=new d}(jQuery,window); \ No newline at end of file +!function(a,b,c){var d=function(){function d(){if("string"==typeof b.pagenow&&(B.screenId=b.pagenow),"string"==typeof b.ajaxurl&&(B.url=b.ajaxurl),"object"==typeof b.heartbeatSettings){var c=b.heartbeatSettings;!B.url&&c.ajaxurl&&(B.url=c.ajaxurl),c.interval&&(B.mainInterval=c.interval,B.mainInterval<15?B.mainInterval=15:B.mainInterval>60&&(B.mainInterval=60)),B.screenId||(B.screenId=c.screenId||"front"),"disable"===c.suspend&&(B.suspendEnabled=!1)}B.mainInterval=1e3*B.mainInterval,B.originalInterval=B.mainInterval,a(b).on("blur.wp-heartbeat-focus",function(){m(),B.winBlurTimer=b.setTimeout(function(){k()},500)}).on("focus.wp-heartbeat-focus",function(){n(),l()}).on("unload.wp-heartbeat",function(){B.suspend=!0,B.xhr&&4!==B.xhr.readyState&&B.xhr.abort()}),b.setInterval(function(){q()},3e4),A.ready(function(){B.lastTick=e(),j()})}function e(){return(new Date).getTime()}function f(a){var c,d=a.src;if(d&&/^https?:\/\//.test(d)&&(c=b.location.origin?b.location.origin:b.location.protocol+"//"+b.location.host,0!==d.indexOf(c)))return!1;try{if(a.contentWindow.document)return!0}catch(e){}return!1}function g(a,b){var c;if(a){switch(a){case"abort":break;case"timeout":c=!0;break;case"error":if(503===b&&B.hasConnected){c=!0;break}case"parsererror":case"empty":case"unknown":B.errorcount++,B.errorcount>2&&B.hasConnected&&(c=!0)}c&&!s()&&(B.connectionError=!0,A.trigger("heartbeat-connection-lost",[a,b]))}}function h(){B.hasConnected=!0,s()&&(B.errorcount=0,B.connectionError=!1,A.trigger("heartbeat-connection-restored"))}function i(){var c,d;B.connecting||B.suspend||(B.lastTick=e(),d=a.extend({},B.queue),B.queue={},A.trigger("heartbeat-send",[d]),c={data:d,interval:B.tempInterval?B.tempInterval/1e3:B.mainInterval/1e3,_nonce:"object"==typeof b.heartbeatSettings?b.heartbeatSettings.nonce:"",action:"heartbeat",screen_id:B.screenId,has_focus:B.hasFocus},B.connecting=!0,B.xhr=a.ajax({url:B.url,type:"post",timeout:3e4,data:c,dataType:"json"}).always(function(){B.connecting=!1,j()}).done(function(a,b,c){var d;return a?(h(),a.nonces_expired?(A.trigger("heartbeat-nonces-expired"),void 0):(a.heartbeat_interval&&(d=a.heartbeat_interval,delete a.heartbeat_interval),A.trigger("heartbeat-tick",[a,b,c]),d&&v(d),void 0)):(g("empty"),void 0)}).fail(function(a,b,c){g(b||"unknown",a.status),A.trigger("heartbeat-error",[a,b,c])}))}function j(){var a=e()-B.lastTick,c=B.mainInterval;B.suspend||(B.hasFocus?B.countdown>0&&B.tempInterval&&(c=B.tempInterval,B.countdown--,B.countdown<1&&(B.tempInterval=0)):c=12e4,b.clearTimeout(B.beatTimer),c>a?B.beatTimer=b.setTimeout(function(){i()},c-a):i())}function k(){o(),B.hasFocus=!1}function l(){o(),B.userActivity=e(),B.suspend=!1,B.hasFocus||(B.hasFocus=!0,j())}function m(){a("iframe").each(function(c,d){f(d)&&(a.data(d,"wp-heartbeat-focus")||(a.data(d,"wp-heartbeat-focus",1),a(d.contentWindow).on("focus.wp-heartbeat-focus",function(){l()}).on("blur.wp-heartbeat-focus",function(){m(),B.frameBlurTimer=b.setTimeout(function(){k()},500)})))})}function n(){a("iframe").each(function(b,c){f(c)&&(a.removeData(c,"wp-heartbeat-focus"),a(c.contentWindow).off(".wp-heartbeat-focus"))})}function o(){b.clearTimeout(B.winBlurTimer),b.clearTimeout(B.frameBlurTimer)}function p(){B.userActivityEvents=!1,A.off(".wp-heartbeat-active"),a("iframe").each(function(b,c){f(c)&&a(c.contentWindow).off(".wp-heartbeat-active")}),l()}function q(){var b=B.userActivity?e()-B.userActivity:0;b>3e5&&B.hasFocus&&k(),B.suspendEnabled&&b>12e5&&(B.suspend=!0),B.userActivityEvents||(A.on("mouseover.wp-heartbeat-active keyup.wp-heartbeat-active",function(){p()}),a("iframe").each(function(b,c){f(c)&&a(c.contentWindow).on("mouseover.wp-heartbeat-active keyup.wp-heartbeat-active",function(){p()})}),B.userActivityEvents=!0)}function r(){return B.hasFocus}function s(){return B.connectionError}function t(){B.lastTick=0,j()}function u(){B.suspendEnabled=!1}function v(a,b){var c,d=B.tempInterval?B.tempInterval:B.mainInterval;if(a){switch(a){case"fast":case 5:c=5e3;break;case 15:c=15e3;break;case 30:c=3e4;break;case 60:c=6e4;break;case"long-polling":return B.mainInterval=0,0;default:c=B.originalInterval}5e3===c?(b=parseInt(b,10)||30,b=1>b||b>30?30:b,B.countdown=b,B.tempInterval=c):(B.countdown=0,B.tempInterval=0,B.mainInterval=c),c!==d&&j()}return B.tempInterval?B.tempInterval/1e3:B.mainInterval/1e3}function w(a,b,c){return a?c&&this.isQueued(a)?!1:(B.queue[a]=b,!0):!1}function x(a){return a?B.queue.hasOwnProperty(a):void 0}function y(a){a&&delete B.queue[a]}function z(a){return a?this.isQueued(a)?B.queue[a]:c:void 0}var A=a(document),B={suspend:!1,suspendEnabled:!0,screenId:"",url:"",lastTick:0,queue:{},mainInterval:60,tempInterval:0,originalInterval:0,countdown:0,connecting:!1,connectionError:!1,errorcount:0,hasConnected:!1,hasFocus:!0,userActivity:0,userActivityEvents:!1,beatTimer:0,winBlurTimer:0,frameBlurTimer:0};return d(),{hasFocus:r,connectNow:t,disableSuspend:u,setInterval:v,hasConnectionError:s,enqueue:w,dequeue:y,isQueued:x,getQueuedItem:z}};b.wp=b.wp||{},b.wp.heartbeat=new d}(jQuery,window); \ No newline at end of file