1 let doc, HIDDEN, VISIBILITY_CHANGE,
3 const clearHandles = Object.create( null );
5 function init( overrideDoc ) {
6 doc = overrideDoc || document;
8 if ( doc.hidden !== undefined ) {
10 VISIBILITY_CHANGE = 'visibilitychange';
11 } else if ( doc.mozHidden !== undefined ) {
13 VISIBILITY_CHANGE = 'mozvisibilitychange';
14 } else if ( doc.webkitHidden !== undefined ) {
15 HIDDEN = 'webkitHidden';
16 VISIBILITY_CHANGE = 'webkitvisibilitychange';
23 * A library similar to similar to setTimeout and clearTimeout,
24 * that pauses the time when page visibility is hidden.
26 * @exports mediawiki.visibleTimeout
31 * Generally similar to setTimeout, but pauses the time when page visibility is hidden.
33 * The provided function is invoked after the page has been cumulatively visible for the
34 * specified number of milliseconds.
36 * @param {Function} fn Callback
37 * @param {number} delay Time left, in milliseconds.
38 * @return {number} A positive integer value which identifies the timer. This
39 * value can be passed to clear() to cancel the timeout.
41 set: function ( fn, delay ) {
43 lastStartedAt = mw.now();
44 const visibleId = nextId++;
46 function clearHandle() {
47 if ( nativeId !== null ) {
48 clearTimeout( nativeId );
51 delete clearHandles[ visibleId ];
52 if ( VISIBILITY_CHANGE ) {
53 // Circular reference is intentional, chain starts after last definition.
54 doc.removeEventListener( VISIBILITY_CHANGE, visibilityCheck, false );
58 function onComplete() {
63 function visibilityCheck() {
66 if ( HIDDEN && doc[ HIDDEN ] ) {
67 if ( nativeId !== null ) {
68 // Calculate how long we were visible, and update the time left.
69 delay = Math.max( 0, delay - Math.max( 0, now - lastStartedAt ) );
73 // Unschedule the native timeout, will restart when visible again.
74 clearTimeout( nativeId );
79 // If we're visible, or if HIDDEN is not supported, then start
80 // (or resume) the timeout, which runs the user callback after one
81 // delay, unless the page becomes hidden first.
82 if ( nativeId === null ) {
84 nativeId = setTimeout( onComplete, delay );
89 clearHandles[ visibleId ] = clearHandle;
90 if ( VISIBILITY_CHANGE ) {
91 doc.addEventListener( VISIBILITY_CHANGE, visibilityCheck, false );
99 * Cancel a visible timeout previously established by calling set.
101 * Passing an invalid ID silently does nothing.
103 * @param {number} visibleId The identifier of the visible timeout you
104 * want to cancel. This ID was returned by the corresponding call to set().
106 clear: function ( visibleId ) {
107 if ( visibleId in clearHandles ) {
108 clearHandles[ visibleId ]();
113 if ( window.QUnit ) {
114 module.exports.init = init;