diff options
Diffstat (limited to 'wp-includes/js/heartbeat.js')
-rw-r--r-- | wp-includes/js/heartbeat.js | 461 |
1 files changed, 0 insertions, 461 deletions
diff --git a/wp-includes/js/heartbeat.js b/wp-includes/js/heartbeat.js deleted file mode 100644 index 8023600659..0000000000 --- a/wp-includes/js/heartbeat.js +++ /dev/null @@ -1,461 +0,0 @@ -/** - * Heartbeat API - * - * Note: this API is "experimental" meaning it will likely change a lot - * in the next few releases based on feedback from 3.6.0. If you intend - * to use it, please follow the development closely. - * - * Heartbeat is a simple server polling API that sends XHR requests to - * the server every 15 seconds and triggers events (or callbacks) upon - * receiving data. Currently these 'ticks' handle transports for post locking, - * login-expiration warnings, and related tasks while a user is logged in. - * - * Available filters in ajax-actions.php: - * - heartbeat_received - * - heartbeat_send - * - heartbeat_tick - * - heartbeat_nopriv_received - * - heartbeat_nopriv_send - * - heartbeat_nopriv_tick - * @see wp_ajax_nopriv_heartbeat(), wp_ajax_heartbeat() - * - * @since 3.6.0 - */ - - // Ensure the global `wp` object exists. -window.wp = window.wp || {}; - -(function($){ - var Heartbeat = function() { - var self = this, - running, - beat, - screenId = typeof pagenow != 'undefined' ? pagenow : '', - url = typeof ajaxurl != 'undefined' ? ajaxurl : '', - settings, - tick = 0, - queue = {}, - interval, - connecting, - countdown = 0, - errorcount = 0, - tempInterval, - hasFocus = true, - isUserActive, - userActiveEvents, - winBlurTimeout, - frameBlurTimeout = -1, - hasConnectionError = false; - - /** - * Returns a boolean that's indicative of whether or not there is a connection error - * - * @returns boolean - */ - this.hasConnectionError = function() { - return hasConnectionError; - }; - - if ( typeof( window.heartbeatSettings ) == 'object' ) { - settings = $.extend( {}, window.heartbeatSettings ); - - // Add private vars - url = settings.ajaxurl || url; - delete settings.ajaxurl; - delete settings.nonce; - - interval = settings.interval || 15; // default interval - delete settings.interval; - // The interval can be from 15 to 60 sec. and can be set temporarily to 5 sec. - if ( interval < 15 ) - interval = 15; - else if ( interval > 60 ) - interval = 60; - - interval = interval * 1000; - - // 'screenId' can be added from settings on the front-end where the JS global 'pagenow' is not set - screenId = screenId || settings.screenId || 'front'; - delete settings.screenId; - - // Add or overwrite public vars - $.extend( this, settings ); - } - - function time(s) { - if ( s ) - return parseInt( (new Date()).getTime() / 1000 ); - - return (new Date()).getTime(); - } - - function isLocalFrame( frame ) { - var origin, src = frame.src; - - if ( src && /^https?:\/\//.test( src ) ) { - origin = window.location.origin ? window.location.origin : window.location.protocol + '//' + window.location.host; - - if ( src.indexOf( origin ) !== 0 ) - return false; - } - - try { - if ( frame.contentWindow.document ) - return true; - } catch(e) {} - - return false; - } - - // Set error state and fire an event on XHR errors or timeout - function errorstate( error ) { - var trigger; - - if ( error ) { - switch ( error ) { - case 'abort': - // do nothing - break; - case 'timeout': - // no response for 30 sec. - trigger = true; - break; - case 'parsererror': - case 'error': - case 'empty': - case 'unknown': - errorcount++; - - if ( errorcount > 2 ) - trigger = true; - - break; - } - - if ( trigger && ! self.hasConnectionError() ) { - hasConnectionError = true; - $(document).trigger( 'heartbeat-connection-lost', [error] ); - } - } else if ( self.hasConnectionError() ) { - errorcount = 0; - hasConnectionError = false; - $(document).trigger( 'heartbeat-connection-restored' ); - } - } - - function connect() { - var send = {}, data, i, empty = true, - nonce = typeof window.heartbeatSettings == 'object' ? window.heartbeatSettings.nonce : ''; - tick = time(); - - data = $.extend( {}, queue ); - // Clear the data queue, anything added after this point will be send on the next tick - queue = {}; - - $(document).trigger( 'heartbeat-send', [data] ); - - for ( i in data ) { - if ( data.hasOwnProperty( i ) ) { - empty = false; - break; - } - } - - // If nothing to send (nothing is expecting a response), - // schedule the next tick and bail - if ( empty && ! self.hasConnectionError() ) { - connecting = false; - next(); - return; - } - - send.data = data; - send.interval = interval / 1000; - send._nonce = nonce; - send.action = 'heartbeat'; - send.screen_id = screenId; - send.has_focus = hasFocus; - - connecting = true; - self.xhr = $.ajax({ - url: url, - type: 'post', - timeout: 30000, // throw an error if not completed after 30 sec. - data: send, - dataType: 'json' - }).done( function( response, textStatus, jqXHR ) { - var new_interval; - - if ( ! response ) - return errorstate( 'empty' ); - - // Clear error state - if ( self.hasConnectionError() ) - errorstate(); - - if ( response.nonces_expired ) { - $(document).trigger( 'heartbeat-nonces-expired' ); - return; - } - - // Change the interval from PHP - if ( response.heartbeat_interval ) { - new_interval = response.heartbeat_interval; - delete response.heartbeat_interval; - } - - self.tick( response, textStatus, jqXHR ); - - // do this last, can trigger the next XHR if connection time > 5 sec. and new_interval == 'fast' - if ( new_interval ) - self.interval.call( self, new_interval ); - }).always( function() { - connecting = false; - next(); - }).fail( function( jqXHR, textStatus, error ) { - errorstate( textStatus || 'unknown' ); - self.error( jqXHR, textStatus, error ); - }); - } - - function next() { - var delta = time() - tick, t = interval; - - if ( ! running ) - return; - - if ( ! hasFocus ) { - t = 100000; // 100 sec. Post locks expire after 120 sec. - } else if ( countdown > 0 && tempInterval ) { - t = tempInterval; - countdown--; - } - - window.clearTimeout(beat); - - if ( delta < t ) { - beat = window.setTimeout( - function(){ - if ( running ) - connect(); - }, - t - delta - ); - } else { - connect(); - } - } - - function blurred() { - window.clearTimeout(winBlurTimeout); - window.clearTimeout(frameBlurTimeout); - winBlurTimeout = frameBlurTimeout = 0; - - hasFocus = false; - } - - function focused() { - window.clearTimeout(winBlurTimeout); - window.clearTimeout(frameBlurTimeout); - winBlurTimeout = frameBlurTimeout = 0; - - isUserActive = time(); - - if ( hasFocus ) - return; - - hasFocus = true; - window.clearTimeout(beat); - - if ( ! connecting ) - next(); - } - - function setFrameEvents() { - $('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(e) { - focused(); - }).on('blur.wp-heartbeat-focus', function(e) { - setFrameEvents(); - frameBlurTimeout = window.setTimeout( function(){ blurred(); }, 500 ); - }); - }); - } - - $(window).on( 'blur.wp-heartbeat-focus', function(e) { - setFrameEvents(); - winBlurTimeout = window.setTimeout( function(){ blurred(); }, 500 ); - }).on( 'focus.wp-heartbeat-focus', function() { - $('iframe').each( function( i, frame ) { - if ( !isLocalFrame( frame ) ) - return; - - $.removeData( frame, 'wp-heartbeat-focus' ); - $( frame.contentWindow ).off( '.wp-heartbeat-focus' ); - }); - - focused(); - }); - - function userIsActive() { - userActiveEvents = false; - $(document).off( '.wp-heartbeat-active' ); - $('iframe').each( function( i, frame ) { - if ( ! isLocalFrame( frame ) ) - return; - - $( frame.contentWindow ).off( '.wp-heartbeat-active' ); - }); - - focused(); - } - - // Set 'hasFocus = true' if user is active and the window is in the background. - // Set 'hasFocus = false' if the user has been inactive (no mouse or keyboard activity) for 5 min. even when the window has focus. - function checkUserActive() { - var lastActive = isUserActive ? time() - isUserActive : 0; - - // Throttle down when no mouse or keyboard activity for 5 min - if ( lastActive > 300000 && hasFocus ) - blurred(); - - if ( ! userActiveEvents ) { - $(document).on( 'mouseover.wp-heartbeat-active keyup.wp-heartbeat-active', function(){ userIsActive(); } ); - - $('iframe').each( function( i, frame ) { - if ( ! isLocalFrame( frame ) ) - return; - - $( frame.contentWindow ).on( 'mouseover.wp-heartbeat-active keyup.wp-heartbeat-active', function(){ userIsActive(); } ); - }); - - userActiveEvents = true; - } - } - - // Check for user activity every 30 seconds. - window.setInterval( function(){ checkUserActive(); }, 30000 ); - $(document).ready( function() { - // Start one tick (15 sec) after DOM ready - running = true; - tick = time(); - next(); - }); - - this.hasFocus = function() { - return hasFocus; - }; - - /** - * Get/Set the interval - * - * When setting to 'fast', the interval is 5 sec. for the next 30 ticks (for 2 min and 30 sec). - * If the window doesn't have focus, the interval slows down to 2 min. - * - * @param string speed Interval speed: 'fast' (5sec), 'standard' (15sec) default, 'slow' (60sec) - * @param string ticks Used with speed = 'fast', how many ticks before the speed reverts back - * @return int Current interval in seconds - */ - this.interval = function( speed, ticks ) { - var reset, seconds; - ticks = parseInt( ticks, 10 ) || 30; - ticks = ticks < 1 || ticks > 30 ? 30 : ticks; - - if ( speed ) { - switch ( speed ) { - case 'fast': - seconds = 5; - countdown = ticks; - break; - case 'slow': - seconds = 60; - countdown = 0; - break; - case 'long-polling': - // Allow long polling, (experimental) - interval = 0; - return 0; - break; - default: - seconds = 15; - countdown = 0; - } - - // Reset when the new interval value is lower than the current one - reset = seconds * 1000 < interval; - - if ( countdown > 0 ) { - tempInterval = seconds * 1000; - } else { - interval = seconds * 1000; - tempInterval = 0; - } - - if ( reset ) - next(); - } - - if ( ! hasFocus ) - return 120; - - return tempInterval ? tempInterval / 1000 : interval / 1000; - }; - - /** - * Enqueue data to send with the next XHR - * - * As the data is sent later, this function doesn't return the XHR response. - * To see the response, use the custom jQuery event 'heartbeat-tick' on the document, example: - * $(document).on( 'heartbeat-tick.myname', function( event, data, textStatus, jqXHR ) { - * // code - * }); - * If the same 'handle' is used more than once, the data is not overwritten when the third argument is 'true'. - * Use wp.heartbeat.isQueued('handle') to see if any data is already queued for that handle. - * - * $param string handle Unique handle for the data. The handle is used in PHP to receive the data. - * $param mixed data The data to send. - * $param bool dont_overwrite Whether to overwrite existing data in the queue. - * $return bool Whether the data was queued or not. - */ - this.enqueue = function( handle, data, dont_overwrite ) { - if ( handle ) { - if ( queue.hasOwnProperty( handle ) && dont_overwrite ) - return false; - - queue[handle] = data; - return true; - } - return false; - }; - - /** - * Check if data with a particular handle is queued - * - * $param string handle The handle for the data - * $return mixed The data queued with that handle or null - */ - this.isQueued = function( handle ) { - return queue[handle]; - }; - }; - - $.extend( Heartbeat.prototype, { - tick: function( data, textStatus, jqXHR ) { - $(document).trigger( 'heartbeat-tick', [data, textStatus, jqXHR] ); - }, - error: function( jqXHR, textStatus, error ) { - $(document).trigger( 'heartbeat-error', [jqXHR, textStatus, error] ); - } - }); - - wp.heartbeat = new Heartbeat(); - -}(jQuery)); |