visibility 0.1

Sign up to get free protection for your applications and to get access to all the features.
data/LICENSE ADDED
@@ -0,0 +1,166 @@
1
+ GNU LESSER GENERAL PUBLIC LICENSE
2
+ Version 3, 29 June 2007
3
+
4
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
5
+ Everyone is permitted to copy and distribute verbatim copies
6
+ of this license document, but changing it is not allowed.
7
+
8
+
9
+ This version of the GNU Lesser General Public License incorporates
10
+ the terms and conditions of version 3 of the GNU General Public
11
+ License, supplemented by the additional permissions listed below.
12
+
13
+ 0. Additional Definitions.
14
+
15
+ As used herein, "this License" refers to version 3 of the GNU Lesser
16
+ General Public License, and the "GNU GPL" refers to version 3 of the GNU
17
+ General Public License.
18
+
19
+ "The Library" refers to a covered work governed by this License,
20
+ other than an Application or a Combined Work as defined below.
21
+
22
+ An "Application" is any work that makes use of an interface provided
23
+ by the Library, but which is not otherwise based on the Library.
24
+ Defining a subclass of a class defined by the Library is deemed a mode
25
+ of using an interface provided by the Library.
26
+
27
+ A "Combined Work" is a work produced by combining or linking an
28
+ Application with the Library. The particular version of the Library
29
+ with which the Combined Work was made is also called the "Linked
30
+ Version".
31
+
32
+ The "Minimal Corresponding Source" for a Combined Work means the
33
+ Corresponding Source for the Combined Work, excluding any source code
34
+ for portions of the Combined Work that, considered in isolation, are
35
+ based on the Application, and not on the Linked Version.
36
+
37
+ The "Corresponding Application Code" for a Combined Work means the
38
+ object code and/or source code for the Application, including any data
39
+ and utility programs needed for reproducing the Combined Work from the
40
+ Application, but excluding the System Libraries of the Combined Work.
41
+
42
+ 1. Exception to Section 3 of the GNU GPL.
43
+
44
+ You may convey a covered work under sections 3 and 4 of this License
45
+ without being bound by section 3 of the GNU GPL.
46
+
47
+ 2. Conveying Modified Versions.
48
+
49
+ If you modify a copy of the Library, and, in your modifications, a
50
+ facility refers to a function or data to be supplied by an Application
51
+ that uses the facility (other than as an argument passed when the
52
+ facility is invoked), then you may convey a copy of the modified
53
+ version:
54
+
55
+ a) under this License, provided that you make a good faith effort to
56
+ ensure that, in the event an Application does not supply the
57
+ function or data, the facility still operates, and performs
58
+ whatever part of its purpose remains meaningful, or
59
+
60
+ b) under the GNU GPL, with none of the additional permissions of
61
+ this License applicable to that copy.
62
+
63
+ 3. Object Code Incorporating Material from Library Header Files.
64
+
65
+ The object code form of an Application may incorporate material from
66
+ a header file that is part of the Library. You may convey such object
67
+ code under terms of your choice, provided that, if the incorporated
68
+ material is not limited to numerical parameters, data structure
69
+ layouts and accessors, or small macros, inline functions and templates
70
+ (ten or fewer lines in length), you do both of the following:
71
+
72
+ a) Give prominent notice with each copy of the object code that the
73
+ Library is used in it and that the Library and its use are
74
+ covered by this License.
75
+
76
+ b) Accompany the object code with a copy of the GNU GPL and this license
77
+ document.
78
+
79
+ 4. Combined Works.
80
+
81
+ You may convey a Combined Work under terms of your choice that,
82
+ taken together, effectively do not restrict modification of the
83
+ portions of the Library contained in the Combined Work and reverse
84
+ engineering for debugging such modifications, if you also do each of
85
+ the following:
86
+
87
+ a) Give prominent notice with each copy of the Combined Work that
88
+ the Library is used in it and that the Library and its use are
89
+ covered by this License.
90
+
91
+ b) Accompany the Combined Work with a copy of the GNU GPL and this license
92
+ document.
93
+
94
+ c) For a Combined Work that displays copyright notices during
95
+ execution, include the copyright notice for the Library among
96
+ these notices, as well as a reference directing the user to the
97
+ copies of the GNU GPL and this license document.
98
+
99
+ d) Do one of the following:
100
+
101
+ 0) Convey the Minimal Corresponding Source under the terms of this
102
+ License, and the Corresponding Application Code in a form
103
+ suitable for, and under terms that permit, the user to
104
+ recombine or relink the Application with a modified version of
105
+ the Linked Version to produce a modified Combined Work, in the
106
+ manner specified by section 6 of the GNU GPL for conveying
107
+ Corresponding Source.
108
+
109
+ 1) Use a suitable shared library mechanism for linking with the
110
+ Library. A suitable mechanism is one that (a) uses at run time
111
+ a copy of the Library already present on the user's computer
112
+ system, and (b) will operate properly with a modified version
113
+ of the Library that is interface-compatible with the Linked
114
+ Version.
115
+
116
+ e) Provide Installation Information, but only if you would otherwise
117
+ be required to provide such information under section 6 of the
118
+ GNU GPL, and only to the extent that such information is
119
+ necessary to install and execute a modified version of the
120
+ Combined Work produced by recombining or relinking the
121
+ Application with a modified version of the Linked Version. (If
122
+ you use option 4d0, the Installation Information must accompany
123
+ the Minimal Corresponding Source and Corresponding Application
124
+ Code. If you use option 4d1, you must provide the Installation
125
+ Information in the manner specified by section 6 of the GNU GPL
126
+ for conveying Corresponding Source.)
127
+
128
+ 5. Combined Libraries.
129
+
130
+ You may place library facilities that are a work based on the
131
+ Library side by side in a single library together with other library
132
+ facilities that are not Applications and are not covered by this
133
+ License, and convey such a combined library under terms of your
134
+ choice, if you do both of the following:
135
+
136
+ a) Accompany the combined library with a copy of the same work based
137
+ on the Library, uncombined with any other library facilities,
138
+ conveyed under the terms of this License.
139
+
140
+ b) Give prominent notice with the combined library that part of it
141
+ is a work based on the Library, and explaining where to find the
142
+ accompanying uncombined form of the same work.
143
+
144
+ 6. Revised Versions of the GNU Lesser General Public License.
145
+
146
+ The Free Software Foundation may publish revised and/or new versions
147
+ of the GNU Lesser General Public License from time to time. Such new
148
+ versions will be similar in spirit to the present version, but may
149
+ differ in detail to address new problems or concerns.
150
+
151
+ Each version is given a distinguishing version number. If the
152
+ Library as you received it specifies that a certain numbered version
153
+ of the GNU Lesser General Public License "or any later version"
154
+ applies to it, you have the option of following the terms and
155
+ conditions either of that published version or of any later version
156
+ published by the Free Software Foundation. If the Library as you
157
+ received it does not specify a version number of the GNU Lesser
158
+ General Public License, you may choose any version of the GNU Lesser
159
+ General Public License ever published by the Free Software Foundation.
160
+
161
+ If the Library as you received it specifies that a proxy can decide
162
+ whether future versions of the GNU Lesser General Public License shall
163
+ apply, that proxy's public statement of acceptance of any version is
164
+ permanent authorization for you to choose that version for the
165
+ Library.
166
+
@@ -0,0 +1,260 @@
1
+ # Visibility.js – sugar for Page Visibility API
2
+
3
+ Visibility.js allow you to know, that your web page is visible to the user or
4
+ hidden in background tab or prerendering. It allow you to depend JS logic on
5
+ page visibility state and save browser performance (disable unnecessary timers
6
+ and AJAX requests) or create careful UI (for example, you can stop video or
7
+ slideshow, when user switch tab to answer for urgent email).
8
+
9
+ Also you can detect, that browser just [prerendering] page, and don’t count
10
+ visitor (before user will not really click on estimated link) or run heavy
11
+ calculations (which can disable prerendering).
12
+
13
+ This library is wrap under [Page Visibility API]. It fix problems with different
14
+ vendor prefixes and add high-level useful functions.
15
+
16
+ You don’t need to check Page Visibility API support in browser for common cases,
17
+ because library without API support will just assume, that page is always
18
+ visible and your logic will be work correctly.
19
+
20
+ [Page Visibility API]: http://www.w3.org/TR/2011/WD-page-visibility-20110602/
21
+ [prerendering]: http://code.google.com/chrome/whitepapers/prerender.html
22
+
23
+ ## States
24
+
25
+ Now Page Visibility API support 3 visibility states:
26
+
27
+ * `visible` – user open page and work with it.
28
+ * `hidden` – user switch to another tab or minimize browser window.
29
+ * `prerender` – browser just prerendering estimated next page to
30
+ instantly open it.
31
+
32
+ ## Timers
33
+
34
+ The main user case is to run some timers only, when content is visible to user.
35
+ For example, show countdown animation.
36
+
37
+ `Visibility.every(interval, callback)` is a analog of
38
+ `setInterval(callback, interval)`, but call `callback` every `interval` ms only
39
+ if page is visible. For example, let create countdown:
40
+
41
+ ```js
42
+ Visibility.every(1000, function() {
43
+ updateCountdownAnimation();
44
+ });
45
+ ```
46
+
47
+ You can set in second argument another interval, which will be used, when page
48
+ is hidden. For example, lets check inbox updates every 1 minute for visible
49
+ page and every 5 minutes for hidden:
50
+
51
+ ```js
52
+ var minute = 60 * 1000;
53
+ Visibility.every(minute, 5 * minute, function() {
54
+ checkNewMails();
55
+ });
56
+ ```
57
+
58
+ Note, that callback will be execute also on every state changing from hidden to
59
+ visible (to update old content).
60
+
61
+ You can add some really useful syntax sugar for interval formats, if you include
62
+ [jQuery Chrono plugin] *before* Visibility.js:
63
+
64
+ ```js
65
+ Visibility.every('minute', '5 minutes', function() {
66
+ checkNewMails();
67
+ });
68
+ ```
69
+
70
+ `Visibility.every` return timer ID. It is **not** same ID, that return
71
+ `clearInterval`, so you must use only `Visibility.stop(id)` to stop timer:
72
+
73
+ ```js
74
+ slideshow = Visibility.every(5 * 1000, function() {
75
+ changeSlide();
76
+ });
77
+
78
+ $('.stopSlideshow').click(function() {
79
+ Visibility.stop(slideshow);
80
+ });
81
+ ```
82
+
83
+ If browser doesn’t support Page Visibility API, `Visibility.every` will be
84
+ just full analog of `setInterval` and just run `callback` every `interval` ms
85
+ for visible and hidden pages.
86
+
87
+ [jQuery Chrono plugin]: https://github.com/avk/jQuery-Chrono
88
+
89
+ ## Initializers
90
+
91
+ Another common user case is when we need to check visibility state and wait for
92
+ some value.
93
+
94
+ ### Wait until state will be visible
95
+
96
+ `Visibility.onVisible(callback)` check current state. If it visible now, it
97
+ will run `callback`, else it will wait until state changes to visible and then
98
+ run `callback`.
99
+
100
+ For example, lets show new notification animation only when page is visible
101
+ (so if user open page directly in background tab, animation will be wait until
102
+ user open tab):
103
+
104
+ ```js
105
+ Visibility.onVisible(function() {
106
+ Notification.animateNotice("Hello");
107
+ });
108
+ ```
109
+
110
+ If browser doesn’t support Page Visibility API, `Visibility.onVisible` will run
111
+ `callback` at once.
112
+
113
+ ### Wait until state will be not prerender
114
+
115
+ Web developer can say by Prerender API, that user is likely to open next link
116
+ (for example, when a user is reading a multi-page article). So browser will
117
+ fetch and render this link and when user click link, he will see content
118
+ instantly.
119
+
120
+ But when browser will prerendering page, you may decide that is really
121
+ (not probably) visitor. Also, browser will turn off prerendering, if you have
122
+ heavy computation or video/audio tags on page. So it will be better,
123
+ if your JS will not run some code in prerendering and wait until
124
+ user really open link.
125
+
126
+ You can use `Visibility.notPrerender(callback)` for this cases. For example,
127
+ lets count statistics only for real visitor, not for prerendering:
128
+
129
+ ```js
130
+ Visibility.notPrerender(function() {
131
+ Statistics.countVisitor();
132
+ });
133
+ ```
134
+
135
+ Or we can add audio and video tags or start heavy computation in
136
+ non-prerendering states.
137
+
138
+ If browser doesn’t support Page Visibility API, `Visibility.notPrerender` will
139
+ run `callback` at once.
140
+
141
+ ## Low-level tools
142
+
143
+ For some special cases you can need more low-level methods. For example, if you
144
+ want to count background and foreground time of page using.
145
+
146
+ `Visibility.support()` will return `true`, if browser support
147
+ Page Visibility API:
148
+
149
+ ```js
150
+ if ( Visibility.support() ) {
151
+ Statistics.startTrackingVisibility();
152
+ }
153
+ ```
154
+
155
+ `Visibility.state()` will return string with visibility state name. States can
156
+ be extend in future, so in common cases use more simpler and general
157
+ `Visibility.hidden()`, that will return `true`, if page is hidden by any reason.
158
+ For example, in prerendering `Visibility.state()` will return `"prerender"`, but
159
+ `Visibility.hidden()` will return `true`.
160
+
161
+ Lets collect in what state user open our page:
162
+
163
+ ```js
164
+ $(document).load(function () {
165
+
166
+ if ( 'hidden' == Visibility.state() ) {
167
+ Statistics.userOpenPageInBackgroundTab();
168
+ }
169
+ if ( 'prerender' == Visibility.state() ) {
170
+ Statistics.pageIsPrerendering();
171
+ }
172
+
173
+ });
174
+ ```
175
+
176
+ Or lets enable auto-playing only when page opening in current tab
177
+ (not, when user open page in background tab):
178
+
179
+ ```js
180
+ $(document).load(function () {
181
+
182
+ if ( !Visibility.hidden() ) {
183
+ VideoPlayer.play();
184
+ }
185
+
186
+ });
187
+ ```
188
+
189
+ By `Visibility.change(callback)` you can listen visibility state changing event.
190
+ First argument in callback will be event object, second will be state name.
191
+
192
+ Lets collect visibility changes to statistics, how user use our site:
193
+
194
+ ```js
195
+ Visibility.change(function(e, state) {
196
+ Statistics.visibilityChange(state);
197
+ });
198
+ ```
199
+
200
+ ## Install
201
+
202
+ ### Rails 3.1
203
+
204
+ In Rails 3.1 (or another project with Sprockets 2) just add `visibility` to
205
+ `Gemfile`:
206
+
207
+ ```ruby
208
+ gem 'visibility'
209
+ ```
210
+
211
+ and add require to `app/assets/javascripts/application.js.coffee`:
212
+
213
+ ```coffee
214
+ #= require "visibility"
215
+ ```
216
+
217
+ ### Jammit
218
+
219
+ If you use Jammit or another package manager just copy `lib/visibility.js` to
220
+ `public/javascripts/lib` in your project and add library to `config/assets.yml`:
221
+
222
+ ```yaml
223
+ javascripts:
224
+ application:
225
+ - public/javascripts/lib/visibility.js
226
+ ```
227
+
228
+ ### Other
229
+
230
+ If you didn’t use Rails 3.1 or assets packaging manager you can use already
231
+ minimized version of library at `lib/visibility.min.js`.
232
+
233
+ ## Contributing
234
+
235
+ To run project tests and minimize source you must have Ruby and Bundler.
236
+ For example, on Ubuntu:
237
+
238
+ ```
239
+ sudo apt-get install ruby rubygems
240
+ sudo gem install bundler
241
+ ```
242
+
243
+ Next you need install Jasmine, UglifyJS and other dependencies by Bundler.
244
+ Run in project root:
245
+
246
+ ```
247
+ bundle install --path=.bundle
248
+ ```
249
+
250
+ That’s all. To run tests, start server and open <http://localhost:8888/>:
251
+
252
+ ```
253
+ bundle exec rake server
254
+ ```
255
+
256
+ Before commit minimize project source:
257
+
258
+ ```
259
+ bundle exec rake min
260
+ ```
@@ -0,0 +1,382 @@
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
+ // Link to document object to change it in tests.
33
+ _doc: window.document,
34
+
35
+ // Vendor prefixes to create event and properties names.
36
+ _prefixes: ['webkit', 'moz', 'o', 'ms'],
37
+
38
+ // Vendor prefix cached by `_prefix` function.
39
+ _chechedPrefix: null,
40
+
41
+ // Is listener for `visibilitychange` event is already added
42
+ // by `_setListener` method.
43
+ _listening: false,
44
+
45
+ // Callbacks from `change` method, that wait visibility changes.
46
+ _changeCallbacks: [],
47
+
48
+ // Callbacks from `onVisible` method, that wait when page become to be
49
+ // visible.
50
+ _onVisibleCallbacks: [],
51
+
52
+ // Callbacks from `notPrerender` method, that wait when visibility state
53
+ // change from “prerender”.
54
+ _notPrerenderCallbacks: [],
55
+
56
+ // Last timer number.
57
+ _lastTimer: 0,
58
+
59
+ // Callbacks and intervals added by `every` method.
60
+ _timers: { },
61
+
62
+ // Variable to check hidden-visible state changes.
63
+ _hiddenBefore: false,
64
+
65
+ // Initialize variables on page loading.
66
+ _init: function () {
67
+ this._hiddenBefore = this.hidden();
68
+
69
+ if ( defined(window.jQuery) && defined(jQuery.every) ) {
70
+ this._setInterval = this._chronoSetInterval;
71
+ } else {
72
+ this._setInterval = this._originalSetInterval;
73
+ }
74
+ },
75
+
76
+ // Detect vendor prefix and return it.
77
+ _prefix: function () {
78
+ if ( null !== this._chechedPrefix ) {
79
+ return this._chechedPrefix;
80
+ }
81
+ if ( defined(this._doc.visibilityState) ) {
82
+ return this._chechedPrefix = '';
83
+ }
84
+ var name;
85
+ for ( var i = 0; i < this._prefixes.length; i++ ) {
86
+ name = this._prefixes[i] + 'VisibilityState';
87
+ if ( defined(this._doc[name]) ) {
88
+ return this._chechedPrefix = this._prefixes[i];
89
+ }
90
+ }
91
+ },
92
+
93
+ // Return property name with vendor prefix.
94
+ _name: function (name) {
95
+ var prefix = this._prefix();
96
+ if ( '' == prefix ) {
97
+ return name;
98
+ } else {
99
+ return prefix +
100
+ name.substr(0, 1).toUpperCase() + name.substr(1);
101
+ }
102
+ },
103
+
104
+ // Return document’s property value with name with vendor prefix.
105
+ _prop: function (name) {
106
+ return this._doc[this._name(name)]
107
+ },
108
+
109
+ // Listener for `visibilitychange` event.
110
+ _onVisibilityChange: function(event) {
111
+ var isHidden = this.hidden(),
112
+ state = this.state();
113
+
114
+ for ( var i = 0; i < this._changeCallbacks.length; i++ ) {
115
+ this._changeCallbacks[i].call(this._doc, event, state);
116
+ }
117
+
118
+ var hiddenBefore = this._hiddenBefore;
119
+ if ( (isHidden && !hiddenBefore) || (!isHidden && hiddenBefore) ) {
120
+ for ( i in this._timers ) {
121
+ this._stopTimer(i);
122
+ this._runTimer(i, !isHidden);
123
+ }
124
+ }
125
+
126
+ if ( !isHidden ) {
127
+ for ( var i = 0; i < this._onVisibleCallbacks.length; i++ ) {
128
+ this._onVisibleCallbacks[i]();
129
+ }
130
+ this._onVisibleCallbacks = [];
131
+ }
132
+
133
+ if ( 'prerender' != this.state() ) {
134
+ for ( var i = 0; i < this._notPrerenderCallbacks.length; i++ ) {
135
+ this._notPrerenderCallbacks[i]();
136
+ }
137
+ this._notPrerenderCallbacks = [];
138
+ }
139
+
140
+ this._hiddenBefore = isHidden;
141
+ },
142
+
143
+ // Set listener for `visibilitychange` event.
144
+ _setListener: function () {
145
+ if ( this._listening ) {
146
+ return;
147
+ }
148
+ var event = this._prefix() + 'visibilitychange';
149
+ this._doc.addEventListener(event, function () {
150
+ Visibility._onVisibilityChange.apply(Visibility, arguments);
151
+ }, false);
152
+ this._listening = true;
153
+ this._hiddenBefore = this.hidden();
154
+ },
155
+
156
+ // Set interval directly by `setInterval` function without any syntax
157
+ // sugar.
158
+ _originalSetInterval: function (callback, interval) {
159
+ return setInterval(callback, interval);
160
+ },
161
+
162
+ // Set interval by jQuery Chrono plugin. Add syntax sugar to `interval`
163
+ // and `hiddenInterval` arguments, such as "1 second" and others.
164
+ //
165
+ // It will be automatically set to `_setInterval` on loading if
166
+ // you include jQuery Chrono plugin before Visibility.js.
167
+ _chronoSetInterval: function (callback, internal) {
168
+ return jQuery.every(internal, callback);
169
+ },
170
+
171
+ // Set interval by `setInterval`. Allow to change function for tests or
172
+ // syntax sugar in `interval` arguments.
173
+ //
174
+ // Function will be automatically set in `_init` method (which will be
175
+ // call on script loading). So you must include jQuery Chrono plugin
176
+ // before Visibility.js.
177
+ _setInterval: null,
178
+
179
+ // Try to run timer from every method by it’s ID. It will be use
180
+ // `interval` or `hiddenInterval` depending on visibility state.
181
+ // If page is hidden and `hiddenInterval` is null,
182
+ // it will not run timer.
183
+ //
184
+ // Argument `now` say, that timers must be execute now too.
185
+ _runTimer: function (id, now) {
186
+ var interval,
187
+ timer = this._timers[id];
188
+ if ( this.hidden() ) {
189
+ if ( null === timer.hiddenInterval ) {
190
+ return;
191
+ }
192
+ interval = timer.hiddenInterval;
193
+ } else {
194
+ interval = timer.interval;
195
+ }
196
+ if ( now ) {
197
+ timer.callback.call(window);
198
+ }
199
+ timer.intervalID = this._setInterval(timer.callback, interval);
200
+ },
201
+
202
+ // Stop timer from `every` method by it's ID.
203
+ _stopTimer: function (id) {
204
+ var timer = this._timers[id];
205
+ clearInterval(timer.intervalID);
206
+ delete timer.intervalID;
207
+ },
208
+
209
+ // Return true if browser support Page Visibility API.
210
+ //
211
+ // if ( Visibility.support() ) {
212
+ // Statistics.startTrackingVisibility();
213
+ // Visibility.change(function(e, state)) {
214
+ // Statistics.trackVisibility(state);
215
+ // });
216
+ // }
217
+ support: function () {
218
+ return defined(this._prefix());
219
+ },
220
+
221
+ // Return true if page now isn’t visible to user.
222
+ //
223
+ // if ( !Visibility.hidden() ) {
224
+ // VideoPlayer.play();
225
+ // }
226
+ //
227
+ // It is just proxy to `document.hidden`, but use vendor prefix.
228
+ hidden: function () {
229
+ if ( !this.support() ) {
230
+ return false;
231
+ }
232
+ return this._prop('hidden');
233
+ },
234
+
235
+ // Return visibility state: 'visible', 'hidden' or 'prerender'.
236
+ //
237
+ // if ( 'prerender' == Visibility.state() ) {
238
+ // Statistics.pageIsPrerendering();
239
+ // }
240
+ //
241
+ // Don’t use `Visibility.state()` to detect, is page visible, because
242
+ // visibility states can extend in next API versions.
243
+ // Use more simpler and general `Visibility.hidden()` for this cases.
244
+ //
245
+ // It is just proxy to `document.visibilityState`, but use
246
+ // vendor prefix.
247
+ state: function () {
248
+ if ( !this.support() ) {
249
+ return 'visible';
250
+ }
251
+ return this._prop('visibilityState');
252
+ },
253
+
254
+ // Call callback when visibility will be changed. First argument for
255
+ // callback will be original event object, second will be visibility
256
+ // state name.
257
+ //
258
+ // If Page Visibility API doesn’t supported method will be return false
259
+ // and callback never will be called.
260
+ //
261
+ // Visibility.change(function(e, state) {
262
+ // Statistics.visibilityChange(state);
263
+ // });
264
+ //
265
+ // It is just proxy to `visibilitychange` event, but use vendor prefix.
266
+ change: function (callback) {
267
+ if ( !this.support() ) {
268
+ return false;
269
+ }
270
+ this._changeCallbacks.push(callback);
271
+ this._setListener();
272
+ return true;
273
+ },
274
+
275
+ // Call callback only when page become to visible for user or
276
+ // call it now if page is visible now or Page Visibility API
277
+ // doesn’t supported.
278
+ //
279
+ // Return true if callback if called now.
280
+ //
281
+ // Visibility.onVisible(function() {
282
+ // Notification.animateNotice("Hello");
283
+ // });
284
+ onVisible: function (callback) {
285
+ if ( !this.support() || !this.hidden() ) {
286
+ callback();
287
+ return true;
288
+ }
289
+ this._onVisibleCallbacks.push(callback);
290
+ this._setListener();
291
+ },
292
+
293
+ // Call `callback` in any state, expect “prerender”. If current state
294
+ // is “prerender” it will wait until state will be changed.
295
+ // If Page Visibility API doesn’t supported, it will call `callback`
296
+ // immediately.
297
+ //
298
+ // Visibility.notPrerender(function() {
299
+ // Statistics.countVisitor();
300
+ // });
301
+ notPrerender: function (callback) {
302
+ if ( !this.support() || 'prerender' != this.state() ) {
303
+ callback();
304
+ return true;
305
+ }
306
+ this._notPrerenderCallbacks.push(callback);
307
+ this._setListener();
308
+ },
309
+
310
+ // Run callback every `interval` milliseconds if page is visible and
311
+ // every `hiddenInterval` milliseconds if page is hidden.
312
+ //
313
+ // Visibility.every(60 * 1000, 5 * 60 * 1000, function() {
314
+ // checkNewMails();
315
+ // });
316
+ //
317
+ // You can skip `hiddenInterval` and callback will be called only if
318
+ // page is visible.
319
+ //
320
+ // Visibility.every(1000, function() {
321
+ // updateCountdown();
322
+ // });
323
+ //
324
+ // It is analog of `setInterval(callback, interval)` but use visibility
325
+ // state.
326
+ //
327
+ // It return timer ID, that you can use in `Visibility.stop(id)` to stop
328
+ // timer (`clearInterval` analog).
329
+ // Warning: timer ID is different from intervalID from `setInterval`,
330
+ // so don't use it in `clearInterval`.
331
+ //
332
+ // On change state from hidden to visible timers will be execute.
333
+ //
334
+ // If you include jQuery Chrono plugin before Visibility.js, you could
335
+ // use Chrono’s syntax sugar in interval arguments:
336
+ //
337
+ // Visibility.every('second', function() {
338
+ // updateCountdown();
339
+ // });
340
+ // Visibility.every('1 minute', '5 minutes', function() {
341
+ // checkNewMails();
342
+ // });
343
+ every: function (interval, hiddenInterval, callback) {
344
+ if ( !defined(callback) ) {
345
+ callback = hiddenInterval;
346
+ hiddenInterval = null;
347
+ }
348
+ this._lastTimer += 1;
349
+ var number = this._lastTimer;
350
+ this._timers[number] = ({
351
+ interval: interval,
352
+ hiddenInterval: hiddenInterval,
353
+ callback: callback
354
+ });
355
+ this._runTimer(number, false);
356
+ this._setListener();
357
+ return number;
358
+ },
359
+
360
+ // Stop timer from `every` method by it ID (`every` method return it).
361
+ //
362
+ // slideshow = Visibility.every(5 * 1000, function() {
363
+ // changeSlide();
364
+ // });
365
+ // $('.stopSlideshow').click(function() {
366
+ // Visibility.stop(slideshow);
367
+ // });
368
+ stop: function(id) {
369
+ var timer = this._timers[id]
370
+ if ( !defined(timer) ) {
371
+ return false;
372
+ }
373
+ this._stopTimer(id);
374
+ delete this._timers[id];
375
+ return timer;
376
+ }
377
+
378
+ };
379
+
380
+ Visibility._init();
381
+
382
+ })();
metadata ADDED
@@ -0,0 +1,87 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: visibility
3
+ version: !ruby/object:Gem::Version
4
+ hash: 9
5
+ prerelease: false
6
+ segments:
7
+ - 0
8
+ - 1
9
+ version: "0.1"
10
+ platform: ruby
11
+ authors:
12
+ - "Andrey \xE2\x80\x9CA.I.\xE2\x80\x9D Sitnik"
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2011-06-20 00:00:00 +04:00
18
+ default_executable:
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ prerelease: false
22
+ version_requirements: &id001 !ruby/object:Gem::Requirement
23
+ none: false
24
+ requirements:
25
+ - - ">="
26
+ - !ruby/object:Gem::Version
27
+ hash: 62196457
28
+ segments:
29
+ - 2
30
+ - 0
31
+ - 0
32
+ - beta
33
+ - 5
34
+ version: 2.0.0.beta.5
35
+ requirement: *id001
36
+ type: :runtime
37
+ name: sprockets
38
+ description: Visibility.js allow you to depend JS logic on page visibility state and save browser performance or create careful UI.
39
+ email:
40
+ - andrey@sitnik.ru
41
+ executables: []
42
+
43
+ extensions: []
44
+
45
+ extra_rdoc_files:
46
+ - LICENSE
47
+ - README.md
48
+ files:
49
+ - vendor/assets/javascripts/visibility.js
50
+ - LICENSE
51
+ - README.md
52
+ has_rdoc: true
53
+ homepage: https://github.com/evilmartians/visibility.js
54
+ licenses: []
55
+
56
+ post_install_message:
57
+ rdoc_options: []
58
+
59
+ require_paths:
60
+ - lib
61
+ required_ruby_version: !ruby/object:Gem::Requirement
62
+ none: false
63
+ requirements:
64
+ - - ">="
65
+ - !ruby/object:Gem::Version
66
+ hash: 3
67
+ segments:
68
+ - 0
69
+ version: "0"
70
+ required_rubygems_version: !ruby/object:Gem::Requirement
71
+ none: false
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ hash: 3
76
+ segments:
77
+ - 0
78
+ version: "0"
79
+ requirements: []
80
+
81
+ rubyforge_project:
82
+ rubygems_version: 1.3.7
83
+ signing_key:
84
+ specification_version: 3
85
+ summary: Visibility.js allow you to know, that your web page is visible to the user or hidden in background tab or prerendering.
86
+ test_files: []
87
+