[ Index ] |
PHP Cross Reference of WordPress Trunk (Updated Daily) |
[Summary view] [Print] [Text view]
1 /** 2 * Heartbeat API 3 * 4 * Heartbeat is a simple server polling API that sends XHR requests to 5 * the server every 15 - 60 seconds and triggers events (or callbacks) upon 6 * receiving data. Currently these 'ticks' handle transports for post locking, 7 * login-expiration warnings, autosave, and related tasks while a user is logged in. 8 * 9 * Available PHP filters (in ajax-actions.php): 10 * - heartbeat_received 11 * - heartbeat_send 12 * - heartbeat_tick 13 * - heartbeat_nopriv_received 14 * - heartbeat_nopriv_send 15 * - heartbeat_nopriv_tick 16 * @see wp_ajax_nopriv_heartbeat(), wp_ajax_heartbeat() 17 * 18 * Custom jQuery events: 19 * - heartbeat-send 20 * - heartbeat-tick 21 * - heartbeat-error 22 * - heartbeat-connection-lost 23 * - heartbeat-connection-restored 24 * - heartbeat-nonces-expired 25 * 26 * @since 3.6.0 27 * @output wp-includes/js/heartbeat.js 28 */ 29 30 ( function( $, window, undefined ) { 31 32 /** 33 * Constructs the Heartbeat API. 34 * 35 * @since 3.6.0 36 * 37 * @return {Object} An instance of the Heartbeat class. 38 * @constructor 39 */ 40 var Heartbeat = function() { 41 var $document = $(document), 42 settings = { 43 // Suspend/resume. 44 suspend: false, 45 46 // Whether suspending is enabled. 47 suspendEnabled: true, 48 49 // Current screen id, defaults to the JS global 'pagenow' when present 50 // (in the admin) or 'front'. 51 screenId: '', 52 53 // XHR request URL, defaults to the JS global 'ajaxurl' when present. 54 url: '', 55 56 // Timestamp, start of the last connection request. 57 lastTick: 0, 58 59 // Container for the enqueued items. 60 queue: {}, 61 62 // Connect interval (in seconds). 63 mainInterval: 60, 64 65 // Used when the interval is set to 5 seconds temporarily. 66 tempInterval: 0, 67 68 // Used when the interval is reset. 69 originalInterval: 0, 70 71 // Used to limit the number of Ajax requests. 72 minimalInterval: 0, 73 74 // Used together with tempInterval. 75 countdown: 0, 76 77 // Whether a connection is currently in progress. 78 connecting: false, 79 80 // Whether a connection error occurred. 81 connectionError: false, 82 83 // Used to track non-critical errors. 84 errorcount: 0, 85 86 // Whether at least one connection has been completed successfully. 87 hasConnected: false, 88 89 // Whether the current browser window is in focus and the user is active. 90 hasFocus: true, 91 92 // Timestamp, last time the user was active. Checked every 30 seconds. 93 userActivity: 0, 94 95 // Flag whether events tracking user activity were set. 96 userActivityEvents: false, 97 98 // Timer that keeps track of how long a user has focus. 99 checkFocusTimer: 0, 100 101 // Timer that keeps track of how long needs to be waited before connecting to 102 // the server again. 103 beatTimer: 0 104 }; 105 106 /** 107 * Sets local variables and events, then starts the heartbeat. 108 * 109 * @since 3.8.0 110 * @access private 111 * 112 * @return {void} 113 */ 114 function initialize() { 115 var options, hidden, visibilityState, visibilitychange; 116 117 if ( typeof window.pagenow === 'string' ) { 118 settings.screenId = window.pagenow; 119 } 120 121 if ( typeof window.ajaxurl === 'string' ) { 122 settings.url = window.ajaxurl; 123 } 124 125 // Pull in options passed from PHP. 126 if ( typeof window.heartbeatSettings === 'object' ) { 127 options = window.heartbeatSettings; 128 129 // The XHR URL can be passed as option when window.ajaxurl is not set. 130 if ( ! settings.url && options.ajaxurl ) { 131 settings.url = options.ajaxurl; 132 } 133 134 /* 135 * The interval can be from 15 to 120 seconds and can be set temporarily to 5 seconds. 136 * It can be set in the initial options or changed later through JS and/or through PHP. 137 */ 138 if ( options.interval ) { 139 settings.mainInterval = options.interval; 140 141 if ( settings.mainInterval < 15 ) { 142 settings.mainInterval = 15; 143 } else if ( settings.mainInterval > 120 ) { 144 settings.mainInterval = 120; 145 } 146 } 147 148 /* 149 * Used to limit the number of Ajax requests. Overrides all other intervals 150 * if they are shorter. Needed for some hosts that cannot handle frequent requests 151 * and the user may exceed the allocated server CPU time, etc. The minimal interval 152 * can be up to 600 seconds, however setting it to longer than 120 seconds 153 * will limit or disable some of the functionality (like post locks). 154 * Once set at initialization, minimalInterval cannot be changed/overridden. 155 */ 156 if ( options.minimalInterval ) { 157 options.minimalInterval = parseInt( options.minimalInterval, 10 ); 158 settings.minimalInterval = options.minimalInterval > 0 && options.minimalInterval <= 600 ? options.minimalInterval : 0; 159 } 160 161 if ( settings.minimalInterval && settings.mainInterval < settings.minimalInterval ) { 162 settings.mainInterval = settings.minimalInterval; 163 } 164 165 // 'screenId' can be added from settings on the front end where the JS global 166 // 'pagenow' is not set. 167 if ( ! settings.screenId ) { 168 settings.screenId = options.screenId || 'front'; 169 } 170 171 if ( options.suspension === 'disable' ) { 172 settings.suspendEnabled = false; 173 } 174 } 175 176 // Convert to milliseconds. 177 settings.mainInterval = settings.mainInterval * 1000; 178 settings.originalInterval = settings.mainInterval; 179 if ( settings.minimalInterval ) { 180 settings.minimalInterval = settings.minimalInterval * 1000; 181 } 182 183 /* 184 * Switch the interval to 120 seconds by using the Page Visibility API. 185 * If the browser doesn't support it (Safari < 7, Android < 4.4, IE < 10), the 186 * interval will be increased to 120 seconds after 5 minutes of mouse and keyboard 187 * inactivity. 188 */ 189 if ( typeof document.hidden !== 'undefined' ) { 190 hidden = 'hidden'; 191 visibilitychange = 'visibilitychange'; 192 visibilityState = 'visibilityState'; 193 } else if ( typeof document.msHidden !== 'undefined' ) { // IE10. 194 hidden = 'msHidden'; 195 visibilitychange = 'msvisibilitychange'; 196 visibilityState = 'msVisibilityState'; 197 } else if ( typeof document.webkitHidden !== 'undefined' ) { // Android. 198 hidden = 'webkitHidden'; 199 visibilitychange = 'webkitvisibilitychange'; 200 visibilityState = 'webkitVisibilityState'; 201 } 202 203 if ( hidden ) { 204 if ( document[hidden] ) { 205 settings.hasFocus = false; 206 } 207 208 $document.on( visibilitychange + '.wp-heartbeat', function() { 209 if ( document[visibilityState] === 'hidden' ) { 210 blurred(); 211 window.clearInterval( settings.checkFocusTimer ); 212 } else { 213 focused(); 214 if ( document.hasFocus ) { 215 settings.checkFocusTimer = window.setInterval( checkFocus, 10000 ); 216 } 217 } 218 }); 219 } 220 221 // Use document.hasFocus() if available. 222 if ( document.hasFocus ) { 223 settings.checkFocusTimer = window.setInterval( checkFocus, 10000 ); 224 } 225 226 $(window).on( 'pagehide.wp-heartbeat', function() { 227 // Don't connect anymore. 228 suspend(); 229 230 // Abort the last request if not completed. 231 if ( settings.xhr && settings.xhr.readyState !== 4 ) { 232 settings.xhr.abort(); 233 } 234 }); 235 236 $(window).on( 237 'pageshow.wp-heartbeat', 238 /** 239 * Handles pageshow event, specifically when page navigation is restored from back/forward cache. 240 * 241 * @param {jQuery.Event} event 242 * @param {PageTransitionEvent} event.originalEvent 243 */ 244 function ( event ) { 245 if ( event.originalEvent.persisted ) { 246 /* 247 * When page navigation is stored via bfcache (Back/Forward Cache), consider this the same as 248 * if the user had just switched to the tab since the behavior is similar. 249 */ 250 focused(); 251 } 252 } 253 ); 254 255 // Check for user activity every 30 seconds. 256 window.setInterval( checkUserActivity, 30000 ); 257 258 // Start one tick after DOM ready. 259 $( function() { 260 settings.lastTick = time(); 261 scheduleNextTick(); 262 }); 263 } 264 265 /** 266 * Returns the current time according to the browser. 267 * 268 * @since 3.6.0 269 * @access private 270 * 271 * @return {number} Returns the current time. 272 */ 273 function time() { 274 return (new Date()).getTime(); 275 } 276 277 /** 278 * Checks if the iframe is from the same origin. 279 * 280 * @since 3.6.0 281 * @access private 282 * 283 * @return {boolean} Returns whether or not the iframe is from the same origin. 284 */ 285 function isLocalFrame( frame ) { 286 var origin, src = frame.src; 287 288 /* 289 * Need to compare strings as WebKit doesn't throw JS errors when iframes have 290 * different origin. It throws uncatchable exceptions. 291 */ 292 if ( src && /^https?:\/\//.test( src ) ) { 293 origin = window.location.origin ? window.location.origin : window.location.protocol + '//' + window.location.host; 294 295 if ( src.indexOf( origin ) !== 0 ) { 296 return false; 297 } 298 } 299 300 try { 301 if ( frame.contentWindow.document ) { 302 return true; 303 } 304 } catch(e) {} 305 306 return false; 307 } 308 309 /** 310 * Checks if the document's focus has changed. 311 * 312 * @since 4.1.0 313 * @access private 314 * 315 * @return {void} 316 */ 317 function checkFocus() { 318 if ( settings.hasFocus && ! document.hasFocus() ) { 319 blurred(); 320 } else if ( ! settings.hasFocus && document.hasFocus() ) { 321 focused(); 322 } 323 } 324 325 /** 326 * Sets error state and fires an event on XHR errors or timeout. 327 * 328 * @since 3.8.0 329 * @access private 330 * 331 * @param {string} error The error type passed from the XHR. 332 * @param {number} status The HTTP status code passed from jqXHR 333 * (200, 404, 500, etc.). 334 * 335 * @return {void} 336 */ 337 function setErrorState( error, status ) { 338 var trigger; 339 340 if ( error ) { 341 switch ( error ) { 342 case 'abort': 343 // Do nothing. 344 break; 345 case 'timeout': 346 // No response for 30 seconds. 347 trigger = true; 348 break; 349 case 'error': 350 if ( 503 === status && settings.hasConnected ) { 351 trigger = true; 352 break; 353 } 354 /* falls through */ 355 case 'parsererror': 356 case 'empty': 357 case 'unknown': 358 settings.errorcount++; 359 360 if ( settings.errorcount > 2 && settings.hasConnected ) { 361 trigger = true; 362 } 363 364 break; 365 } 366 367 if ( trigger && ! hasConnectionError() ) { 368 settings.connectionError = true; 369 $document.trigger( 'heartbeat-connection-lost', [error, status] ); 370 wp.hooks.doAction( 'heartbeat.connection-lost', error, status ); 371 } 372 } 373 } 374 375 /** 376 * Clears the error state and fires an event if there is a connection error. 377 * 378 * @since 3.8.0 379 * @access private 380 * 381 * @return {void} 382 */ 383 function clearErrorState() { 384 // Has connected successfully. 385 settings.hasConnected = true; 386 387 if ( hasConnectionError() ) { 388 settings.errorcount = 0; 389 settings.connectionError = false; 390 $document.trigger( 'heartbeat-connection-restored' ); 391 wp.hooks.doAction( 'heartbeat.connection-restored' ); 392 } 393 } 394 395 /** 396 * Gathers the data and connects to the server. 397 * 398 * @since 3.6.0 399 * @access private 400 * 401 * @return {void} 402 */ 403 function connect() { 404 var ajaxData, heartbeatData; 405 406 // If the connection to the server is slower than the interval, 407 // heartbeat connects as soon as the previous connection's response is received. 408 if ( settings.connecting || settings.suspend ) { 409 return; 410 } 411 412 settings.lastTick = time(); 413 414 heartbeatData = $.extend( {}, settings.queue ); 415 // Clear the data queue. Anything added after this point will be sent on the next tick. 416 settings.queue = {}; 417 418 $document.trigger( 'heartbeat-send', [ heartbeatData ] ); 419 wp.hooks.doAction( 'heartbeat.send', heartbeatData ); 420 421 ajaxData = { 422 data: heartbeatData, 423 interval: settings.tempInterval ? settings.tempInterval / 1000 : settings.mainInterval / 1000, 424 _nonce: typeof window.heartbeatSettings === 'object' ? window.heartbeatSettings.nonce : '', 425 action: 'heartbeat', 426 screen_id: settings.screenId, 427 has_focus: settings.hasFocus 428 }; 429 430 if ( 'customize' === settings.screenId ) { 431 ajaxData.wp_customize = 'on'; 432 } 433 434 settings.connecting = true; 435 settings.xhr = $.ajax({ 436 url: settings.url, 437 type: 'post', 438 timeout: 30000, // Throw an error if not completed after 30 seconds. 439 data: ajaxData, 440 dataType: 'json' 441 }).always( function() { 442 settings.connecting = false; 443 scheduleNextTick(); 444 }).done( function( response, textStatus, jqXHR ) { 445 var newInterval; 446 447 if ( ! response ) { 448 setErrorState( 'empty' ); 449 return; 450 } 451 452 clearErrorState(); 453 454 if ( response.nonces_expired ) { 455 $document.trigger( 'heartbeat-nonces-expired' ); 456 wp.hooks.doAction( 'heartbeat.nonces-expired' ); 457 } 458 459 // Change the interval from PHP. 460 if ( response.heartbeat_interval ) { 461 newInterval = response.heartbeat_interval; 462 delete response.heartbeat_interval; 463 } 464 465 // Update the heartbeat nonce if set. 466 if ( response.heartbeat_nonce && typeof window.heartbeatSettings === 'object' ) { 467 window.heartbeatSettings.nonce = response.heartbeat_nonce; 468 delete response.heartbeat_nonce; 469 } 470 471 // Update the Rest API nonce if set and wp-api loaded. 472 if ( response.rest_nonce && typeof window.wpApiSettings === 'object' ) { 473 window.wpApiSettings.nonce = response.rest_nonce; 474 // This nonce is required for api-fetch through heartbeat.tick. 475 // delete response.rest_nonce; 476 } 477 478 $document.trigger( 'heartbeat-tick', [response, textStatus, jqXHR] ); 479 wp.hooks.doAction( 'heartbeat.tick', response, textStatus, jqXHR ); 480 481 // Do this last. Can trigger the next XHR if connection time > 5 seconds and newInterval == 'fast'. 482 if ( newInterval ) { 483 interval( newInterval ); 484 } 485 }).fail( function( jqXHR, textStatus, error ) { 486 setErrorState( textStatus || 'unknown', jqXHR.status ); 487 $document.trigger( 'heartbeat-error', [jqXHR, textStatus, error] ); 488 wp.hooks.doAction( 'heartbeat.error', jqXHR, textStatus, error ); 489 }); 490 } 491 492 /** 493 * Schedules the next connection. 494 * 495 * Fires immediately if the connection time is longer than the interval. 496 * 497 * @since 3.8.0 498 * @access private 499 * 500 * @return {void} 501 */ 502 function scheduleNextTick() { 503 var delta = time() - settings.lastTick, 504 interval = settings.mainInterval; 505 506 if ( settings.suspend ) { 507 return; 508 } 509 510 if ( ! settings.hasFocus ) { 511 interval = 120000; // 120 seconds. Post locks expire after 150 seconds. 512 } else if ( settings.countdown > 0 && settings.tempInterval ) { 513 interval = settings.tempInterval; 514 settings.countdown--; 515 516 if ( settings.countdown < 1 ) { 517 settings.tempInterval = 0; 518 } 519 } 520 521 if ( settings.minimalInterval && interval < settings.minimalInterval ) { 522 interval = settings.minimalInterval; 523 } 524 525 window.clearTimeout( settings.beatTimer ); 526 527 if ( delta < interval ) { 528 settings.beatTimer = window.setTimeout( 529 function() { 530 connect(); 531 }, 532 interval - delta 533 ); 534 } else { 535 connect(); 536 } 537 } 538 539 /** 540 * Sets the internal state when the browser window becomes hidden or loses focus. 541 * 542 * @since 3.6.0 543 * @access private 544 * 545 * @return {void} 546 */ 547 function blurred() { 548 settings.hasFocus = false; 549 } 550 551 /** 552 * Sets the internal state when the browser window becomes visible or is in focus. 553 * 554 * @since 3.6.0 555 * @access private 556 * 557 * @return {void} 558 */ 559 function focused() { 560 settings.userActivity = time(); 561 562 // Resume if suspended. 563 resume(); 564 565 if ( ! settings.hasFocus ) { 566 settings.hasFocus = true; 567 scheduleNextTick(); 568 } 569 } 570 571 /** 572 * Suspends connecting. 573 */ 574 function suspend() { 575 settings.suspend = true; 576 } 577 578 /** 579 * Resumes connecting. 580 */ 581 function resume() { 582 settings.suspend = false; 583 } 584 585 /** 586 * Runs when the user becomes active after a period of inactivity. 587 * 588 * @since 3.6.0 589 * @access private 590 * 591 * @return {void} 592 */ 593 function userIsActive() { 594 settings.userActivityEvents = false; 595 $document.off( '.wp-heartbeat-active' ); 596 597 $('iframe').each( function( i, frame ) { 598 if ( isLocalFrame( frame ) ) { 599 $( frame.contentWindow ).off( '.wp-heartbeat-active' ); 600 } 601 }); 602 603 focused(); 604 } 605 606 /** 607 * Checks for user activity. 608 * 609 * Runs every 30 seconds. Sets 'hasFocus = true' if user is active and the window 610 * is in the background. Sets 'hasFocus = false' if the user has been inactive 611 * (no mouse or keyboard activity) for 5 minutes even when the window has focus. 612 * 613 * @since 3.8.0 614 * @access private 615 * 616 * @return {void} 617 */ 618 function checkUserActivity() { 619 var lastActive = settings.userActivity ? time() - settings.userActivity : 0; 620 621 // Throttle down when no mouse or keyboard activity for 5 minutes. 622 if ( lastActive > 300000 && settings.hasFocus ) { 623 blurred(); 624 } 625 626 // Suspend after 10 minutes of inactivity when suspending is enabled. 627 // Always suspend after 60 minutes of inactivity. This will release the post lock, etc. 628 if ( ( settings.suspendEnabled && lastActive > 600000 ) || lastActive > 3600000 ) { 629 suspend(); 630 } 631 632 if ( ! settings.userActivityEvents ) { 633 $document.on( 'mouseover.wp-heartbeat-active keyup.wp-heartbeat-active touchend.wp-heartbeat-active', function() { 634 userIsActive(); 635 }); 636 637 $('iframe').each( function( i, frame ) { 638 if ( isLocalFrame( frame ) ) { 639 $( frame.contentWindow ).on( 'mouseover.wp-heartbeat-active keyup.wp-heartbeat-active touchend.wp-heartbeat-active', function() { 640 userIsActive(); 641 }); 642 } 643 }); 644 645 settings.userActivityEvents = true; 646 } 647 } 648 649 // Public methods. 650 651 /** 652 * Checks whether the window (or any local iframe in it) has focus, or the user 653 * is active. 654 * 655 * @since 3.6.0 656 * @memberOf wp.heartbeat.prototype 657 * 658 * @return {boolean} True if the window or the user is active. 659 */ 660 function hasFocus() { 661 return settings.hasFocus; 662 } 663 664 /** 665 * Checks whether there is a connection error. 666 * 667 * @since 3.6.0 668 * 669 * @memberOf wp.heartbeat.prototype 670 * 671 * @return {boolean} True if a connection error was found. 672 */ 673 function hasConnectionError() { 674 return settings.connectionError; 675 } 676 677 /** 678 * Connects as soon as possible regardless of 'hasFocus' state. 679 * 680 * Will not open two concurrent connections. If a connection is in progress, 681 * will connect again immediately after the current connection completes. 682 * 683 * @since 3.8.0 684 * 685 * @memberOf wp.heartbeat.prototype 686 * 687 * @return {void} 688 */ 689 function connectNow() { 690 settings.lastTick = 0; 691 scheduleNextTick(); 692 } 693 694 /** 695 * Disables suspending. 696 * 697 * Should be used only when Heartbeat is performing critical tasks like 698 * autosave, post-locking, etc. Using this on many screens may overload 699 * the user's hosting account if several browser windows/tabs are left open 700 * for a long time. 701 * 702 * @since 3.8.0 703 * 704 * @memberOf wp.heartbeat.prototype 705 * 706 * @return {void} 707 */ 708 function disableSuspend() { 709 settings.suspendEnabled = false; 710 } 711 712 /** 713 * Gets/Sets the interval. 714 * 715 * When setting to 'fast' or 5, the interval is 5 seconds for the next 30 ticks 716 * (for 2 minutes and 30 seconds) by default. In this case the number of 'ticks' 717 * can be passed as second argument. If the window doesn't have focus, 718 * the interval slows down to 2 minutes. 719 * 720 * @since 3.6.0 721 * 722 * @memberOf wp.heartbeat.prototype 723 * 724 * @param {string|number} speed Interval: 'fast' or 5, 15, 30, 60, 120. 725 * Fast equals 5. 726 * @param {string} ticks Tells how many ticks before the interval reverts 727 * back. Used with speed = 'fast' or 5. 728 * 729 * @return {number} Current interval in seconds. 730 */ 731 function interval( speed, ticks ) { 732 var newInterval, 733 oldInterval = settings.tempInterval ? settings.tempInterval : settings.mainInterval; 734 735 if ( speed ) { 736 switch ( speed ) { 737 case 'fast': 738 case 5: 739 newInterval = 5000; 740 break; 741 case 15: 742 newInterval = 15000; 743 break; 744 case 30: 745 newInterval = 30000; 746 break; 747 case 60: 748 newInterval = 60000; 749 break; 750 case 120: 751 newInterval = 120000; 752 break; 753 case 'long-polling': 754 // Allow long polling (experimental). 755 settings.mainInterval = 0; 756 return 0; 757 default: 758 newInterval = settings.originalInterval; 759 } 760 761 if ( settings.minimalInterval && newInterval < settings.minimalInterval ) { 762 newInterval = settings.minimalInterval; 763 } 764 765 if ( 5000 === newInterval ) { 766 ticks = parseInt( ticks, 10 ) || 30; 767 ticks = ticks < 1 || ticks > 30 ? 30 : ticks; 768 769 settings.countdown = ticks; 770 settings.tempInterval = newInterval; 771 } else { 772 settings.countdown = 0; 773 settings.tempInterval = 0; 774 settings.mainInterval = newInterval; 775 } 776 777 /* 778 * Change the next connection time if new interval has been set. 779 * Will connect immediately if the time since the last connection 780 * is greater than the new interval. 781 */ 782 if ( newInterval !== oldInterval ) { 783 scheduleNextTick(); 784 } 785 } 786 787 return settings.tempInterval ? settings.tempInterval / 1000 : settings.mainInterval / 1000; 788 } 789 790 /** 791 * Enqueues data to send with the next XHR. 792 * 793 * As the data is send asynchronously, this function doesn't return the XHR 794 * response. To see the response, use the custom jQuery event 'heartbeat-tick' 795 * on the document, example: 796 * $(document).on( 'heartbeat-tick.myname', function( event, data, textStatus, jqXHR ) { 797 * // code 798 * }); 799 * If the same 'handle' is used more than once, the data is not overwritten when 800 * the third argument is 'true'. Use `wp.heartbeat.isQueued('handle')` to see if 801 * any data is already queued for that handle. 802 * 803 * @since 3.6.0 804 * 805 * @memberOf wp.heartbeat.prototype 806 * 807 * @param {string} handle Unique handle for the data, used in PHP to 808 * receive the data. 809 * @param {*} data The data to send. 810 * @param {boolean} noOverwrite Whether to overwrite existing data in the queue. 811 * 812 * @return {boolean} True if the data was queued. 813 */ 814 function enqueue( handle, data, noOverwrite ) { 815 if ( handle ) { 816 if ( noOverwrite && this.isQueued( handle ) ) { 817 return false; 818 } 819 820 settings.queue[handle] = data; 821 return true; 822 } 823 return false; 824 } 825 826 /** 827 * Checks if data with a particular handle is queued. 828 * 829 * @since 3.6.0 830 * 831 * @param {string} handle The handle for the data. 832 * 833 * @return {boolean} True if the data is queued with this handle. 834 */ 835 function isQueued( handle ) { 836 if ( handle ) { 837 return settings.queue.hasOwnProperty( handle ); 838 } 839 } 840 841 /** 842 * Removes data with a particular handle from the queue. 843 * 844 * @since 3.7.0 845 * 846 * @memberOf wp.heartbeat.prototype 847 * 848 * @param {string} handle The handle for the data. 849 * 850 * @return {void} 851 */ 852 function dequeue( handle ) { 853 if ( handle ) { 854 delete settings.queue[handle]; 855 } 856 } 857 858 /** 859 * Gets data that was enqueued with a particular handle. 860 * 861 * @since 3.7.0 862 * 863 * @memberOf wp.heartbeat.prototype 864 * 865 * @param {string} handle The handle for the data. 866 * 867 * @return {*} The data or undefined. 868 */ 869 function getQueuedItem( handle ) { 870 if ( handle ) { 871 return this.isQueued( handle ) ? settings.queue[handle] : undefined; 872 } 873 } 874 875 initialize(); 876 877 // Expose public methods. 878 return { 879 hasFocus: hasFocus, 880 connectNow: connectNow, 881 disableSuspend: disableSuspend, 882 interval: interval, 883 hasConnectionError: hasConnectionError, 884 enqueue: enqueue, 885 dequeue: dequeue, 886 isQueued: isQueued, 887 getQueuedItem: getQueuedItem 888 }; 889 }; 890 891 /** 892 * Ensure the global `wp` object exists. 893 * 894 * @namespace wp 895 */ 896 window.wp = window.wp || {}; 897 898 /** 899 * Contains the Heartbeat API. 900 * 901 * @namespace wp.heartbeat 902 * @type {Heartbeat} 903 */ 904 window.wp.heartbeat = new Heartbeat(); 905 906 }( jQuery, window ));
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated : Tue Mar 19 08:20:01 2024 | Cross-referenced by PHPXref |