2 var hidden
, visibilityChange
,
3 nextVisibleTimeoutId
= 0,
5 document
= window
.document
,
6 init = function ( overrideDoc
) {
7 if ( overrideDoc
!== undefined ) {
8 document
= overrideDoc
;
11 if ( document
.hidden
!== undefined ) {
13 visibilityChange
= 'visibilitychange';
14 } else if ( document
.mozHidden
!== undefined ) {
16 visibilityChange
= 'mozvisibilitychange';
17 } else if ( document
.msHidden
!== undefined ) {
19 visibilityChange
= 'msvisibilitychange';
20 } else if ( document
.webkitHidden
!== undefined ) {
21 hidden
= 'webkitHidden';
22 visibilityChange
= 'webkitvisibilitychange';
29 * @class mw.visibleTimeout
34 * Generally similar to setTimeout, but turns itself on/off on page
35 * visibility changes. The passed function fires after the page has been
36 * cumulatively visible for the specified number of ms.
38 * @param {Function} fn The action to execute after visible timeout has expired.
39 * @param {number} delay The number of ms the page should be visible before
41 * @return {number} A positive integer value which identifies the timer. This
42 * value can be passed to clearVisibleTimeout() to cancel the timeout.
44 set: function ( fn
, delay
) {
45 var handleVisibilityChange
,
47 visibleTimeoutId
= nextVisibleTimeoutId
++,
48 lastStartedAt
= mw
.now(),
49 clearVisibleTimeout = function () {
50 if ( timeoutId
!== null ) {
51 clearTimeout( timeoutId
);
54 delete activeTimeouts
[ visibleTimeoutId
];
55 if ( hidden
!== undefined ) {
56 document
.removeEventListener( visibilityChange
, handleVisibilityChange
, false );
59 onComplete = function () {
60 clearVisibleTimeout();
64 handleVisibilityChange = function () {
67 if ( document
[ hidden
] ) {
68 // pause timeout if running
69 if ( timeoutId
!== null ) {
70 delay
= Math
.max( 0, delay
- Math
.max( 0, now
- lastStartedAt
) );
74 clearTimeout( timeoutId
);
79 // resume timeout if not running
80 if ( timeoutId
=== null ) {
82 timeoutId
= setTimeout( onComplete
, delay
);
87 activeTimeouts
[ visibleTimeoutId
] = clearVisibleTimeout
;
88 if ( hidden
!== undefined ) {
89 document
.addEventListener( visibilityChange
, handleVisibilityChange
, false );
91 handleVisibilityChange();
93 return visibleTimeoutId
;
97 * Cancel a visible timeout previously established by calling set.
98 * Passing an invalid ID silently does nothing.
100 * @param {number} visibleTimeoutId The identifier of the visible
101 * timeout you want to cancel. This ID was returned by the
102 * corresponding call to set().
104 clear: function ( visibleTimeoutId
) {
105 if ( Object
.prototype.hasOwnProperty
.call( activeTimeouts
, visibleTimeoutId
) ) {
106 activeTimeouts
[ visibleTimeoutId
]();
111 if ( window
.QUnit
) {
112 module
.exports
.setDocument
= init
;