visibility 0.1 → 0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/ChangeLog +7 -0
- data/README.md +111 -103
- data/vendor/assets/javascripts/visibility.js +22 -19
- metadata +7 -6
data/ChangeLog
ADDED
data/README.md
CHANGED
@@ -1,164 +1,170 @@
|
|
1
|
-
# Visibility.js –
|
1
|
+
# Visibility.js – a wrapper for the Page Visibility API
|
2
2
|
|
3
|
-
Visibility.js allow you to
|
4
|
-
hidden in background tab or prerendering. It
|
5
|
-
|
6
|
-
and AJAX requests
|
7
|
-
|
3
|
+
Visibility.js allow you to determine whether your web page is visible to an
|
4
|
+
user, is hidden in background tab or is prerendering. It allows you use the page
|
5
|
+
visibility state in JavaScript logic and improve browser performance by
|
6
|
+
disabling unnecessary timers and AJAX requests, or improve user interface
|
7
|
+
experience (for example, by stopping video playback or slideshow when user
|
8
|
+
switches to another browser tab).
|
8
9
|
|
9
|
-
|
10
|
-
|
11
|
-
calculations
|
10
|
+
Moreover, you can detect if the browser is just [prerendering] the page while
|
11
|
+
the user has not still opened the link, and don’t count this as a visit in your
|
12
|
+
analytics module, or do not run heavy calculations or other actions which will
|
13
|
+
disable the prerendering.
|
12
14
|
|
13
|
-
This library is
|
14
|
-
vendor prefixes and
|
15
|
+
This library is a wrapper of the [Page Visibility API]. It eases usage of the
|
16
|
+
API by hiding vendor-specific property prefixes and adding some high-level
|
17
|
+
functions.
|
15
18
|
|
16
|
-
|
17
|
-
|
18
|
-
visible and your logic will
|
19
|
+
In most cases you don’t need to check whether the Page Visibility API is
|
20
|
+
actually supported in the browser as, if it does not, the library will just
|
21
|
+
assume that the page is visible all the time, and your logic will still work
|
22
|
+
correctly, albeit less effective in some cases.
|
19
23
|
|
20
24
|
[Page Visibility API]: http://www.w3.org/TR/2011/WD-page-visibility-20110602/
|
21
25
|
[prerendering]: http://code.google.com/chrome/whitepapers/prerender.html
|
22
26
|
|
23
27
|
## States
|
24
28
|
|
25
|
-
|
29
|
+
Currently the Page Visibility API supports three visibility states:
|
26
30
|
|
27
|
-
* `visible
|
28
|
-
* `hidden
|
29
|
-
* `prerender
|
30
|
-
|
31
|
+
* `visible`: user has opened the page and works within it.
|
32
|
+
* `hidden`: user has switched to another tab or minimized browser window.
|
33
|
+
* `prerender`: browser is just prerendering a page which may possibly be opened
|
34
|
+
by the user to make the apparent loading time lesser.
|
31
35
|
|
32
36
|
## Timers
|
33
37
|
|
34
|
-
The main
|
35
|
-
|
38
|
+
The main use case for this library is to enable some of the times only when
|
39
|
+
content is visible to the user, i.e. the ones animating a countdown animation.
|
36
40
|
|
37
|
-
`Visibility.every(interval, callback)` is
|
38
|
-
`setInterval(callback, interval)`, but
|
39
|
-
if page is visible. For example, let create countdown:
|
41
|
+
`Visibility.every(interval, callback)` is similar to
|
42
|
+
`setInterval(callback, interval)`, but calls `callback` every `interval` ms only
|
43
|
+
if the page is visible. For example, let’s create a countdown timer:
|
40
44
|
|
41
45
|
```js
|
42
|
-
Visibility.every(1000, function() {
|
46
|
+
Visibility.every(1000, function () {
|
43
47
|
updateCountdownAnimation();
|
44
48
|
});
|
45
49
|
```
|
46
50
|
|
47
|
-
You can
|
48
|
-
is hidden.
|
49
|
-
page and every 5 minutes for hidden:
|
51
|
+
You can provide an additional interval which will be used when the page
|
52
|
+
is hidden. In next example, a check for inbox updates will be run every 1 minute
|
53
|
+
for a visible page and every 5 minutes for a hidden one:
|
50
54
|
|
51
55
|
```js
|
52
56
|
var minute = 60 * 1000;
|
53
|
-
Visibility.every(minute, 5 * minute, function() {
|
54
|
-
|
57
|
+
Visibility.every(minute, 5 * minute, function () {
|
58
|
+
checkForEmail();
|
55
59
|
});
|
56
60
|
```
|
57
61
|
|
58
|
-
Note
|
59
|
-
|
62
|
+
Note that the callback will also be executed on every `hidden`->`visible` state
|
63
|
+
change to update old contents.
|
60
64
|
|
61
|
-
|
62
|
-
[jQuery Chrono plugin]
|
65
|
+
A syntactic sugar for specifying time intervals is supported when
|
66
|
+
[jQuery Chrono plugin] is included before Visibility.js. It can be used like
|
67
|
+
this:
|
63
68
|
|
64
69
|
```js
|
65
|
-
Visibility.every('minute', '5 minutes', function() {
|
70
|
+
Visibility.every('minute', '5 minutes', function () {
|
66
71
|
checkNewMails();
|
67
72
|
});
|
68
73
|
```
|
69
74
|
|
70
|
-
`Visibility.every`
|
71
|
-
|
75
|
+
`Visibility.every` returns a timer identifier, much like the `setTimeout`
|
76
|
+
function. It cannot be passed to `clearInterval`, through, and you should use
|
77
|
+
`Visibility.stop(id)` to stop the timer.
|
72
78
|
|
73
79
|
```js
|
74
|
-
slideshow = Visibility.every(5 * 1000, function() {
|
75
|
-
|
80
|
+
slideshow = Visibility.every(5 * 1000, function () {
|
81
|
+
nextSlide();
|
76
82
|
});
|
77
83
|
|
78
|
-
$('.stopSlideshow').click(function() {
|
84
|
+
$('.stopSlideshow').click(function () {
|
79
85
|
Visibility.stop(slideshow);
|
80
86
|
});
|
81
87
|
```
|
82
88
|
|
83
|
-
If browser
|
84
|
-
|
85
|
-
|
89
|
+
If the browser does not support the Page Visibility API, `Visibility.every` will
|
90
|
+
fall back to `setInterval`, and `callback` will be run every `interval` ms for
|
91
|
+
both the hidden and visible pages.
|
86
92
|
|
87
93
|
[jQuery Chrono plugin]: https://github.com/avk/jQuery-Chrono
|
88
94
|
|
89
95
|
## Initializers
|
90
96
|
|
91
|
-
|
92
|
-
|
97
|
+
In another common use case you need to execute some actions upon a switch to
|
98
|
+
particular visibility state.
|
93
99
|
|
94
|
-
###
|
100
|
+
### Waiting until the page becomes visible
|
95
101
|
|
96
|
-
`Visibility.onVisible(callback)`
|
97
|
-
will run `callback`,
|
98
|
-
run `callback`.
|
102
|
+
`Visibility.onVisible(callback)` checks current state of the page. If it is
|
103
|
+
visible now, it will run `callback`, otherwise it will wait until state changes
|
104
|
+
to `visible`, and then run `callback`.
|
99
105
|
|
100
|
-
For example,
|
101
|
-
|
102
|
-
user
|
106
|
+
For example, let’s show an animated notification only when the page is visible,
|
107
|
+
so if an user opens a page in the background, the animation will delay until
|
108
|
+
the page becomes visible, i.e. until the user has switched to a tab with
|
109
|
+
the page:
|
103
110
|
|
104
111
|
```js
|
105
|
-
Visibility.onVisible(function() {
|
112
|
+
Visibility.onVisible(function () {
|
106
113
|
Notification.animateNotice("Hello");
|
107
114
|
});
|
108
115
|
```
|
109
116
|
|
110
|
-
If browser doesn’t support Page Visibility API, `Visibility.onVisible` will
|
111
|
-
`callback`
|
117
|
+
If a browser doesn’t support Page Visibility API, `Visibility.onVisible` will
|
118
|
+
run the `callback` immediately.
|
112
119
|
|
113
|
-
### Wait until
|
120
|
+
### Wait until the page is opened after prerendering
|
114
121
|
|
115
|
-
|
116
|
-
(
|
117
|
-
|
118
|
-
|
122
|
+
A web developer can hint a browser (using Prerendering API) that an user is
|
123
|
+
likely to click on some link (i.e. on a "Next" link in a multi-page article),
|
124
|
+
and the browser then may prefetch and prerender the page, so that the user will
|
125
|
+
not wait after actually going via the like.
|
119
126
|
|
120
|
-
But
|
121
|
-
|
122
|
-
heavy
|
123
|
-
|
124
|
-
user
|
127
|
+
But you may not want to count the browser prerendering a page as a visitor in
|
128
|
+
your analytics system. Moreover, the browser will disable prerendering if you
|
129
|
+
will try to do heavy computations or use audio/video tags on the page. So, you
|
130
|
+
may decide to not run parts of the code while prerendering and wait until the
|
131
|
+
user actually opens the link.
|
125
132
|
|
126
|
-
You can use `Visibility.
|
127
|
-
|
133
|
+
You can use `Visibility.afterPrerendering(callback)` in this cases. For example,
|
134
|
+
this code will only take real visitors (and not page prerenderings) into
|
135
|
+
account:
|
128
136
|
|
129
137
|
```js
|
130
|
-
Visibility.
|
138
|
+
Visibility.afterPrerendering(function () {
|
131
139
|
Statistics.countVisitor();
|
132
140
|
});
|
133
141
|
```
|
134
142
|
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
If browser doesn’t support Page Visibility API, `Visibility.notPrerender` will
|
139
|
-
run `callback` at once.
|
143
|
+
If the browser doesn’t support Page Visibility API,
|
144
|
+
`Visibility.afterPrerendering` will run `callback` immediately.
|
140
145
|
|
141
|
-
## Low-level
|
146
|
+
## Low-level API
|
142
147
|
|
143
|
-
|
144
|
-
|
148
|
+
In some cases you may need more low-level methods. For example, you may want to
|
149
|
+
count the time user has viewed the page in foreground and time it has stayed in
|
150
|
+
background.
|
145
151
|
|
146
|
-
`Visibility.
|
152
|
+
`Visibility.isSupported()` will return `true` if browser supports the
|
147
153
|
Page Visibility API:
|
148
154
|
|
149
155
|
```js
|
150
|
-
if
|
156
|
+
if( Visibility.isSupported() ) {
|
151
157
|
Statistics.startTrackingVisibility();
|
152
158
|
}
|
153
159
|
```
|
154
160
|
|
155
|
-
`Visibility.state()` will return string with visibility state
|
156
|
-
be
|
157
|
-
|
158
|
-
For example,
|
159
|
-
`Visibility.hidden()` will return `true`.
|
161
|
+
`Visibility.state()` will return a string with visibility state. More states
|
162
|
+
can be added in the future, so for most cases a simpler `Visibility.hidden()`
|
163
|
+
method can be used. It will return `true` if the page is hidden by any reason.
|
164
|
+
For example, while prerendering, `Visibility.state()` will return `"prerender"`,
|
165
|
+
but `Visibility.hidden()` will return `true`.
|
160
166
|
|
161
|
-
|
167
|
+
This code will aid in collecting page visibility statistics:
|
162
168
|
|
163
169
|
```js
|
164
170
|
$(document).load(function () {
|
@@ -173,8 +179,8 @@ $(document).load(function () {
|
|
173
179
|
});
|
174
180
|
```
|
175
181
|
|
176
|
-
|
177
|
-
(not
|
182
|
+
And this example will only enable auto-playing when the page is opening as a
|
183
|
+
visible tab (not a background one):
|
178
184
|
|
179
185
|
```js
|
180
186
|
$(document).load(function () {
|
@@ -186,29 +192,29 @@ $(document).load(function () {
|
|
186
192
|
});
|
187
193
|
```
|
188
194
|
|
189
|
-
|
190
|
-
|
195
|
+
Using `Visibility.change(callback)` you can listen to visibility state changing
|
196
|
+
events. The `callback` takes 2 arguments: an event object and a state name.
|
191
197
|
|
192
|
-
|
198
|
+
Let’s collect some statistics with this evented approach:
|
193
199
|
|
194
200
|
```js
|
195
|
-
Visibility.change(function(e, state) {
|
201
|
+
Visibility.change(function (e, state) {
|
196
202
|
Statistics.visibilityChange(state);
|
197
203
|
});
|
198
204
|
```
|
199
205
|
|
200
|
-
##
|
206
|
+
## Installing
|
201
207
|
|
202
208
|
### Rails 3.1
|
203
209
|
|
204
|
-
In Rails 3.1 (or another
|
205
|
-
`Gemfile`:
|
210
|
+
In Rails 3.1 (or another framework with Sprockets 2) just add `visibility` gem
|
211
|
+
to `Gemfile`:
|
206
212
|
|
207
213
|
```ruby
|
208
214
|
gem 'visibility'
|
209
215
|
```
|
210
216
|
|
211
|
-
and
|
217
|
+
and require it in `app/assets/javascripts/application.js.coffee`:
|
212
218
|
|
213
219
|
```coffee
|
214
220
|
#= require "visibility"
|
@@ -216,8 +222,9 @@ and add require to `app/assets/javascripts/application.js.coffee`:
|
|
216
222
|
|
217
223
|
### Jammit
|
218
224
|
|
219
|
-
If you use Jammit or another package manager
|
220
|
-
`public/javascripts/lib` in your project and add
|
225
|
+
If you use Jammit or another package manager, you’ll need to copy
|
226
|
+
`lib/visibility.js` to `public/javascripts/lib` in your project and add the
|
227
|
+
library to `config/assets.yml`:
|
221
228
|
|
222
229
|
```yaml
|
223
230
|
javascripts:
|
@@ -227,21 +234,22 @@ javascripts:
|
|
227
234
|
|
228
235
|
### Other
|
229
236
|
|
230
|
-
If you
|
231
|
-
|
237
|
+
If you don’t use Rails 3.1 or assets packaging manager you can use an already
|
238
|
+
minified version of the library, located in repository as
|
239
|
+
`lib/visibility.min.js`.
|
232
240
|
|
233
241
|
## Contributing
|
234
242
|
|
235
|
-
To run project tests and minimize source you
|
236
|
-
For example,
|
243
|
+
To run project tests and minimize source you’ll need to have Ruby and Bundler
|
244
|
+
installed. For example, in a Debian-based (e.g. Ubuntu) environment:
|
237
245
|
|
238
246
|
```
|
239
247
|
sudo apt-get install ruby rubygems
|
240
248
|
sudo gem install bundler
|
241
249
|
```
|
242
250
|
|
243
|
-
|
244
|
-
Run in project
|
251
|
+
Then, you will need to install Jasmine, UglifyJS and other dependencies with
|
252
|
+
Bundler. Run in root of the project repository:
|
245
253
|
|
246
254
|
```
|
247
255
|
bundle install --path=.bundle
|
@@ -253,7 +261,7 @@ That’s all. To run tests, start server and open <http://localhost:8888/>:
|
|
253
261
|
bundle exec rake server
|
254
262
|
```
|
255
263
|
|
256
|
-
|
264
|
+
Minimize the source before commiting:
|
257
265
|
|
258
266
|
```
|
259
267
|
bundle exec rake min
|
@@ -49,9 +49,9 @@
|
|
49
49
|
// visible.
|
50
50
|
_onVisibleCallbacks: [],
|
51
51
|
|
52
|
-
// Callbacks from `
|
53
|
-
// change from “prerender”.
|
54
|
-
|
52
|
+
// Callbacks from `afterPrerendering` method, that wait when visibility
|
53
|
+
// state change from “prerender”.
|
54
|
+
_afterPrerenderingCallbacks: [],
|
55
55
|
|
56
56
|
// Last timer number.
|
57
57
|
_lastTimer: 0,
|
@@ -131,10 +131,11 @@
|
|
131
131
|
}
|
132
132
|
|
133
133
|
if ( 'prerender' != this.state() ) {
|
134
|
-
|
135
|
-
|
134
|
+
var after = this._afterPrerenderingCallbacks.length
|
135
|
+
for ( var i = 0; i < after; i++ ) {
|
136
|
+
this._afterPrerenderingCallbacks[i]();
|
136
137
|
}
|
137
|
-
this.
|
138
|
+
this._afterPrerenderingCallbacks = [];
|
138
139
|
}
|
139
140
|
|
140
141
|
this._hiddenBefore = isHidden;
|
@@ -199,7 +200,7 @@
|
|
199
200
|
timer.intervalID = this._setInterval(timer.callback, interval);
|
200
201
|
},
|
201
202
|
|
202
|
-
// Stop timer from `every` method by it
|
203
|
+
// Stop timer from `every` method by it’s ID.
|
203
204
|
_stopTimer: function (id) {
|
204
205
|
var timer = this._timers[id];
|
205
206
|
clearInterval(timer.intervalID);
|
@@ -208,13 +209,13 @@
|
|
208
209
|
|
209
210
|
// Return true if browser support Page Visibility API.
|
210
211
|
//
|
211
|
-
// if ( Visibility.
|
212
|
+
// if ( Visibility.isSupported() ) {
|
212
213
|
// Statistics.startTrackingVisibility();
|
213
214
|
// Visibility.change(function(e, state)) {
|
214
215
|
// Statistics.trackVisibility(state);
|
215
216
|
// });
|
216
217
|
// }
|
217
|
-
|
218
|
+
isSupported: function () {
|
218
219
|
return defined(this._prefix());
|
219
220
|
},
|
220
221
|
|
@@ -226,7 +227,7 @@
|
|
226
227
|
//
|
227
228
|
// It is just proxy to `document.hidden`, but use vendor prefix.
|
228
229
|
hidden: function () {
|
229
|
-
if ( !this.
|
230
|
+
if ( !this.isSupported() ) {
|
230
231
|
return false;
|
231
232
|
}
|
232
233
|
return this._prop('hidden');
|
@@ -245,7 +246,7 @@
|
|
245
246
|
// It is just proxy to `document.visibilityState`, but use
|
246
247
|
// vendor prefix.
|
247
248
|
state: function () {
|
248
|
-
if ( !this.
|
249
|
+
if ( !this.isSupported() ) {
|
249
250
|
return 'visible';
|
250
251
|
}
|
251
252
|
return this._prop('visibilityState');
|
@@ -264,7 +265,7 @@
|
|
264
265
|
//
|
265
266
|
// It is just proxy to `visibilitychange` event, but use vendor prefix.
|
266
267
|
change: function (callback) {
|
267
|
-
if ( !this.
|
268
|
+
if ( !this.isSupported() ) {
|
268
269
|
return false;
|
269
270
|
}
|
270
271
|
this._changeCallbacks.push(callback);
|
@@ -282,7 +283,7 @@
|
|
282
283
|
// Notification.animateNotice("Hello");
|
283
284
|
// });
|
284
285
|
onVisible: function (callback) {
|
285
|
-
if ( !this.
|
286
|
+
if ( !this.isSupported() || !this.hidden() ) {
|
286
287
|
callback();
|
287
288
|
return true;
|
288
289
|
}
|
@@ -295,15 +296,15 @@
|
|
295
296
|
// If Page Visibility API doesn’t supported, it will call `callback`
|
296
297
|
// immediately.
|
297
298
|
//
|
298
|
-
// Visibility.
|
299
|
+
// Visibility.afterPrerendering(function () {
|
299
300
|
// Statistics.countVisitor();
|
300
301
|
// });
|
301
|
-
|
302
|
-
if ( !this.
|
302
|
+
afterPrerendering: function (callback) {
|
303
|
+
if ( !this.isSupported() || 'prerender' != this.state() ) {
|
303
304
|
callback();
|
304
305
|
return true;
|
305
306
|
}
|
306
|
-
this.
|
307
|
+
this._afterPrerenderingCallbacks.push(callback);
|
307
308
|
this._setListener();
|
308
309
|
},
|
309
310
|
|
@@ -327,7 +328,7 @@
|
|
327
328
|
// It return timer ID, that you can use in `Visibility.stop(id)` to stop
|
328
329
|
// timer (`clearInterval` analog).
|
329
330
|
// Warning: timer ID is different from intervalID from `setInterval`,
|
330
|
-
// so don
|
331
|
+
// so don’t use it in `clearInterval`.
|
331
332
|
//
|
332
333
|
// On change state from hidden to visible timers will be execute.
|
333
334
|
//
|
@@ -353,7 +354,9 @@
|
|
353
354
|
callback: callback
|
354
355
|
});
|
355
356
|
this._runTimer(number, false);
|
356
|
-
this.
|
357
|
+
if ( this.isSupported() ) {
|
358
|
+
this._setListener();
|
359
|
+
}
|
357
360
|
return number;
|
358
361
|
},
|
359
362
|
|
metadata
CHANGED
@@ -1,12 +1,12 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: visibility
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 15
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 0
|
8
|
-
-
|
9
|
-
version: "0.
|
8
|
+
- 2
|
9
|
+
version: "0.2"
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- "Andrey \xE2\x80\x9CA.I.\xE2\x80\x9D Sitnik"
|
@@ -14,7 +14,7 @@ autorequire:
|
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
16
|
|
17
|
-
date: 2011-06-
|
17
|
+
date: 2011-06-26 00:00:00 +04:00
|
18
18
|
default_executable:
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
@@ -35,7 +35,7 @@ dependencies:
|
|
35
35
|
requirement: *id001
|
36
36
|
type: :runtime
|
37
37
|
name: sprockets
|
38
|
-
description: Visibility.js allow you to
|
38
|
+
description: Visibility.js allow you to determine whether your web page is visible to an user, is hidden in background tab or is prerendering. It allows you use the page visibility state in JavaScript logic and improve browser performance or improve user interface experience.
|
39
39
|
email:
|
40
40
|
- andrey@sitnik.ru
|
41
41
|
executables: []
|
@@ -49,6 +49,7 @@ files:
|
|
49
49
|
- vendor/assets/javascripts/visibility.js
|
50
50
|
- LICENSE
|
51
51
|
- README.md
|
52
|
+
- ChangeLog
|
52
53
|
has_rdoc: true
|
53
54
|
homepage: https://github.com/evilmartians/visibility.js
|
54
55
|
licenses: []
|
@@ -82,6 +83,6 @@ rubyforge_project:
|
|
82
83
|
rubygems_version: 1.3.7
|
83
84
|
signing_key:
|
84
85
|
specification_version: 3
|
85
|
-
summary: Visibility.js
|
86
|
+
summary: "Visibility.js \xE2\x80\x93 a wrapper for the Page Visibility API."
|
86
87
|
test_files: []
|
87
88
|
|