SECURITY: resources: Patch jQuery 3.3.1 for CVE-2019-11358
[lhc/web/wiklou.git] / resources / src / mediawiki.visibleTimeout.js
1 ( function () {
2 var hidden, visibilityChange,
3 nextVisibleTimeoutId = 0,
4 activeTimeouts = {},
5 document = window.document,
6 init = function ( overrideDoc ) {
7 if ( overrideDoc !== undefined ) {
8 document = overrideDoc;
9 }
10
11 if ( document.hidden !== undefined ) {
12 hidden = 'hidden';
13 visibilityChange = 'visibilitychange';
14 } else if ( document.mozHidden !== undefined ) {
15 hidden = 'mozHidden';
16 visibilityChange = 'mozvisibilitychange';
17 } else if ( document.msHidden !== undefined ) {
18 hidden = 'msHidden';
19 visibilityChange = 'msvisibilitychange';
20 } else if ( document.webkitHidden !== undefined ) {
21 hidden = 'webkitHidden';
22 visibilityChange = 'webkitvisibilitychange';
23 }
24 };
25
26 init();
27
28 /**
29 * @class mw.visibleTimeout
30 * @singleton
31 */
32 module.exports = {
33 /**
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.
37 *
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
40 * calling fn.
41 * @return {number} A positive integer value which identifies the timer. This
42 * value can be passed to clearVisibleTimeout() to cancel the timeout.
43 */
44 set: function ( fn, delay ) {
45 var handleVisibilityChange,
46 timeoutId = null,
47 visibleTimeoutId = nextVisibleTimeoutId++,
48 lastStartedAt = mw.now(),
49 clearVisibleTimeout = function () {
50 if ( timeoutId !== null ) {
51 clearTimeout( timeoutId );
52 timeoutId = null;
53 }
54 delete activeTimeouts[ visibleTimeoutId ];
55 if ( hidden !== undefined ) {
56 document.removeEventListener( visibilityChange, handleVisibilityChange, false );
57 }
58 },
59 onComplete = function () {
60 clearVisibleTimeout();
61 fn();
62 };
63
64 handleVisibilityChange = function () {
65 var now = mw.now();
66
67 if ( document[ hidden ] ) {
68 // pause timeout if running
69 if ( timeoutId !== null ) {
70 delay = Math.max( 0, delay - Math.max( 0, now - lastStartedAt ) );
71 if ( delay === 0 ) {
72 onComplete();
73 } else {
74 clearTimeout( timeoutId );
75 timeoutId = null;
76 }
77 }
78 } else {
79 // resume timeout if not running
80 if ( timeoutId === null ) {
81 lastStartedAt = now;
82 timeoutId = setTimeout( onComplete, delay );
83 }
84 }
85 };
86
87 activeTimeouts[ visibleTimeoutId ] = clearVisibleTimeout;
88 if ( hidden !== undefined ) {
89 document.addEventListener( visibilityChange, handleVisibilityChange, false );
90 }
91 handleVisibilityChange();
92
93 return visibleTimeoutId;
94 },
95
96 /**
97 * Cancel a visible timeout previously established by calling set.
98 * Passing an invalid ID silently does nothing.
99 *
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().
103 */
104 clear: function ( visibleTimeoutId ) {
105 if ( Object.prototype.hasOwnProperty.call( activeTimeouts, visibleTimeoutId ) ) {
106 activeTimeouts[ visibleTimeoutId ]();
107 }
108 }
109 };
110
111 if ( window.QUnit ) {
112 module.exports.setDocument = init;
113 }
114
115 }() );