visibilityjs 0.4.5 → 0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/ChangeLog +5 -0
- data/README.md +19 -0
- data/lib/assets/javascripts/visibility.core.js +248 -0
- data/lib/assets/javascripts/visibility.fallback.js +2 -2
- data/lib/assets/javascripts/visibility.js +220 -188
- data/lib/assets/javascripts/visibility.timers.js +199 -0
- metadata +4 -2
data/ChangeLog
CHANGED
@@ -1,3 +1,8 @@
|
|
1
|
+
== 0.5 (SCORE, communication)
|
2
|
+
* Split library to core and timers modules.
|
3
|
+
* Allow to unbind change listener.
|
4
|
+
* Use common logic in change(), afterPrerendering() and onVisible().
|
5
|
+
|
1
6
|
== 0.4.5 (Pioneer 3, closer)
|
2
7
|
* Fix gem assets directory.
|
3
8
|
* Update development dependencies.
|
data/README.md
CHANGED
@@ -219,6 +219,18 @@ Visibility.change(function (e, state) {
|
|
219
219
|
|
220
220
|
## Installing
|
221
221
|
|
222
|
+
### Packages
|
223
|
+
|
224
|
+
Visibility.js shipped with 4 files:
|
225
|
+
|
226
|
+
* `visibility.core` – core module.
|
227
|
+
* `visibility.timers` – `every` and `stop` methods to set `setTimeout` depend
|
228
|
+
on visibility state.
|
229
|
+
* `visibility` – `visibility.core` and `visibility.timers` together.
|
230
|
+
* `visibility.fallback` – fallback for browser without Page Visibility API.
|
231
|
+
It use document `focus`/`blur` events, so it say, that document in hidden,
|
232
|
+
when browser just lose focus.
|
233
|
+
|
222
234
|
### Ruby on Rails
|
223
235
|
|
224
236
|
For Ruby on Rails you can use gem for Assets Pipeline.
|
@@ -241,6 +253,13 @@ For Ruby on Rails you can use gem for Assets Pipeline.
|
|
241
253
|
#= require visibility
|
242
254
|
```
|
243
255
|
|
256
|
+
If you didn’t use `every` method, you can reduce library size, by including
|
257
|
+
only core module:
|
258
|
+
|
259
|
+
```coffee
|
260
|
+
#= require visibility.core
|
261
|
+
```
|
262
|
+
|
244
263
|
### Other
|
245
264
|
|
246
265
|
If you don’t use any assets packaging manager (it’s very bad idea), you can use
|
@@ -0,0 +1,248 @@
|
|
1
|
+
/*
|
2
|
+
* Copyright 2011 Andrey “A.I.” Sitnik <andrey@sitnik.ru>,
|
3
|
+
* sponsored by Evil Martians.
|
4
|
+
*
|
5
|
+
* This program is free software: you can redistribute it and/or modify
|
6
|
+
* it under the terms of the GNU Lesser General Public License as published by
|
7
|
+
* the Free Software Foundation, either version 3 of the License, or
|
8
|
+
* (at your option) any later version.
|
9
|
+
*
|
10
|
+
* This program is distributed in the hope that it will be useful,
|
11
|
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
12
|
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
13
|
+
* GNU Lesser General Public License for more details.
|
14
|
+
*
|
15
|
+
* You should have received a copy of the GNU Lesser General Public License
|
16
|
+
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
17
|
+
*/
|
18
|
+
|
19
|
+
;(function () {
|
20
|
+
"use strict";
|
21
|
+
|
22
|
+
var defined = function (variable) {
|
23
|
+
return ('undefined' != typeof(variable));
|
24
|
+
};
|
25
|
+
|
26
|
+
// Visibility.js allow you to know, that your web page is in the background
|
27
|
+
// tab and thus not visible to the user. This library is wrap under
|
28
|
+
// Page Visibility API. It fix problems with different vendor prefixes and
|
29
|
+
// add high-level useful functions.
|
30
|
+
window.Visibility = {
|
31
|
+
|
32
|
+
// Call callback only when page become to visible for user or
|
33
|
+
// call it now if page is visible now or Page Visibility API
|
34
|
+
// doesn’t supported.
|
35
|
+
//
|
36
|
+
// Return true if callback if called now.
|
37
|
+
//
|
38
|
+
// Visibility.onVisible(function () {
|
39
|
+
// Notification.animateNotice("Hello");
|
40
|
+
// });
|
41
|
+
onVisible: function (callback) {
|
42
|
+
if ( !this.isSupported() || !this.hidden() ) {
|
43
|
+
callback();
|
44
|
+
return true;
|
45
|
+
}
|
46
|
+
|
47
|
+
var listener = this.change(function (e, state) {
|
48
|
+
if ( !Visibility.hidden() ) {
|
49
|
+
Visibility.unbind(listener);
|
50
|
+
callback();
|
51
|
+
}
|
52
|
+
});
|
53
|
+
},
|
54
|
+
|
55
|
+
// Call callback when visibility will be changed. First argument for
|
56
|
+
// callback will be original event object, second will be visibility
|
57
|
+
// state name.
|
58
|
+
//
|
59
|
+
// Return listener ID to unbind listener by `unbind` method.
|
60
|
+
//
|
61
|
+
// If Page Visibility API doesn’t supported method will be return false
|
62
|
+
// and callback never will be called.
|
63
|
+
//
|
64
|
+
// Visibility.change(function(e, state) {
|
65
|
+
// Statistics.visibilityChange(state);
|
66
|
+
// });
|
67
|
+
//
|
68
|
+
// It is just proxy to `visibilitychange` event, but use vendor prefix.
|
69
|
+
change: function (callback) {
|
70
|
+
if ( !this.isSupported() ) {
|
71
|
+
return false;
|
72
|
+
}
|
73
|
+
this._lastCallback += 1;
|
74
|
+
var number = this._lastCallback;
|
75
|
+
this._callbacks[number] = callback;
|
76
|
+
this._setListener();
|
77
|
+
return number;
|
78
|
+
},
|
79
|
+
|
80
|
+
// Remove `change` listener by it ID.
|
81
|
+
//
|
82
|
+
// var id = Visibility.change(function(e, state) {
|
83
|
+
// firstChangeCallback();
|
84
|
+
// Visibility.unbind(id);
|
85
|
+
// });
|
86
|
+
unbind: function (id) {
|
87
|
+
delete this._callbacks[id];
|
88
|
+
},
|
89
|
+
|
90
|
+
// Call `callback` in any state, expect “prerender”. If current state
|
91
|
+
// is “prerender” it will wait until state will be changed.
|
92
|
+
// If Page Visibility API doesn’t supported, it will call `callback`
|
93
|
+
// immediately.
|
94
|
+
//
|
95
|
+
// Visibility.afterPrerendering(function () {
|
96
|
+
// Statistics.countVisitor();
|
97
|
+
// });
|
98
|
+
afterPrerendering: function (callback) {
|
99
|
+
if ( !this.isSupported() || 'prerender' != this.state() ) {
|
100
|
+
callback();
|
101
|
+
return true;
|
102
|
+
}
|
103
|
+
|
104
|
+
var listener = this.change(function (e, state) {
|
105
|
+
if ( 'prerender' != state ) {
|
106
|
+
Visibility.unbind(listener);
|
107
|
+
callback();
|
108
|
+
}
|
109
|
+
});
|
110
|
+
},
|
111
|
+
|
112
|
+
// Return true if page now isn’t visible to user.
|
113
|
+
//
|
114
|
+
// if ( !Visibility.hidden() ) {
|
115
|
+
// VideoPlayer.play();
|
116
|
+
// }
|
117
|
+
//
|
118
|
+
// It is just proxy to `document.hidden`, but use vendor prefix.
|
119
|
+
hidden: function () {
|
120
|
+
return this._prop('hidden', false);
|
121
|
+
},
|
122
|
+
|
123
|
+
// Return visibility state: 'visible', 'hidden' or 'prerender'.
|
124
|
+
//
|
125
|
+
// if ( 'prerender' == Visibility.state() ) {
|
126
|
+
// Statistics.pageIsPrerendering();
|
127
|
+
// }
|
128
|
+
//
|
129
|
+
// Don’t use `Visibility.state()` to detect, is page visible, because
|
130
|
+
// visibility states can extend in next API versions.
|
131
|
+
// Use more simpler and general `Visibility.hidden()` for this cases.
|
132
|
+
//
|
133
|
+
// It is just proxy to `document.visibilityState`, but use
|
134
|
+
// vendor prefix.
|
135
|
+
state: function () {
|
136
|
+
return this._prop('visibilityState', 'visible');
|
137
|
+
},
|
138
|
+
|
139
|
+
// Return true if browser support Page Visibility API.
|
140
|
+
//
|
141
|
+
// if ( Visibility.isSupported() ) {
|
142
|
+
// Statistics.startTrackingVisibility();
|
143
|
+
// Visibility.change(function(e, state)) {
|
144
|
+
// Statistics.trackVisibility(state);
|
145
|
+
// });
|
146
|
+
// }
|
147
|
+
isSupported: function () {
|
148
|
+
return defined(this._prefix());
|
149
|
+
},
|
150
|
+
|
151
|
+
// Link to document object to change it in tests.
|
152
|
+
_doc: window.document,
|
153
|
+
|
154
|
+
// Vendor prefixes to create event and properties names.
|
155
|
+
_prefixes: ['webkit', 'moz', 'o', 'ms'],
|
156
|
+
|
157
|
+
// Vendor prefix cached by `_prefix` function.
|
158
|
+
_chechedPrefix: null,
|
159
|
+
|
160
|
+
// Is listener for `visibilitychange` event is already added
|
161
|
+
// by `_setListener` method.
|
162
|
+
_listening: false,
|
163
|
+
|
164
|
+
// Last timer number.
|
165
|
+
_lastCallback: -1,
|
166
|
+
|
167
|
+
// Callbacks from `change` method, that wait visibility changes.
|
168
|
+
_callbacks: { },
|
169
|
+
|
170
|
+
// Variable to check hidden-visible state changes.
|
171
|
+
_hiddenBefore: false,
|
172
|
+
|
173
|
+
// Initialize variables on page loading.
|
174
|
+
_init: function () {
|
175
|
+
this._hiddenBefore = this.hidden();
|
176
|
+
},
|
177
|
+
|
178
|
+
// Detect vendor prefix and return it.
|
179
|
+
_prefix: function () {
|
180
|
+
if ( null !== this._chechedPrefix ) {
|
181
|
+
return this._chechedPrefix;
|
182
|
+
}
|
183
|
+
if ( defined(this._doc.visibilityState) ) {
|
184
|
+
return this._chechedPrefix = '';
|
185
|
+
}
|
186
|
+
var name;
|
187
|
+
for ( var i = 0; i < this._prefixes.length; i++ ) {
|
188
|
+
name = this._prefixes[i] + 'VisibilityState';
|
189
|
+
if ( defined(this._doc[name]) ) {
|
190
|
+
return this._chechedPrefix = this._prefixes[i];
|
191
|
+
}
|
192
|
+
}
|
193
|
+
},
|
194
|
+
|
195
|
+
// Return property name with vendor prefix.
|
196
|
+
_name: function (name) {
|
197
|
+
var prefix = this._prefix();
|
198
|
+
if ( '' == prefix ) {
|
199
|
+
return name;
|
200
|
+
} else {
|
201
|
+
return prefix +
|
202
|
+
name.substr(0, 1).toUpperCase() + name.substr(1);
|
203
|
+
}
|
204
|
+
},
|
205
|
+
|
206
|
+
// Return document’s property value with name with vendor prefix.
|
207
|
+
// If API is not support, it will retun `unsupported` value.
|
208
|
+
_prop: function (name, unsupported) {
|
209
|
+
if ( !this.isSupported() ) {
|
210
|
+
return unsupported;
|
211
|
+
}
|
212
|
+
return this._doc[this._name(name)];
|
213
|
+
},
|
214
|
+
|
215
|
+
// Listener for `visibilitychange` event.
|
216
|
+
_onChange: function(event) {
|
217
|
+
var state = this.state();
|
218
|
+
|
219
|
+
for ( var i in this._callbacks ) {
|
220
|
+
this._callbacks[i].call(this._doc, event, state);
|
221
|
+
}
|
222
|
+
|
223
|
+
this._hiddenBefore = this.hidden();
|
224
|
+
},
|
225
|
+
|
226
|
+
// Set listener for `visibilitychange` event.
|
227
|
+
_setListener: function () {
|
228
|
+
if ( this._listening ) {
|
229
|
+
return;
|
230
|
+
}
|
231
|
+
var event = this._prefix() + 'visibilitychange';
|
232
|
+
var listener = function () {
|
233
|
+
Visibility._onChange.apply(Visibility, arguments);
|
234
|
+
};
|
235
|
+
if ( this._doc.addEventListener ) {
|
236
|
+
this._doc.addEventListener(event, listener, false);
|
237
|
+
} else {
|
238
|
+
this._doc.attachEvent(event, listener);
|
239
|
+
}
|
240
|
+
this._listening = true;
|
241
|
+
this._hiddenBefore = this.hidden();
|
242
|
+
}
|
243
|
+
|
244
|
+
};
|
245
|
+
|
246
|
+
Visibility._init();
|
247
|
+
|
248
|
+
})();
|
@@ -26,7 +26,7 @@
|
|
26
26
|
//
|
27
27
|
// For Firefox 5–9 it will be better to use MozVisibility hack without
|
28
28
|
// this issue. See <https://github.com/private-face/mozvisibility>.
|
29
|
-
;(function() {
|
29
|
+
;(function () {
|
30
30
|
"use strict";
|
31
31
|
|
32
32
|
if ( document.visibilityState || document.webkitVisibilityState ||
|
@@ -49,7 +49,7 @@
|
|
49
49
|
document.dispatchEvent(event);
|
50
50
|
} else {
|
51
51
|
if ( typeof(Visibility) == 'object' ) {
|
52
|
-
Visibility.
|
52
|
+
Visibility._onChange.call(Visibility, { })
|
53
53
|
}
|
54
54
|
}
|
55
55
|
}
|
@@ -16,10 +16,10 @@
|
|
16
16
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
17
17
|
*/
|
18
18
|
|
19
|
-
;(function() {
|
19
|
+
;(function () {
|
20
20
|
"use strict";
|
21
21
|
|
22
|
-
var defined = function(variable) {
|
22
|
+
var defined = function (variable) {
|
23
23
|
return ('undefined' != typeof(variable));
|
24
24
|
};
|
25
25
|
|
@@ -35,7 +35,7 @@
|
|
35
35
|
//
|
36
36
|
// Return true if callback if called now.
|
37
37
|
//
|
38
|
-
// Visibility.onVisible(function() {
|
38
|
+
// Visibility.onVisible(function () {
|
39
39
|
// Notification.animateNotice("Hello");
|
40
40
|
// });
|
41
41
|
onVisible: function (callback) {
|
@@ -43,84 +43,21 @@
|
|
43
43
|
callback();
|
44
44
|
return true;
|
45
45
|
}
|
46
|
-
this._onVisibleCallbacks.push(callback);
|
47
|
-
this._setListener();
|
48
|
-
},
|
49
46
|
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
// });
|
56
|
-
//
|
57
|
-
// You can skip `hiddenInterval` and callback will be called only if
|
58
|
-
// page is visible.
|
59
|
-
//
|
60
|
-
// Visibility.every(1000, function() {
|
61
|
-
// updateCountdown();
|
62
|
-
// });
|
63
|
-
//
|
64
|
-
// It is analog of `setInterval(callback, interval)` but use visibility
|
65
|
-
// state.
|
66
|
-
//
|
67
|
-
// It return timer ID, that you can use in `Visibility.stop(id)` to stop
|
68
|
-
// timer (`clearInterval` analog).
|
69
|
-
// Warning: timer ID is different from intervalID from `setInterval`,
|
70
|
-
// so don’t use it in `clearInterval`.
|
71
|
-
//
|
72
|
-
// On change state from hidden to visible timers will be execute.
|
73
|
-
//
|
74
|
-
// If you include jQuery Chrono plugin before Visibility.js, you could
|
75
|
-
// use Chrono’s syntax sugar in interval arguments:
|
76
|
-
//
|
77
|
-
// Visibility.every('second', function() {
|
78
|
-
// updateCountdown();
|
79
|
-
// });
|
80
|
-
// Visibility.every('1 minute', '5 minutes', function() {
|
81
|
-
// checkNewMails();
|
82
|
-
// });
|
83
|
-
every: function (interval, hiddenInterval, callback) {
|
84
|
-
if ( !defined(callback) ) {
|
85
|
-
callback = hiddenInterval;
|
86
|
-
hiddenInterval = null;
|
87
|
-
}
|
88
|
-
this._lastTimer += 1;
|
89
|
-
var number = this._lastTimer;
|
90
|
-
this._timers[number] = ({
|
91
|
-
interval: interval,
|
92
|
-
hiddenInterval: hiddenInterval,
|
93
|
-
callback: callback
|
47
|
+
var listener = this.change(function (e, state) {
|
48
|
+
if ( !Visibility.hidden() ) {
|
49
|
+
Visibility.unbind(listener);
|
50
|
+
callback();
|
51
|
+
}
|
94
52
|
});
|
95
|
-
this._runTimer(number, false);
|
96
|
-
if ( this.isSupported() ) {
|
97
|
-
this._setListener();
|
98
|
-
}
|
99
|
-
return number;
|
100
|
-
},
|
101
|
-
|
102
|
-
// Stop timer from `every` method by it ID (`every` method return it).
|
103
|
-
//
|
104
|
-
// slideshow = Visibility.every(5 * 1000, function() {
|
105
|
-
// changeSlide();
|
106
|
-
// });
|
107
|
-
// $('.stopSlideshow').click(function() {
|
108
|
-
// Visibility.stop(slideshow);
|
109
|
-
// });
|
110
|
-
stop: function(id) {
|
111
|
-
var timer = this._timers[id]
|
112
|
-
if ( !defined(timer) ) {
|
113
|
-
return false;
|
114
|
-
}
|
115
|
-
this._stopTimer(id);
|
116
|
-
delete this._timers[id];
|
117
|
-
return timer;
|
118
53
|
},
|
119
54
|
|
120
55
|
// Call callback when visibility will be changed. First argument for
|
121
56
|
// callback will be original event object, second will be visibility
|
122
57
|
// state name.
|
123
58
|
//
|
59
|
+
// Return listener ID to unbind listener by `unbind` method.
|
60
|
+
//
|
124
61
|
// If Page Visibility API doesn’t supported method will be return false
|
125
62
|
// and callback never will be called.
|
126
63
|
//
|
@@ -133,9 +70,21 @@
|
|
133
70
|
if ( !this.isSupported() ) {
|
134
71
|
return false;
|
135
72
|
}
|
136
|
-
this.
|
73
|
+
this._lastCallback += 1;
|
74
|
+
var number = this._lastCallback;
|
75
|
+
this._callbacks[number] = callback;
|
137
76
|
this._setListener();
|
138
|
-
return
|
77
|
+
return number;
|
78
|
+
},
|
79
|
+
|
80
|
+
// Remove `change` listener by it ID.
|
81
|
+
//
|
82
|
+
// var id = Visibility.change(function(e, state) {
|
83
|
+
// firstChangeCallback();
|
84
|
+
// Visibility.unbind(id);
|
85
|
+
// });
|
86
|
+
unbind: function (id) {
|
87
|
+
delete this._callbacks[id];
|
139
88
|
},
|
140
89
|
|
141
90
|
// Call `callback` in any state, expect “prerender”. If current state
|
@@ -151,8 +100,13 @@
|
|
151
100
|
callback();
|
152
101
|
return true;
|
153
102
|
}
|
154
|
-
|
155
|
-
this.
|
103
|
+
|
104
|
+
var listener = this.change(function (e, state) {
|
105
|
+
if ( 'prerender' != state ) {
|
106
|
+
Visibility.unbind(listener);
|
107
|
+
callback();
|
108
|
+
}
|
109
|
+
});
|
156
110
|
},
|
157
111
|
|
158
112
|
// Return true if page now isn’t visible to user.
|
@@ -163,10 +117,7 @@
|
|
163
117
|
//
|
164
118
|
// It is just proxy to `document.hidden`, but use vendor prefix.
|
165
119
|
hidden: function () {
|
166
|
-
|
167
|
-
return false;
|
168
|
-
}
|
169
|
-
return this._prop('hidden');
|
120
|
+
return this._prop('hidden', false);
|
170
121
|
},
|
171
122
|
|
172
123
|
// Return visibility state: 'visible', 'hidden' or 'prerender'.
|
@@ -182,10 +133,7 @@
|
|
182
133
|
// It is just proxy to `document.visibilityState`, but use
|
183
134
|
// vendor prefix.
|
184
135
|
state: function () {
|
185
|
-
|
186
|
-
return 'visible';
|
187
|
-
}
|
188
|
-
return this._prop('visibilityState');
|
136
|
+
return this._prop('visibilityState', 'visible');
|
189
137
|
},
|
190
138
|
|
191
139
|
// Return true if browser support Page Visibility API.
|
@@ -213,22 +161,11 @@
|
|
213
161
|
// by `_setListener` method.
|
214
162
|
_listening: false,
|
215
163
|
|
216
|
-
// Callbacks from `change` method, that wait visibility changes.
|
217
|
-
_changeCallbacks: [],
|
218
|
-
|
219
|
-
// Callbacks from `onVisible` method, that wait when page become to be
|
220
|
-
// visible.
|
221
|
-
_onVisibleCallbacks: [],
|
222
|
-
|
223
|
-
// Callbacks from `afterPrerendering` method, that wait when visibility
|
224
|
-
// state change from “prerender”.
|
225
|
-
_afterPrerenderingCallbacks: [],
|
226
|
-
|
227
164
|
// Last timer number.
|
228
|
-
|
165
|
+
_lastCallback: -1,
|
229
166
|
|
230
|
-
// Callbacks
|
231
|
-
|
167
|
+
// Callbacks from `change` method, that wait visibility changes.
|
168
|
+
_callbacks: { },
|
232
169
|
|
233
170
|
// Variable to check hidden-visible state changes.
|
234
171
|
_hiddenBefore: false,
|
@@ -236,12 +173,6 @@
|
|
236
173
|
// Initialize variables on page loading.
|
237
174
|
_init: function () {
|
238
175
|
this._hiddenBefore = this.hidden();
|
239
|
-
|
240
|
-
if ( defined(window.jQuery) && defined(jQuery.every) ) {
|
241
|
-
this._setInterval = this._chronoSetInterval;
|
242
|
-
} else {
|
243
|
-
this._setInterval = this._originalSetInterval;
|
244
|
-
}
|
245
176
|
},
|
246
177
|
|
247
178
|
// Detect vendor prefix and return it.
|
@@ -273,43 +204,23 @@
|
|
273
204
|
},
|
274
205
|
|
275
206
|
// Return document’s property value with name with vendor prefix.
|
276
|
-
|
277
|
-
|
207
|
+
// If API is not support, it will retun `unsupported` value.
|
208
|
+
_prop: function (name, unsupported) {
|
209
|
+
if ( !this.isSupported() ) {
|
210
|
+
return unsupported;
|
211
|
+
}
|
212
|
+
return this._doc[this._name(name)];
|
278
213
|
},
|
279
214
|
|
280
215
|
// Listener for `visibilitychange` event.
|
281
|
-
|
282
|
-
var
|
283
|
-
state = this.state();
|
284
|
-
|
285
|
-
for ( var i = 0; i < this._changeCallbacks.length; i++ ) {
|
286
|
-
this._changeCallbacks[i].call(this._doc, event, state);
|
287
|
-
}
|
288
|
-
|
289
|
-
var hiddenBefore = this._hiddenBefore;
|
290
|
-
if ( (isHidden && !hiddenBefore) || (!isHidden && hiddenBefore) ) {
|
291
|
-
for ( i in this._timers ) {
|
292
|
-
this._stopTimer(i);
|
293
|
-
this._runTimer(i, !isHidden);
|
294
|
-
}
|
295
|
-
}
|
296
|
-
|
297
|
-
if ( !isHidden ) {
|
298
|
-
for ( var i = 0; i < this._onVisibleCallbacks.length; i++ ) {
|
299
|
-
this._onVisibleCallbacks[i]();
|
300
|
-
}
|
301
|
-
this._onVisibleCallbacks = [];
|
302
|
-
}
|
216
|
+
_onChange: function(event) {
|
217
|
+
var state = this.state();
|
303
218
|
|
304
|
-
|
305
|
-
|
306
|
-
for ( var i = 0; i < after; i++ ) {
|
307
|
-
this._afterPrerenderingCallbacks[i]();
|
308
|
-
}
|
309
|
-
this._afterPrerenderingCallbacks = [];
|
219
|
+
for ( var i in this._callbacks ) {
|
220
|
+
this._callbacks[i].call(this._doc, event, state);
|
310
221
|
}
|
311
222
|
|
312
|
-
this._hiddenBefore =
|
223
|
+
this._hiddenBefore = this.hidden();
|
313
224
|
},
|
314
225
|
|
315
226
|
// Set listener for `visibilitychange` event.
|
@@ -319,7 +230,7 @@
|
|
319
230
|
}
|
320
231
|
var event = this._prefix() + 'visibilitychange';
|
321
232
|
var listener = function () {
|
322
|
-
Visibility.
|
233
|
+
Visibility._onChange.apply(Visibility, arguments);
|
323
234
|
};
|
324
235
|
if ( this._doc.addEventListener ) {
|
325
236
|
this._doc.addEventListener(event, listener, false);
|
@@ -328,63 +239,184 @@
|
|
328
239
|
}
|
329
240
|
this._listening = true;
|
330
241
|
this._hiddenBefore = this.hidden();
|
331
|
-
}
|
242
|
+
}
|
332
243
|
|
333
|
-
|
334
|
-
// sugar.
|
335
|
-
_originalSetInterval: function (callback, interval) {
|
336
|
-
return setInterval(callback, interval);
|
337
|
-
},
|
244
|
+
};
|
338
245
|
|
339
|
-
|
340
|
-
// and `hiddenInterval` arguments, such as "1 second" and others.
|
341
|
-
//
|
342
|
-
// It will be automatically set to `_setInterval` on loading if
|
343
|
-
// you include jQuery Chrono plugin before Visibility.js.
|
344
|
-
_chronoSetInterval: function (callback, internal) {
|
345
|
-
return jQuery.every(internal, callback);
|
346
|
-
},
|
246
|
+
Visibility._init();
|
347
247
|
|
348
|
-
// Set interval by `setInterval`. Allow to change function for tests or
|
349
|
-
// syntax sugar in `interval` arguments.
|
350
|
-
//
|
351
|
-
// Function will be automatically set in `_init` method (which will be
|
352
|
-
// call on script loading). So you must include jQuery Chrono plugin
|
353
|
-
// before Visibility.js.
|
354
|
-
_setInterval: null,
|
355
|
-
|
356
|
-
// Try to run timer from every method by it’s ID. It will be use
|
357
|
-
// `interval` or `hiddenInterval` depending on visibility state.
|
358
|
-
// If page is hidden and `hiddenInterval` is null,
|
359
|
-
// it will not run timer.
|
360
|
-
//
|
361
|
-
// Argument `now` say, that timers must be execute now too.
|
362
|
-
_runTimer: function (id, now) {
|
363
|
-
var interval,
|
364
|
-
timer = this._timers[id];
|
365
|
-
if ( this.hidden() ) {
|
366
|
-
if ( null === timer.hiddenInterval ) {
|
367
|
-
return;
|
368
|
-
}
|
369
|
-
interval = timer.hiddenInterval;
|
370
|
-
} else {
|
371
|
-
interval = timer.interval;
|
372
|
-
}
|
373
|
-
if ( now ) {
|
374
|
-
timer.callback.call(window);
|
375
|
-
}
|
376
|
-
timer.intervalID = this._setInterval(timer.callback, interval);
|
377
|
-
},
|
378
248
|
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
249
|
+
var timers = {
|
250
|
+
|
251
|
+
// Run callback every `interval` milliseconds if page is visible and
|
252
|
+
// every `hiddenInterval` milliseconds if page is hidden.
|
253
|
+
//
|
254
|
+
// Visibility.every(60 * 1000, 5 * 60 * 1000, function () {
|
255
|
+
// checkNewMails();
|
256
|
+
// });
|
257
|
+
//
|
258
|
+
// You can skip `hiddenInterval` and callback will be called only if
|
259
|
+
// page is visible.
|
260
|
+
//
|
261
|
+
// Visibility.every(1000, function () {
|
262
|
+
// updateCountdown();
|
263
|
+
// });
|
264
|
+
//
|
265
|
+
// It is analog of `setInterval(callback, interval)` but use visibility
|
266
|
+
// state.
|
267
|
+
//
|
268
|
+
// It return timer ID, that you can use in `Visibility.stop(id)` to stop
|
269
|
+
// timer (`clearInterval` analog).
|
270
|
+
// Warning: timer ID is different from interval ID from `setInterval`,
|
271
|
+
// so don’t use it in `clearInterval`.
|
272
|
+
//
|
273
|
+
// On change state from hidden to visible timers will be execute.
|
274
|
+
//
|
275
|
+
// If you include jQuery Chrono plugin before Visibility.js, you could
|
276
|
+
// use Chrono’s syntax sugar in interval arguments:
|
277
|
+
//
|
278
|
+
// Visibility.every('second', function () {
|
279
|
+
// updateCountdown();
|
280
|
+
// });
|
281
|
+
// Visibility.every('1 minute', '5 minutes', function () {
|
282
|
+
// checkNewMails();
|
283
|
+
// });
|
284
|
+
every: function (interval, hiddenInterval, callback) {
|
285
|
+
this._initTimers();
|
286
|
+
|
287
|
+
if ( !defined(callback) ) {
|
288
|
+
callback = hiddenInterval;
|
289
|
+
hiddenInterval = null;
|
290
|
+
}
|
291
|
+
this._lastTimer += 1;
|
292
|
+
var number = this._lastTimer;
|
293
|
+
this._timers[number] = ({
|
294
|
+
interval: interval,
|
295
|
+
hiddenInterval: hiddenInterval,
|
296
|
+
callback: callback
|
297
|
+
});
|
298
|
+
this._runTimer(number, false);
|
299
|
+
|
300
|
+
if ( this.isSupported() ) {
|
301
|
+
this._setListener();
|
302
|
+
}
|
303
|
+
return number;
|
304
|
+
},
|
305
|
+
|
306
|
+
// Stop timer from `every` method by it ID (`every` method return it).
|
307
|
+
//
|
308
|
+
// slideshow = Visibility.every(5 * 1000, function () {
|
309
|
+
// changeSlide();
|
310
|
+
// });
|
311
|
+
// $('.stopSlideshow').click(function () {
|
312
|
+
// Visibility.stop(slideshow);
|
313
|
+
// });
|
314
|
+
stop: function(id) {
|
315
|
+
var timer = this._timers[id]
|
316
|
+
if ( !defined(timer) ) {
|
317
|
+
return false;
|
318
|
+
}
|
319
|
+
this._stopTimer(id);
|
320
|
+
delete this._timers[id];
|
321
|
+
return timer;
|
322
|
+
},
|
323
|
+
|
324
|
+
// Last timer number.
|
325
|
+
_lastTimer: -1,
|
326
|
+
|
327
|
+
// Callbacks and intervals added by `every` method.
|
328
|
+
_timers: { },
|
329
|
+
|
330
|
+
// Is setInterval method detected and listener is binded.
|
331
|
+
_timersInitialized: false,
|
332
|
+
|
333
|
+
// Initialize variables on page loading.
|
334
|
+
_initTimers: function () {
|
335
|
+
if ( this._timersInitialized ) {
|
336
|
+
return;
|
337
|
+
}
|
338
|
+
this._timersInitialized = true;
|
339
|
+
|
340
|
+
if ( defined(window.jQuery) && defined(jQuery.every) ) {
|
341
|
+
this._setInterval = this._chronoInterval;
|
342
|
+
} else {
|
343
|
+
this._setInterval = this._originalInterval;
|
344
|
+
}
|
345
|
+
this.change(function () {
|
346
|
+
Visibility._timersStopRun()
|
347
|
+
});
|
348
|
+
},
|
349
|
+
|
350
|
+
// Set interval directly by `setInterval` function without any syntax
|
351
|
+
// sugar.
|
352
|
+
_originalInterval: function (callback, interval) {
|
353
|
+
return setInterval(callback, interval);
|
354
|
+
},
|
355
|
+
|
356
|
+
// Set interval by jQuery Chrono plugin. Add syntax sugar to `interval`
|
357
|
+
// and `hiddenInterval` arguments, such as "1 second" and others.
|
358
|
+
//
|
359
|
+
// It will be automatically set to `_setInterval` on loading if
|
360
|
+
// you include jQuery Chrono plugin before Visibility.js.
|
361
|
+
_chronoInterval: function (callback, internal) {
|
362
|
+
return jQuery.every(internal, callback);
|
363
|
+
},
|
364
|
+
|
365
|
+
// Set interval by `setInterval`. Allow to change function for tests or
|
366
|
+
// syntax sugar in `interval` arguments.
|
367
|
+
//
|
368
|
+
// Function will be automatically set in `_init` method (which will be
|
369
|
+
// call on script loading). So you must include jQuery Chrono plugin
|
370
|
+
// before Visibility.js.
|
371
|
+
_setInterval: null,
|
372
|
+
|
373
|
+
// Try to run timer from every method by it’s ID. It will be use
|
374
|
+
// `interval` or `hiddenInterval` depending on visibility state.
|
375
|
+
// If page is hidden and `hiddenInterval` is null,
|
376
|
+
// it will not run timer.
|
377
|
+
//
|
378
|
+
// Argument `now` say, that timers must be execute now too.
|
379
|
+
_runTimer: function (id, now) {
|
380
|
+
var interval,
|
381
|
+
timer = this._timers[id];
|
382
|
+
if ( this.hidden() ) {
|
383
|
+
if ( null === timer.hiddenInterval ) {
|
384
|
+
return;
|
385
|
+
}
|
386
|
+
interval = timer.hiddenInterval;
|
387
|
+
} else {
|
388
|
+
interval = timer.interval;
|
389
|
+
}
|
390
|
+
if ( now ) {
|
391
|
+
timer.callback.call(window);
|
392
|
+
}
|
393
|
+
timer.id = this._setInterval(timer.callback, interval);
|
394
|
+
},
|
395
|
+
|
396
|
+
// Stop timer from `every` method by it’s ID.
|
397
|
+
_stopTimer: function (id) {
|
398
|
+
var timer = this._timers[id];
|
399
|
+
clearInterval(timer.id);
|
400
|
+
delete timer.id;
|
401
|
+
},
|
402
|
+
|
403
|
+
// Listener for `visibilitychange` event.
|
404
|
+
_timersStopRun: function (event) {
|
405
|
+
var isHidden = this.hidden(),
|
406
|
+
hiddenBefore = this._hiddenBefore;
|
407
|
+
|
408
|
+
if ( (isHidden && !hiddenBefore) || (!isHidden && hiddenBefore) ) {
|
409
|
+
for ( var i in this._timers ) {
|
410
|
+
this._stopTimer(i);
|
411
|
+
this._runTimer(i, !isHidden);
|
412
|
+
}
|
413
|
+
}
|
414
|
+
}
|
385
415
|
|
386
416
|
};
|
387
417
|
|
388
|
-
|
418
|
+
for ( var prop in timers ) {
|
419
|
+
Visibility[prop] = timers[prop];
|
420
|
+
}
|
389
421
|
|
390
422
|
})();
|
@@ -0,0 +1,199 @@
|
|
1
|
+
/*
|
2
|
+
* Copyright 2012 Andrey “A.I.” Sitnik <andrey@sitnik.ru>,
|
3
|
+
* sponsored by Evil Martians.
|
4
|
+
*
|
5
|
+
* This program is free software: you can redistribute it and/or modify
|
6
|
+
* it under the terms of the GNU Lesser General Public License as published by
|
7
|
+
* the Free Software Foundation, either version 3 of the License, or
|
8
|
+
* (at your option) any later version.
|
9
|
+
*
|
10
|
+
* This program is distributed in the hope that it will be useful,
|
11
|
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
12
|
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
13
|
+
* GNU Lesser General Public License for more details.
|
14
|
+
*
|
15
|
+
* You should have received a copy of the GNU Lesser General Public License
|
16
|
+
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
17
|
+
*/
|
18
|
+
|
19
|
+
;(function () {
|
20
|
+
"use strict";
|
21
|
+
|
22
|
+
var defined = function(variable) {
|
23
|
+
return ('undefined' != typeof(variable));
|
24
|
+
};
|
25
|
+
|
26
|
+
var timers = {
|
27
|
+
|
28
|
+
// Run callback every `interval` milliseconds if page is visible and
|
29
|
+
// every `hiddenInterval` milliseconds if page is hidden.
|
30
|
+
//
|
31
|
+
// Visibility.every(60 * 1000, 5 * 60 * 1000, function () {
|
32
|
+
// checkNewMails();
|
33
|
+
// });
|
34
|
+
//
|
35
|
+
// You can skip `hiddenInterval` and callback will be called only if
|
36
|
+
// page is visible.
|
37
|
+
//
|
38
|
+
// Visibility.every(1000, function () {
|
39
|
+
// updateCountdown();
|
40
|
+
// });
|
41
|
+
//
|
42
|
+
// It is analog of `setInterval(callback, interval)` but use visibility
|
43
|
+
// state.
|
44
|
+
//
|
45
|
+
// It return timer ID, that you can use in `Visibility.stop(id)` to stop
|
46
|
+
// timer (`clearInterval` analog).
|
47
|
+
// Warning: timer ID is different from interval ID from `setInterval`,
|
48
|
+
// so don’t use it in `clearInterval`.
|
49
|
+
//
|
50
|
+
// On change state from hidden to visible timers will be execute.
|
51
|
+
//
|
52
|
+
// If you include jQuery Chrono plugin before Visibility.js, you could
|
53
|
+
// use Chrono’s syntax sugar in interval arguments:
|
54
|
+
//
|
55
|
+
// Visibility.every('second', function () {
|
56
|
+
// updateCountdown();
|
57
|
+
// });
|
58
|
+
// Visibility.every('1 minute', '5 minutes', function () {
|
59
|
+
// checkNewMails();
|
60
|
+
// });
|
61
|
+
every: function (interval, hiddenInterval, callback) {
|
62
|
+
this._initTimers();
|
63
|
+
|
64
|
+
if ( !defined(callback) ) {
|
65
|
+
callback = hiddenInterval;
|
66
|
+
hiddenInterval = null;
|
67
|
+
}
|
68
|
+
this._lastTimer += 1;
|
69
|
+
var number = this._lastTimer;
|
70
|
+
this._timers[number] = ({
|
71
|
+
interval: interval,
|
72
|
+
hiddenInterval: hiddenInterval,
|
73
|
+
callback: callback
|
74
|
+
});
|
75
|
+
this._runTimer(number, false);
|
76
|
+
|
77
|
+
if ( this.isSupported() ) {
|
78
|
+
this._setListener();
|
79
|
+
}
|
80
|
+
return number;
|
81
|
+
},
|
82
|
+
|
83
|
+
// Stop timer from `every` method by it ID (`every` method return it).
|
84
|
+
//
|
85
|
+
// slideshow = Visibility.every(5 * 1000, function () {
|
86
|
+
// changeSlide();
|
87
|
+
// });
|
88
|
+
// $('.stopSlideshow').click(function () {
|
89
|
+
// Visibility.stop(slideshow);
|
90
|
+
// });
|
91
|
+
stop: function(id) {
|
92
|
+
var timer = this._timers[id]
|
93
|
+
if ( !defined(timer) ) {
|
94
|
+
return false;
|
95
|
+
}
|
96
|
+
this._stopTimer(id);
|
97
|
+
delete this._timers[id];
|
98
|
+
return timer;
|
99
|
+
},
|
100
|
+
|
101
|
+
// Last timer number.
|
102
|
+
_lastTimer: -1,
|
103
|
+
|
104
|
+
// Callbacks and intervals added by `every` method.
|
105
|
+
_timers: { },
|
106
|
+
|
107
|
+
// Is setInterval method detected and listener is binded.
|
108
|
+
_timersInitialized: false,
|
109
|
+
|
110
|
+
// Initialize variables on page loading.
|
111
|
+
_initTimers: function () {
|
112
|
+
if ( this._timersInitialized ) {
|
113
|
+
return;
|
114
|
+
}
|
115
|
+
this._timersInitialized = true;
|
116
|
+
|
117
|
+
if ( defined(window.jQuery) && defined(jQuery.every) ) {
|
118
|
+
this._setInterval = this._chronoInterval;
|
119
|
+
} else {
|
120
|
+
this._setInterval = this._originalInterval;
|
121
|
+
}
|
122
|
+
this.change(function () {
|
123
|
+
Visibility._timersStopRun()
|
124
|
+
});
|
125
|
+
},
|
126
|
+
|
127
|
+
// Set interval directly by `setInterval` function without any syntax
|
128
|
+
// sugar.
|
129
|
+
_originalInterval: function (callback, interval) {
|
130
|
+
return setInterval(callback, interval);
|
131
|
+
},
|
132
|
+
|
133
|
+
// Set interval by jQuery Chrono plugin. Add syntax sugar to `interval`
|
134
|
+
// and `hiddenInterval` arguments, such as "1 second" and others.
|
135
|
+
//
|
136
|
+
// It will be automatically set to `_setInterval` on loading if
|
137
|
+
// you include jQuery Chrono plugin before Visibility.js.
|
138
|
+
_chronoInterval: function (callback, internal) {
|
139
|
+
return jQuery.every(internal, callback);
|
140
|
+
},
|
141
|
+
|
142
|
+
// Set interval by `setInterval`. Allow to change function for tests or
|
143
|
+
// syntax sugar in `interval` arguments.
|
144
|
+
//
|
145
|
+
// Function will be automatically set in `_init` method (which will be
|
146
|
+
// call on script loading). So you must include jQuery Chrono plugin
|
147
|
+
// before Visibility.js.
|
148
|
+
_setInterval: null,
|
149
|
+
|
150
|
+
// Try to run timer from every method by it’s ID. It will be use
|
151
|
+
// `interval` or `hiddenInterval` depending on visibility state.
|
152
|
+
// If page is hidden and `hiddenInterval` is null,
|
153
|
+
// it will not run timer.
|
154
|
+
//
|
155
|
+
// Argument `now` say, that timers must be execute now too.
|
156
|
+
_runTimer: function (id, now) {
|
157
|
+
var interval,
|
158
|
+
timer = this._timers[id];
|
159
|
+
if ( this.hidden() ) {
|
160
|
+
if ( null === timer.hiddenInterval ) {
|
161
|
+
return;
|
162
|
+
}
|
163
|
+
interval = timer.hiddenInterval;
|
164
|
+
} else {
|
165
|
+
interval = timer.interval;
|
166
|
+
}
|
167
|
+
if ( now ) {
|
168
|
+
timer.callback.call(window);
|
169
|
+
}
|
170
|
+
timer.id = this._setInterval(timer.callback, interval);
|
171
|
+
},
|
172
|
+
|
173
|
+
// Stop timer from `every` method by it’s ID.
|
174
|
+
_stopTimer: function (id) {
|
175
|
+
var timer = this._timers[id];
|
176
|
+
clearInterval(timer.id);
|
177
|
+
delete timer.id;
|
178
|
+
},
|
179
|
+
|
180
|
+
// Listener for `visibilitychange` event.
|
181
|
+
_timersStopRun: function (event) {
|
182
|
+
var isHidden = this.hidden(),
|
183
|
+
hiddenBefore = this._hiddenBefore;
|
184
|
+
|
185
|
+
if ( (isHidden && !hiddenBefore) || (!isHidden && hiddenBefore) ) {
|
186
|
+
for ( var i in this._timers ) {
|
187
|
+
this._stopTimer(i);
|
188
|
+
this._runTimer(i, !isHidden);
|
189
|
+
}
|
190
|
+
}
|
191
|
+
}
|
192
|
+
|
193
|
+
};
|
194
|
+
|
195
|
+
for ( var prop in timers ) {
|
196
|
+
Visibility[prop] = timers[prop];
|
197
|
+
}
|
198
|
+
|
199
|
+
})();
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: visibilityjs
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: '0.5'
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-06
|
12
|
+
date: 2012-07-06 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: sprockets
|
@@ -41,6 +41,8 @@ extra_rdoc_files:
|
|
41
41
|
- ChangeLog
|
42
42
|
files:
|
43
43
|
- lib/assets/javascripts/visibility.js
|
44
|
+
- lib/assets/javascripts/visibility.core.js
|
45
|
+
- lib/assets/javascripts/visibility.timers.js
|
44
46
|
- lib/assets/javascripts/visibility.fallback.js
|
45
47
|
- lib/visibilityjs.rb
|
46
48
|
- LICENSE
|