diff options
Diffstat (limited to 'www/wiki/resources/src/mediawiki/mediawiki.visibleTimeout.js')
-rw-r--r-- | www/wiki/resources/src/mediawiki/mediawiki.visibleTimeout.js | 114 |
1 files changed, 114 insertions, 0 deletions
diff --git a/www/wiki/resources/src/mediawiki/mediawiki.visibleTimeout.js b/www/wiki/resources/src/mediawiki/mediawiki.visibleTimeout.js new file mode 100644 index 00000000..e2bbd683 --- /dev/null +++ b/www/wiki/resources/src/mediawiki/mediawiki.visibleTimeout.js @@ -0,0 +1,114 @@ +( function ( mw, document ) { + var hidden, visibilityChange, + nextVisibleTimeoutId = 0, + activeTimeouts = {}, + init = function ( overrideDoc ) { + if ( overrideDoc !== undefined ) { + document = overrideDoc; + } + + if ( document.hidden !== undefined ) { + hidden = 'hidden'; + visibilityChange = 'visibilitychange'; + } else if ( document.mozHidden !== undefined ) { + hidden = 'mozHidden'; + visibilityChange = 'mozvisibilitychange'; + } else if ( document.msHidden !== undefined ) { + hidden = 'msHidden'; + visibilityChange = 'msvisibilitychange'; + } else if ( document.webkitHidden !== undefined ) { + hidden = 'webkitHidden'; + visibilityChange = 'webkitvisibilitychange'; + } + }; + + init(); + + /** + * @class mw.visibleTimeout + * @singleton + */ + module.exports = { + /** + * Generally similar to setTimeout, but turns itself on/off on page + * visibility changes. The passed function fires after the page has been + * cumulatively visible for the specified number of ms. + * + * @param {Function} fn The action to execute after visible timeout has expired. + * @param {number} delay The number of ms the page should be visible before + * calling fn. + * @return {number} A positive integer value which identifies the timer. This + * value can be passed to clearVisibleTimeout() to cancel the timeout. + */ + set: function ( fn, delay ) { + var handleVisibilityChange, + timeoutId = null, + visibleTimeoutId = nextVisibleTimeoutId++, + lastStartedAt = mw.now(), + clearVisibleTimeout = function () { + if ( timeoutId !== null ) { + clearTimeout( timeoutId ); + timeoutId = null; + } + delete activeTimeouts[ visibleTimeoutId ]; + if ( hidden !== undefined ) { + document.removeEventListener( visibilityChange, handleVisibilityChange, false ); + } + }, + onComplete = function () { + clearVisibleTimeout(); + fn(); + }; + + handleVisibilityChange = function () { + var now = mw.now(); + + if ( document[ hidden ] ) { + // pause timeout if running + if ( timeoutId !== null ) { + delay = Math.max( 0, delay - Math.max( 0, now - lastStartedAt ) ); + if ( delay === 0 ) { + onComplete(); + } else { + clearTimeout( timeoutId ); + timeoutId = null; + } + } + } else { + // resume timeout if not running + if ( timeoutId === null ) { + lastStartedAt = now; + timeoutId = setTimeout( onComplete, delay ); + } + } + }; + + activeTimeouts[ visibleTimeoutId ] = clearVisibleTimeout; + if ( hidden !== undefined ) { + document.addEventListener( visibilityChange, handleVisibilityChange, false ); + } + handleVisibilityChange(); + + return visibleTimeoutId; + }, + + /** + * Cancel a visible timeout previously established by calling set. + * Passing an invalid ID silently does nothing. + * + * @param {number} visibleTimeoutId The identifier of the visible + * timeout you want to cancel. This ID was returned by the + * corresponding call to set(). + */ + clear: function ( visibleTimeoutId ) { + if ( activeTimeouts.hasOwnProperty( visibleTimeoutId ) ) { + activeTimeouts[ visibleTimeoutId ](); + } + } + }; + + if ( window.QUnit ) { + module.exports.setDocument = init; + } + +}( mediaWiki, document ) ); |