mirror of
https://github.com/the-djmaze/snappymail.git
synced 2026-07-13 03:27:39 +03:00
Simple prefetch functionality (ifvisible.js)
config: [labs] allow_prefetch
This commit is contained in:
parent
b7e135a553
commit
38672e1672
18 changed files with 988 additions and 28 deletions
|
|
@ -53,6 +53,7 @@
|
|||
"ko" : true,
|
||||
"ssm" : true,
|
||||
"moment" : true,
|
||||
"ifvisible" : true,
|
||||
"crossroads" : true,
|
||||
"hasher" : true,
|
||||
"Jua" : true,
|
||||
|
|
|
|||
14
Gruntfile.js
14
Gruntfile.js
|
|
@ -45,6 +45,14 @@ module.exports = function (grunt) {
|
|||
src: 'vendors/jquery-cookie/jquery.cookie.js',
|
||||
dest: 'vendors/jquery-cookie/jquery.cookie-1.4.0.min.js'
|
||||
},
|
||||
ifvisible: {
|
||||
options: {
|
||||
banner: '/*!ifvisible.js v1.0.0 (c) 2013 Serkan Yersen | MIT */\n',
|
||||
preserveComments: 'false'
|
||||
},
|
||||
src: 'vendors/ifvisible/src/ifvisible.js',
|
||||
dest: 'vendors/ifvisible/ifvisible.min.js'
|
||||
},
|
||||
wakeup: {
|
||||
options: {
|
||||
banner: '/*! jQuery WakeUp plugin (c) 2013 Paul Okopny <paul.okopny@gmail.com> | MIT */\n',
|
||||
|
|
@ -130,6 +138,7 @@ module.exports = function (grunt) {
|
|||
"vendors/knockout-projections/knockout-projections-1.0.0.min.js",
|
||||
"vendors/ssm/ssm.min.js",
|
||||
"vendors/jua/jua.min.js",
|
||||
"vendors/ifvisible/ifvisible.min.js",
|
||||
"vendors/jquery-magnific-popup/jquery.magnific-popup.min.js",
|
||||
"vendors/bootstrap/js/bootstrap.min.js",
|
||||
"dev/Common/_LibsEnd.js"
|
||||
|
|
@ -217,8 +226,8 @@ module.exports = function (grunt) {
|
|||
options: {
|
||||
stripBanners: true,
|
||||
banner: '/*! RainLoop Webmail Main Module (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */\n' +
|
||||
'(function (window, $, ko, crossroads, hasher, moment, Jua, _) {\n',
|
||||
footer: '\n\n}(window, jQuery, ko, crossroads, hasher, moment, Jua, _));'
|
||||
'(function (window, $, ko, crossroads, hasher, moment, Jua, _, ifvisible) {\n',
|
||||
footer: '\n\n}(window, jQuery, ko, crossroads, hasher, moment, Jua, _, ifvisible));'
|
||||
},
|
||||
src: [
|
||||
"dev/Common/_Begin.js",
|
||||
|
|
@ -445,6 +454,7 @@ module.exports = function (grunt) {
|
|||
grunt.registerTask('cookie', ['uglify:cookie']);
|
||||
grunt.registerTask('mousewheel', ['uglify:mousewheel']);
|
||||
grunt.registerTask('inputosaurus', ['uglify:inputosaurus']);
|
||||
grunt.registerTask('ifvisible', ['uglify:ifvisible']);
|
||||
// ---
|
||||
|
||||
grunt.registerTask('default', ['less', 'concat', 'cssmin', 'jshint', 'rlmin']);
|
||||
|
|
|
|||
|
|
@ -17,8 +17,6 @@ function MessageModel()
|
|||
this.toEmailsString = ko.observable('');
|
||||
this.senderEmailsString = ko.observable('');
|
||||
|
||||
this.prefetched = false;
|
||||
|
||||
this.emails = [];
|
||||
|
||||
this.from = [];
|
||||
|
|
@ -228,8 +226,6 @@ MessageModel.prototype.clear = function ()
|
|||
this.toEmailsString('');
|
||||
this.senderEmailsString('');
|
||||
|
||||
this.prefetched = false;
|
||||
|
||||
this.emails = [];
|
||||
|
||||
this.from = [];
|
||||
|
|
@ -299,8 +295,6 @@ MessageModel.prototype.initByJson = function (oJsonMessage)
|
|||
this.uid = oJsonMessage.Uid;
|
||||
this.requestHash = oJsonMessage.RequestHash;
|
||||
|
||||
this.prefetched = false;
|
||||
|
||||
this.size(Utils.pInt(oJsonMessage.Size));
|
||||
|
||||
this.from = MessageModel.initEmailsFromJson(oJsonMessage.From);
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ function AdminLoginViewModel()
|
|||
|
||||
RL.remote().adminLogin(_.bind(function (sResult, oData) {
|
||||
|
||||
if (Enums.StorageResultType.Success === sResult && oData&& 'AdminLogin' === oData.Action)
|
||||
if (Enums.StorageResultType.Success === sResult && oData && 'AdminLogin' === oData.Action)
|
||||
{
|
||||
if (oData.Result)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ function MailBoxMessageListViewModel()
|
|||
KnoinAbstractViewModel.call(this, 'Right', 'MailMessageList');
|
||||
|
||||
this.sLastUid = null;
|
||||
this.bPrefetch = false;
|
||||
this.emptySubjectValue = '';
|
||||
|
||||
var oData = RL.data();
|
||||
|
|
@ -796,6 +797,51 @@ MailBoxMessageListViewModel.prototype.onBuild = function (oDom)
|
|||
}, this).extend({'notify': 'always'});
|
||||
|
||||
this.initUploaderForAppend();
|
||||
|
||||
if (!Globals.bMobileDevice && !!RL.settingsGet('AllowPrefetch') && ifvisible)
|
||||
{
|
||||
ifvisible.setIdleDuration(10);
|
||||
|
||||
ifvisible.idle(function () {
|
||||
self.prefetchNextTick();
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
MailBoxMessageListViewModel.prototype.prefetchNextTick = function ()
|
||||
{
|
||||
if (!this.bPrefetch && !ifvisible.now() && this.viewModelVisibility())
|
||||
{
|
||||
var
|
||||
self = this,
|
||||
oCache = RL.cache(),
|
||||
oMessage = _.find(this.messageList(), function (oMessage) {
|
||||
return oMessage &&
|
||||
!oCache.hasRequestedMessage(oMessage.folderFullNameRaw, oMessage.uid);
|
||||
})
|
||||
;
|
||||
|
||||
if (oMessage)
|
||||
{
|
||||
this.bPrefetch = true;
|
||||
|
||||
RL.cache().addRequestedMessage(oMessage.folderFullNameRaw, oMessage.uid);
|
||||
|
||||
RL.remote().message(function (sResult, oData) {
|
||||
|
||||
var bNext = !!(Enums.StorageResultType.Success === sResult && oData && oData.Result);
|
||||
|
||||
_.delay(function () {
|
||||
self.bPrefetch = false;
|
||||
if (bNext)
|
||||
{
|
||||
self.prefetchNextTick();
|
||||
}
|
||||
}, 1000);
|
||||
|
||||
}, oMessage.folderFullNameRaw, oMessage.uid);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
MailBoxMessageListViewModel.prototype.composeClick = function ()
|
||||
|
|
|
|||
|
|
@ -909,6 +909,7 @@ class Actions
|
|||
'AllowAdditionalAccounts' => (bool) $oConfig->Get('webmail', 'allow_additional_accounts', true),
|
||||
'AllowIdentities' => (bool) $oConfig->Get('webmail', 'allow_identities', true),
|
||||
'DetermineUserLanguage' => (bool) $oConfig->Get('labs', 'determine_user_language', false),
|
||||
'AllowPrefetch' => (bool) $oConfig->Get('labs', 'allow_prefetch', true),
|
||||
'AllowCustomLogin' => (bool) $oConfig->Get('login', 'allow_custom_login', false),
|
||||
'LoginDefaultDomain' => $oConfig->Get('login', 'default_domain', ''),
|
||||
'AllowThemes' => (bool) $oConfig->Get('webmail', 'allow_themes', true),
|
||||
|
|
|
|||
|
|
@ -229,6 +229,7 @@ Enables caching in the system'),
|
|||
'imap_forwarded_flag' => array('$Forwarded'),
|
||||
'imap_read_receipt_flag' => array('$ReadReceipt'),
|
||||
'smtp_show_server_errors' => array(false),
|
||||
'allow_prefetch' => array(true),
|
||||
'autocreate_system_folders' => array(true),
|
||||
'repo_type' => array('stable'),
|
||||
'custom_repo' => array(''),
|
||||
|
|
|
|||
|
|
@ -1153,7 +1153,7 @@ Utils.log = function (sDesc)
|
|||
|
||||
/**
|
||||
* @param {number} iCode
|
||||
* @param {ыекштп=} mMessage = ''
|
||||
* @param {*=} mMessage = ''
|
||||
* @return {string}
|
||||
*/
|
||||
Utils.getNotification = function (iCode, mMessage)
|
||||
|
|
@ -5139,7 +5139,7 @@ function AdminLoginViewModel()
|
|||
|
||||
RL.remote().adminLogin(_.bind(function (sResult, oData) {
|
||||
|
||||
if (Enums.StorageResultType.Success === sResult && oData&& 'AdminLogin' === oData.Action)
|
||||
if (Enums.StorageResultType.Success === sResult && oData && 'AdminLogin' === oData.Action)
|
||||
{
|
||||
if (oData.Result)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*! RainLoop Webmail Main Module (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */
|
||||
(function (window, $, ko, crossroads, hasher, moment, Jua, _) {
|
||||
(function (window, $, ko, crossroads, hasher, moment, Jua, _, ifvisible) {
|
||||
|
||||
'use strict';
|
||||
|
||||
|
|
@ -1153,7 +1153,7 @@ Utils.log = function (sDesc)
|
|||
|
||||
/**
|
||||
* @param {number} iCode
|
||||
* @param {ыекштп=} mMessage = ''
|
||||
* @param {*=} mMessage = ''
|
||||
* @return {string}
|
||||
*/
|
||||
Utils.getNotification = function (iCode, mMessage)
|
||||
|
|
@ -6328,8 +6328,6 @@ function MessageModel()
|
|||
this.toEmailsString = ko.observable('');
|
||||
this.senderEmailsString = ko.observable('');
|
||||
|
||||
this.prefetched = false;
|
||||
|
||||
this.emails = [];
|
||||
|
||||
this.from = [];
|
||||
|
|
@ -6539,8 +6537,6 @@ MessageModel.prototype.clear = function ()
|
|||
this.toEmailsString('');
|
||||
this.senderEmailsString('');
|
||||
|
||||
this.prefetched = false;
|
||||
|
||||
this.emails = [];
|
||||
|
||||
this.from = [];
|
||||
|
|
@ -6610,8 +6606,6 @@ MessageModel.prototype.initByJson = function (oJsonMessage)
|
|||
this.uid = oJsonMessage.Uid;
|
||||
this.requestHash = oJsonMessage.RequestHash;
|
||||
|
||||
this.prefetched = false;
|
||||
|
||||
this.size(Utils.pInt(oJsonMessage.Size));
|
||||
|
||||
this.from = MessageModel.initEmailsFromJson(oJsonMessage.From);
|
||||
|
|
@ -11220,6 +11214,7 @@ function MailBoxMessageListViewModel()
|
|||
KnoinAbstractViewModel.call(this, 'Right', 'MailMessageList');
|
||||
|
||||
this.sLastUid = null;
|
||||
this.bPrefetch = false;
|
||||
this.emptySubjectValue = '';
|
||||
|
||||
var oData = RL.data();
|
||||
|
|
@ -12007,6 +12002,51 @@ MailBoxMessageListViewModel.prototype.onBuild = function (oDom)
|
|||
}, this).extend({'notify': 'always'});
|
||||
|
||||
this.initUploaderForAppend();
|
||||
|
||||
if (!Globals.bMobileDevice && !!RL.settingsGet('AllowPrefetch') && ifvisible)
|
||||
{
|
||||
ifvisible.setIdleDuration(10);
|
||||
|
||||
ifvisible.idle(function () {
|
||||
self.prefetchNextTick();
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
MailBoxMessageListViewModel.prototype.prefetchNextTick = function ()
|
||||
{
|
||||
if (!this.bPrefetch && !ifvisible.now() && this.viewModelVisibility())
|
||||
{
|
||||
var
|
||||
self = this,
|
||||
oCache = RL.cache(),
|
||||
oMessage = _.find(this.messageList(), function (oMessage) {
|
||||
return oMessage &&
|
||||
!oCache.hasRequestedMessage(oMessage.folderFullNameRaw, oMessage.uid);
|
||||
})
|
||||
;
|
||||
|
||||
if (oMessage)
|
||||
{
|
||||
this.bPrefetch = true;
|
||||
|
||||
RL.cache().addRequestedMessage(oMessage.folderFullNameRaw, oMessage.uid);
|
||||
|
||||
RL.remote().message(function (sResult, oData) {
|
||||
|
||||
var bNext = !!(Enums.StorageResultType.Success === sResult && oData && oData.Result);
|
||||
|
||||
_.delay(function () {
|
||||
self.bPrefetch = false;
|
||||
if (bNext)
|
||||
{
|
||||
self.prefetchNextTick();
|
||||
}
|
||||
}, 1000);
|
||||
|
||||
}, oMessage.folderFullNameRaw, oMessage.uid);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
MailBoxMessageListViewModel.prototype.composeClick = function ()
|
||||
|
|
@ -17509,4 +17549,4 @@ if (window.SimplePace) {
|
|||
window.SimplePace.add(10);
|
||||
}
|
||||
|
||||
}(window, jQuery, ko, crossroads, hasher, moment, Jua, _));
|
||||
}(window, jQuery, ko, crossroads, hasher, moment, Jua, _, ifvisible));
|
||||
16
rainloop/v/0.0.0/static/js/app.min.js
vendored
16
rainloop/v/0.0.0/static/js/app.min.js
vendored
File diff suppressed because one or more lines are too long
|
|
@ -224,6 +224,9 @@ this.j[c]=i,g.on("click",function(){var a=b.b.d("onDialog");a&&a()}).on("change"
|
|||
j.c=e;j.h=0;j.a={};j.m={};j.q=f;j.e=f;j.on=function(a,b){this.m[a]=b;return this};j.g=function(a,b){this.m[a]&&this.m[a].apply(f,b||[])};j.d=function(a){return this.m[a]||f};j.cancel=function(a){this.e.cancel(a)};j.p=function(){return B.p};j.v=function(a){this.c=!!a};j.k=function(){return this.e.k()};j.s=function(a){this.r(w(),a)};
|
||||
j.r=function(a,b){var c=this.d("onSelect");if(b&&(!c||h!==c(a,b))){this.e.t(a);var g=this.e.u,d=this.e;this.q.defer(function(){return g.apply(q(d)?f:d,Array.prototype.slice.call(arguments))},a,b)}else this.e.cancel(a)};l.Jua=B;
|
||||
|
||||
/*!ifvisible.js v1.0.0 (c) 2013 Serkan Yersen | MIT */
|
||||
(function(){"use strict";var a,b,c,d,e,f,g,h,i,j,k,l,m,n;i={},c=document,k=!1,l="active",g=6e4,f=!1,b=function(){var a,b,c,d,e,f;return a=function(){return(65536*(1+Math.random())|0).toString(16).substring(1)},e=function(){return a()+a()+"-"+a()+"-"+a()+"-"+a()+"-"+a()+a()+a()},f={},c="__ceGUID",b=function(a,b,d){return a[c]=void 0,a[c]||(a[c]="ifvisible.object.event.identifier"),f[a[c]]||(f[a[c]]={}),f[a[c]][b]||(f[a[c]][b]=[]),f[a[c]][b].push(d)},d=function(a,b,d){var e,g,h,i,j;if(a[c]&&f[a[c]]&&f[a[c]][b]){for(i=f[a[c]][b],j=[],g=0,h=i.length;h>g;g++)e=i[g],j.push(e(d||{}));return j}},{add:b,fire:d}}(),a=function(){var a;return a=!1,function(b,c,d){return a||(a=b.addEventListener?function(a,b,c){return a.addEventListener(b,c,!1)}:b.attachEvent?function(a,b,c){return a.attachEvent("on"+b,c,!1)}:function(a,b,c){return a["on"+b]=c}),a(b,c,d)}}(),d=function(a,b){var d;return c.createEventObject?a.fireEvent("on"+b,d):(d=c.createEvent("HTMLEvents"),d.initEvent(b,!0,!0),!a.dispatchEvent(d))},h=function(){var a,b,d,e,f;for(e=void 0,f=3,d=c.createElement("div"),a=d.getElementsByTagName("i"),b=function(){return d.innerHTML="<!--[if gt IE "+ ++f+"]><i></i><![endif]-->",a[0]};b(););return f>4?f:e}(),e=!1,n=void 0,"undefined"!=typeof c.hidden?(e="hidden",n="visibilitychange"):"undefined"!=typeof c.mozHidden?(e="mozHidden",n="mozvisibilitychange"):"undefined"!=typeof c.msHidden?(e="msHidden",n="msvisibilitychange"):"undefined"!=typeof c.webkitHidden&&(e="webkitHidden",n="webkitvisibilitychange"),m=function(){var b,d;return b=!1,d=function(){return clearTimeout(b),"active"!==l&&i.wakeup(),f=+new Date,b=setTimeout(function(){return"active"===l?i.idle():void 0},g)},d(),a(c,"mousemove",d),a(c,"keyup",d),a(window,"scroll",d),i.focus(d)},j=function(){var b;return k?!0:(e===!1?(b="blur",9>h&&(b="focusout"),a(window,b,function(){return i.blur()}),a(window,"focus",function(){return i.focus()})):a(c,n,function(){return c[e]?i.blur():i.focus()},!1),k=!0,m())},i={setIdleDuration:function(a){return g=1e3*a},getIdleDuration:function(){return g},getIdleInfo:function(){var a,b;return a=+new Date,b={},"idle"===l?(b.isIdle=!0,b.idleFor=a-f,b.timeLeft=0,b.timeLeftPer=100):(b.isIdle=!1,b.idleFor=a-f,b.timeLeft=f+g-a,b.timeLeftPer=(100-100*b.timeLeft/g).toFixed(2)),b},focus:function(a){return"function"==typeof a?this.on("focus",a):(l="active",b.fire(this,"focus"),b.fire(this,"wakeup"),b.fire(this,"statusChanged",{status:l}))},blur:function(a){return"function"==typeof a?this.on("blur",a):(l="hidden",b.fire(this,"blur"),b.fire(this,"idle"),b.fire(this,"statusChanged",{status:l}))},idle:function(a){return"function"==typeof a?this.on("idle",a):(l="idle",b.fire(this,"idle"),b.fire(this,"statusChanged",{status:l}))},wakeup:function(a){return"function"==typeof a?this.on("wakeup",a):(l="active",b.fire(this,"wakeup"),b.fire(this,"statusChanged",{status:l}))},on:function(a,c){return j(),b.add(this,a,c)},onEvery:function(a,b){var c;return j(),c=setInterval(function(){return"active"===l?b():void 0},1e3*a),{stop:function(){return clearInterval(c)},code:c,callback:b}},now:function(){return j(),"active"===l}},"function"==typeof define&&define.amd?define(function(){return i}):window.ifvisible=i}).call(this);
|
||||
|
||||
/*! Magnific Popup - v0.9.8 - 2013-10-26
|
||||
* http://dimsemenov.com/plugins/magnific-popup/
|
||||
* Copyright (c) 2013 Dmitry Semenov; MIT */
|
||||
|
|
|
|||
13
vendors/ifvisible/.jshintrc
vendored
Normal file
13
vendors/ifvisible/.jshintrc
vendored
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
{
|
||||
"boss": true,
|
||||
"undef": false,
|
||||
"white": false,
|
||||
"eqeqeq": false,
|
||||
"browser": true,
|
||||
"devel": true,
|
||||
"bitwise": false,
|
||||
"quotmark": false,
|
||||
"camelcase": false,
|
||||
"strict": false,
|
||||
"trailing": true
|
||||
}
|
||||
102
vendors/ifvisible/README.md
vendored
Normal file
102
vendors/ifvisible/README.md
vendored
Normal file
|
|
@ -0,0 +1,102 @@
|
|||
ifvisible.js
|
||||
------------
|
||||
|
||||
Crosbrowser & lightweight way to check if user is looking at the page or interacting with it.
|
||||
|
||||
#### Check out the [Demo](http://serkanyersen.github.com/ifvisible.js/demo.html) or read below for code example or Check [Annotated Sorce](http://serkanyersen.github.com/ifvisible.js/docs/ifvisible.html)
|
||||
|
||||
|
||||
## Installation
|
||||
From Bower
|
||||
```
|
||||
bower install ifvisible
|
||||
```
|
||||
|
||||
For Meteor
|
||||
```
|
||||
mrt add ifvisible
|
||||
```
|
||||
> meteor package is provided by [@frozeman](https://github.com/frozeman/meteor-ifvisible.js) via [Atmosphere](https://atmosphere.meteor.com/package/ifvisible)
|
||||
|
||||
## Examples
|
||||
|
||||
```javascript
|
||||
|
||||
// If page is visible right now
|
||||
if( ifvisible.now() ){
|
||||
// Display pop-up
|
||||
openPopUp();
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
Handle tab switch or browser minimize states
|
||||
|
||||
```javascript
|
||||
|
||||
ifvisible.on("blur", function(){
|
||||
// example code here..
|
||||
animations.pause();
|
||||
});
|
||||
|
||||
ifvisible.on("focus", function(){
|
||||
// resume all animations
|
||||
animations.resume();
|
||||
});
|
||||
|
||||
```
|
||||
|
||||
ifvisible.js can handle activity states too, such as being IDLE or ACTIVE on the page
|
||||
|
||||
```javascript
|
||||
|
||||
ifvisible.on("idle", function(){
|
||||
// Stop auto updating the live data
|
||||
stream.pause();
|
||||
});
|
||||
|
||||
ifvisible.on("wakeup", function(){
|
||||
// go back updating data
|
||||
stream.resume();
|
||||
});
|
||||
|
||||
```
|
||||
|
||||
Default idle duration is 60 seconds but you can change it with `setIdleDuration` method
|
||||
|
||||
```javascript
|
||||
|
||||
ifvisible.setIdleDuration(120); // Page will become idle after 120 seconds
|
||||
|
||||
```
|
||||
|
||||
You can manually trigger status events by calling them directly or you can set events with their names by giving first argument as a callback
|
||||
|
||||
```javascript
|
||||
|
||||
ifvisible.idle(); // will put page in a idle status
|
||||
|
||||
ifvisible.idle(function(){
|
||||
// This code will work when page goes into idle status
|
||||
});
|
||||
|
||||
// other methods are
|
||||
ifvisible.blur();
|
||||
ifvisible.focus();
|
||||
ifvisible.idle();
|
||||
ifvisible.wakeup();
|
||||
|
||||
```
|
||||
|
||||
You can set your smart intervals with ifvisible.js, if user is IDLE or not seeing the page the interval will automatically stop itself
|
||||
|
||||
```javascript
|
||||
|
||||
// If page is visible run this function on every half seconds
|
||||
ifvisible.onEvery(0.5, function(){
|
||||
// Do an animation on the logo only when page is visible
|
||||
animateLogo();
|
||||
|
||||
});
|
||||
|
||||
```
|
||||
5
vendors/ifvisible/component.json
vendored
Normal file
5
vendors/ifvisible/component.json
vendored
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"name": "ifvisible.js",
|
||||
"version": "1.0.0",
|
||||
"main": "./src/ifvisible.js"
|
||||
}
|
||||
2
vendors/ifvisible/ifvisible.min.js
vendored
Normal file
2
vendors/ifvisible/ifvisible.min.js
vendored
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
/*!ifvisible.js v1.0.0 (c) 2013 Serkan Yersen | MIT */
|
||||
(function(){"use strict";var a,b,c,d,e,f,g,h,i,j,k,l,m,n;i={},c=document,k=!1,l="active",g=6e4,f=!1,b=function(){var a,b,c,d,e,f;return a=function(){return(65536*(1+Math.random())|0).toString(16).substring(1)},e=function(){return a()+a()+"-"+a()+"-"+a()+"-"+a()+"-"+a()+a()+a()},f={},c="__ceGUID",b=function(a,b,d){return a[c]=void 0,a[c]||(a[c]="ifvisible.object.event.identifier"),f[a[c]]||(f[a[c]]={}),f[a[c]][b]||(f[a[c]][b]=[]),f[a[c]][b].push(d)},d=function(a,b,d){var e,g,h,i,j;if(a[c]&&f[a[c]]&&f[a[c]][b]){for(i=f[a[c]][b],j=[],g=0,h=i.length;h>g;g++)e=i[g],j.push(e(d||{}));return j}},{add:b,fire:d}}(),a=function(){var a;return a=!1,function(b,c,d){return a||(a=b.addEventListener?function(a,b,c){return a.addEventListener(b,c,!1)}:b.attachEvent?function(a,b,c){return a.attachEvent("on"+b,c,!1)}:function(a,b,c){return a["on"+b]=c}),a(b,c,d)}}(),d=function(a,b){var d;return c.createEventObject?a.fireEvent("on"+b,d):(d=c.createEvent("HTMLEvents"),d.initEvent(b,!0,!0),!a.dispatchEvent(d))},h=function(){var a,b,d,e,f;for(e=void 0,f=3,d=c.createElement("div"),a=d.getElementsByTagName("i"),b=function(){return d.innerHTML="<!--[if gt IE "+ ++f+"]><i></i><![endif]-->",a[0]};b(););return f>4?f:e}(),e=!1,n=void 0,"undefined"!=typeof c.hidden?(e="hidden",n="visibilitychange"):"undefined"!=typeof c.mozHidden?(e="mozHidden",n="mozvisibilitychange"):"undefined"!=typeof c.msHidden?(e="msHidden",n="msvisibilitychange"):"undefined"!=typeof c.webkitHidden&&(e="webkitHidden",n="webkitvisibilitychange"),m=function(){var b,d;return b=!1,d=function(){return clearTimeout(b),"active"!==l&&i.wakeup(),f=+new Date,b=setTimeout(function(){return"active"===l?i.idle():void 0},g)},d(),a(c,"mousemove",d),a(c,"keyup",d),a(window,"scroll",d),i.focus(d)},j=function(){var b;return k?!0:(e===!1?(b="blur",9>h&&(b="focusout"),a(window,b,function(){return i.blur()}),a(window,"focus",function(){return i.focus()})):a(c,n,function(){return c[e]?i.blur():i.focus()},!1),k=!0,m())},i={setIdleDuration:function(a){return g=1e3*a},getIdleDuration:function(){return g},getIdleInfo:function(){var a,b;return a=+new Date,b={},"idle"===l?(b.isIdle=!0,b.idleFor=a-f,b.timeLeft=0,b.timeLeftPer=100):(b.isIdle=!1,b.idleFor=a-f,b.timeLeft=f+g-a,b.timeLeftPer=(100-100*b.timeLeft/g).toFixed(2)),b},focus:function(a){return"function"==typeof a?this.on("focus",a):(l="active",b.fire(this,"focus"),b.fire(this,"wakeup"),b.fire(this,"statusChanged",{status:l}))},blur:function(a){return"function"==typeof a?this.on("blur",a):(l="hidden",b.fire(this,"blur"),b.fire(this,"idle"),b.fire(this,"statusChanged",{status:l}))},idle:function(a){return"function"==typeof a?this.on("idle",a):(l="idle",b.fire(this,"idle"),b.fire(this,"statusChanged",{status:l}))},wakeup:function(a){return"function"==typeof a?this.on("wakeup",a):(l="active",b.fire(this,"wakeup"),b.fire(this,"statusChanged",{status:l}))},on:function(a,c){return j(),b.add(this,a,c)},onEvery:function(a,b){var c;return j(),c=setInterval(function(){return"active"===l?b():void 0},1e3*a),{stop:function(){return clearInterval(c)},code:c,callback:b}},now:function(){return j(),"active"===l}},"function"==typeof define&&define.amd?define(function(){return i}):window.ifvisible=i}).call(this);
|
||||
417
vendors/ifvisible/src/ifvisible.coffee
vendored
Normal file
417
vendors/ifvisible/src/ifvisible.coffee
vendored
Normal file
|
|
@ -0,0 +1,417 @@
|
|||
# # Ifvisible.js
|
||||
# By Serkan Yersen - http://serkanyersen.github.com/ifvisible.js/
|
||||
|
||||
|
||||
###Copyright (c) 2013 Serkan Yersen
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.###
|
||||
|
||||
# Use strict rules for proper coding
|
||||
"use strict"
|
||||
|
||||
# Export Object
|
||||
# ```
|
||||
# @type {Object}
|
||||
# ```
|
||||
ifvisible = {}
|
||||
|
||||
# document element
|
||||
# ```
|
||||
# @type {Document Object}
|
||||
# ```
|
||||
doc = document
|
||||
|
||||
# flag to prevent multiple initializations
|
||||
# ```
|
||||
# @type {Boolean}`
|
||||
# ```
|
||||
initialized = false
|
||||
|
||||
# Current status, may contain `active`, `idle`, `hidden`
|
||||
# ```
|
||||
# @type {String}`
|
||||
# ```
|
||||
status = "active"
|
||||
|
||||
# Time to wait when setting page to idle
|
||||
# ```
|
||||
# @type {Number} in miliseconds
|
||||
# ```
|
||||
idleTime = 60000
|
||||
|
||||
# To track how many time left to become IDLE I need to know
|
||||
# when we started keeping the time
|
||||
# ```
|
||||
# @type {Number} in miliseconds
|
||||
# ```
|
||||
idleStartedTime = false
|
||||
|
||||
# ## Custome Event Handler
|
||||
|
||||
# Handle Custom Object events
|
||||
# ```
|
||||
# @return {Object} add and fire methods to handle custom events
|
||||
# ```
|
||||
customEvent = (->
|
||||
# Create a synthetic GUID
|
||||
S4 = ->
|
||||
(((1+Math.random())*0x10000)|0).toString(16).substring(1)
|
||||
guid = ->
|
||||
(S4()+S4()+"-"+S4()+"-"+S4()+"-"+S4()+"-"+S4()+S4()+S4())
|
||||
|
||||
# Event listeners
|
||||
# ```
|
||||
# @type {Object}
|
||||
# ```
|
||||
listeners = {}
|
||||
|
||||
# Name of the custom GUID property
|
||||
# ```
|
||||
# @type {String}
|
||||
# ```
|
||||
cgid = '__ceGUID'
|
||||
|
||||
# Add a custom event to a given object
|
||||
# ```
|
||||
# @param {Object} obj Object to add custom events
|
||||
# @param {string} event name of the custom event
|
||||
# @param {Function} callback callback function to run when
|
||||
# event is fired
|
||||
# ```
|
||||
addCustomEvent = (obj, event, callback)->
|
||||
# Extent Objects with custom event GUID so that it will be hidden
|
||||
obj[cgid] = `undefined` # it was using prototype before but diabled
|
||||
# We were using GUID here but it's disabled to keep events object in scope
|
||||
obj[cgid] = "ifvisible.object.event.identifier" unless obj[cgid]
|
||||
# create a place for event
|
||||
listeners[obj[cgid]] = {} unless listeners[obj[cgid]]
|
||||
listeners[obj[cgid]][event] = [] unless listeners[obj[cgid]][event]
|
||||
# add event
|
||||
listeners[obj[cgid]][event].push(callback)
|
||||
|
||||
# Trigger the custom event on given object
|
||||
# ```
|
||||
# @param {Object} obj Object to trigger the event
|
||||
# @param {string} event name of the event to trigger
|
||||
# @param {object} memo a custom argument to send
|
||||
# triggered event
|
||||
# ```
|
||||
fireCustomEvent = (obj, event, memo)->
|
||||
if obj[cgid] and listeners[obj[cgid]] and listeners[obj[cgid]][event]
|
||||
ev memo or {} for ev in listeners[obj[cgid]][event]
|
||||
|
||||
# export methods to use
|
||||
add: addCustomEvent
|
||||
fire: fireCustomEvent
|
||||
)()
|
||||
|
||||
# ## Regular Event Handlers
|
||||
|
||||
# CrossBrowser event attachement
|
||||
# ```
|
||||
# @param {DomElement} el Dom Element to attach the event
|
||||
# @param {string} ev name of the event with on prefix
|
||||
# @param {Function} fn callback function to run when event
|
||||
# is fired
|
||||
# ```
|
||||
addEvent = (->
|
||||
setListener = false
|
||||
# return an anonmous function with the correct version of set listener
|
||||
(el, ev, fn)->
|
||||
if not setListener
|
||||
if el.addEventListener
|
||||
setListener = (el, ev, fn) ->
|
||||
el.addEventListener(ev, fn, false)
|
||||
else if el.attachEvent
|
||||
setListener = (el, ev, fn) ->
|
||||
el.attachEvent('on' + ev, fn, false)
|
||||
else
|
||||
setListener = (el, ev, fn) ->
|
||||
el['on' + ev] = fn
|
||||
setListener(el, ev, fn)
|
||||
)()
|
||||
|
||||
# Trigger any HTML events
|
||||
# ```
|
||||
# @param {DomElement} element Dom Element to trigger
|
||||
# events on
|
||||
# @param {string} event event name to trigger
|
||||
# @return {boolean} if dispached or not
|
||||
# ```
|
||||
fireEvent = (element, event) ->
|
||||
if doc.createEventObject
|
||||
element.fireEvent('on'+event,evt)
|
||||
else
|
||||
evt = doc.createEvent('HTMLEvents')
|
||||
evt.initEvent(event, true, true)
|
||||
not element.dispatchEvent(evt)
|
||||
|
||||
# ## IE Detection
|
||||
|
||||
# Get the IE version
|
||||
# ```
|
||||
# @return {Number|Undefined} version number of IE or undefined
|
||||
# ```
|
||||
ie = (->
|
||||
undef = undefined
|
||||
v = 3
|
||||
div = doc.createElement("div")
|
||||
all = div.getElementsByTagName("i")
|
||||
|
||||
check = ->
|
||||
return ((div.innerHTML = "<!--[if gt IE " + (++v) +
|
||||
"]><i></i><![endif]-->"); all[0])
|
||||
|
||||
while check()
|
||||
continue
|
||||
|
||||
(if v > 4 then v else undef)
|
||||
)()
|
||||
|
||||
# ## Get HTML5 visibility api for current browser
|
||||
|
||||
# Set the name of the hidden property and the change event for visibility checks
|
||||
hidden = false
|
||||
visibilityChange = undefined
|
||||
# Standarts
|
||||
if typeof doc.hidden isnt "undefined"
|
||||
hidden = "hidden"
|
||||
visibilityChange = "visibilitychange"
|
||||
# For Gecko browsers
|
||||
else if typeof doc.mozHidden isnt "undefined"
|
||||
hidden = "mozHidden"
|
||||
visibilityChange = "mozvisibilitychange"
|
||||
# For MSIE
|
||||
else if typeof doc.msHidden isnt "undefined"
|
||||
hidden = "msHidden"
|
||||
visibilityChange = "msvisibilitychange"
|
||||
# For Webkit browsers
|
||||
else if typeof doc.webkitHidden isnt "undefined"
|
||||
hidden = "webkitHidden"
|
||||
visibilityChange = "webkitvisibilitychange"
|
||||
|
||||
|
||||
# Track if the page is idle or not
|
||||
trackIdleStatus = ->
|
||||
timer = false
|
||||
wakeUp = ->
|
||||
clearTimeout timer
|
||||
ifvisible.wakeup() if status isnt "active"
|
||||
idleStartedTime = +(new Date())
|
||||
timer = setTimeout(->
|
||||
ifvisible.idle() if status is "active"
|
||||
, idleTime)
|
||||
|
||||
# Call once so that it can set page to idle without doing anything
|
||||
wakeUp()
|
||||
addEvent doc, "mousemove", wakeUp
|
||||
addEvent doc, "keyup", wakeUp
|
||||
addEvent window, "scroll", wakeUp
|
||||
# If page got focus but noinput activity was recorded
|
||||
ifvisible.focus wakeUp
|
||||
|
||||
# ## Initialize the module
|
||||
|
||||
# constructor
|
||||
init = ->
|
||||
return true if initialized
|
||||
|
||||
# If hidden is false the use the legacy methods
|
||||
if hidden is false
|
||||
blur = "blur"
|
||||
blur = "focusout" if ie < 9
|
||||
addEvent window, blur, ->
|
||||
ifvisible.blur()
|
||||
|
||||
addEvent window, "focus", ->
|
||||
ifvisible.focus()
|
||||
|
||||
else
|
||||
|
||||
# add HTML5 visibility events
|
||||
addEvent doc, visibilityChange, ->
|
||||
if doc[hidden]
|
||||
ifvisible.blur()
|
||||
else
|
||||
ifvisible.focus()
|
||||
, false
|
||||
initialized = true
|
||||
|
||||
#Set method to be initialized
|
||||
trackIdleStatus()
|
||||
|
||||
# ## Exports
|
||||
|
||||
# Methods to be exported
|
||||
# ```
|
||||
# @type {Object}
|
||||
# ```
|
||||
ifvisible =
|
||||
|
||||
# Change idle timeout value.
|
||||
# ```
|
||||
# @param {Number} seconds a number in seconds such as: 10 or 0.5
|
||||
# ```
|
||||
setIdleDuration: (seconds) ->
|
||||
idleTime = seconds * 1000
|
||||
|
||||
|
||||
# Get idle timeout value.
|
||||
getIdleDuration: ->
|
||||
idleTime
|
||||
|
||||
|
||||
# Get information about user being idle.
|
||||
# ```
|
||||
# @return {Object} An object contining information about idle status
|
||||
# ```
|
||||
# Informations is as following
|
||||
# ```
|
||||
# isIdle: [current idle status true/false]
|
||||
# idleFor: [how long the user was idle
|
||||
# in milliseconds]
|
||||
# timeLeft: [How long does it take to become
|
||||
# idle in milliseconds]
|
||||
# timeLeftPer: [How long does it take to become
|
||||
# idle in percentage]
|
||||
# ```
|
||||
getIdleInfo: ->
|
||||
now = +(new Date())
|
||||
res = {}
|
||||
if status is "idle"
|
||||
res.isIdle = true
|
||||
res.idleFor = now - idleStartedTime
|
||||
res.timeLeft = 0
|
||||
res.timeLeftPer = 100
|
||||
else
|
||||
res.isIdle = false
|
||||
res.idleFor = now - idleStartedTime
|
||||
res.timeLeft = (idleStartedTime + idleTime) - now
|
||||
res.timeLeftPer = (100 - (res.timeLeft * 100 / idleTime)).toFixed(2)
|
||||
res
|
||||
|
||||
|
||||
# When User Opens the page,
|
||||
# ```
|
||||
# @note: User may not be looking at it directly
|
||||
# ```
|
||||
focus: (callback) ->
|
||||
|
||||
# if first argument is a callback then set an event
|
||||
return @on("focus", callback) if typeof callback is "function"
|
||||
# else trigger event
|
||||
status = "active"
|
||||
customEvent.fire this, "focus"
|
||||
customEvent.fire this, "wakeup" # When focused page will woke up too.
|
||||
customEvent.fire this, "statusChanged", { status: status }
|
||||
|
||||
|
||||
# When User swicthes tabs or minimizes the window
|
||||
# ```
|
||||
# @note: this may trigger when iframes are selected
|
||||
# ```
|
||||
blur: (callback) ->
|
||||
|
||||
# if first argument is a callback then set an event
|
||||
return @on("blur", callback) if typeof callback is "function"
|
||||
# else trigger event
|
||||
status = "hidden"
|
||||
customEvent.fire this, "blur"
|
||||
customEvent.fire this, "idle" # When blurred page is idle too
|
||||
customEvent.fire this, "statusChanged", { status: status }
|
||||
|
||||
|
||||
# When page is focused but user is doing nothing on the page
|
||||
idle: (callback) ->
|
||||
|
||||
# if first argument is a callback then set an event
|
||||
return @on("idle", callback) if typeof callback is "function"
|
||||
# else trigger event
|
||||
status = "idle"
|
||||
customEvent.fire this, "idle"
|
||||
customEvent.fire this, "statusChanged", { status: status }
|
||||
|
||||
|
||||
# When user started to make interactions on the page such as:
|
||||
# `mousemove`, `click`, `keypress`, `scroll`
|
||||
# This will be called when page has focus too
|
||||
wakeup: (callback) ->
|
||||
|
||||
# if first argument is a callback then set an event
|
||||
return @on("wakeup", callback) if typeof callback is "function"
|
||||
# else trigger event
|
||||
status = "active"
|
||||
customEvent.fire this, "wakeup"
|
||||
customEvent.fire this, "statusChanged", { status: status }
|
||||
|
||||
|
||||
|
||||
# Set an event to ifvisible object
|
||||
# ```
|
||||
# @param {string} name Event name such as focus,
|
||||
# idle, blur, wakeup
|
||||
# @param {Function} callback callback function to call
|
||||
# when event is fired
|
||||
# @return {object} an object with a stop method
|
||||
# to unbid this event
|
||||
# ```
|
||||
on: (name, callback) ->
|
||||
init() # Auto init on first call
|
||||
customEvent.add this, name, callback
|
||||
|
||||
|
||||
# if page is visible then run given code in given seconds of intervals
|
||||
# ```
|
||||
# @param {float} seconds seconds to run interval
|
||||
# @param {Function} callback callback function to run
|
||||
# ```
|
||||
onEvery: (seconds, callback) ->
|
||||
# Auto init on first call
|
||||
init()
|
||||
t = setInterval(->
|
||||
callback() if status is "active"
|
||||
, seconds * 1000)
|
||||
|
||||
# return methods
|
||||
stop: ->
|
||||
clearInterval t
|
||||
|
||||
code: t
|
||||
callback: callback
|
||||
|
||||
|
||||
# `ifvisible.now()` return if the page is visible right now?
|
||||
# ```
|
||||
# @return {boolean} true if page is visible
|
||||
# ```
|
||||
now: ->
|
||||
# Auto init on first call
|
||||
init()
|
||||
status is "active"
|
||||
|
||||
|
||||
# If there is a **Require JS** kind of library use it othervise
|
||||
# place it on the `window`
|
||||
if typeof define is "function" and define.amd
|
||||
define ->
|
||||
ifvisible
|
||||
|
||||
else
|
||||
window.ifvisible = ifvisible
|
||||
|
||||
# compile code: `coffee -wcm ifvisible.coffee`
|
||||
315
vendors/ifvisible/src/ifvisible.js
vendored
Normal file
315
vendors/ifvisible/src/ifvisible.js
vendored
Normal file
|
|
@ -0,0 +1,315 @@
|
|||
// Generated by CoffeeScript 1.6.2
|
||||
/*Copyright (c) 2013 Serkan Yersen
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
|
||||
(function() {
|
||||
"use strict";
|
||||
var addEvent, customEvent, doc, fireEvent, hidden, idleStartedTime, idleTime, ie, ifvisible, init, initialized, status, trackIdleStatus, visibilityChange;
|
||||
|
||||
ifvisible = {};
|
||||
|
||||
doc = document;
|
||||
|
||||
initialized = false;
|
||||
|
||||
status = "active";
|
||||
|
||||
idleTime = 60000;
|
||||
|
||||
idleStartedTime = false;
|
||||
|
||||
customEvent = (function() {
|
||||
var S4, addCustomEvent, cgid, fireCustomEvent, guid, listeners;
|
||||
|
||||
S4 = function() {
|
||||
return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);
|
||||
};
|
||||
guid = function() {
|
||||
return S4() + S4() + "-" + S4() + "-" + S4() + "-" + S4() + "-" + S4() + S4() + S4();
|
||||
};
|
||||
listeners = {};
|
||||
cgid = '__ceGUID';
|
||||
addCustomEvent = function(obj, event, callback) {
|
||||
obj[cgid] = undefined;
|
||||
if (!obj[cgid]) {
|
||||
obj[cgid] = "ifvisible.object.event.identifier";
|
||||
}
|
||||
if (!listeners[obj[cgid]]) {
|
||||
listeners[obj[cgid]] = {};
|
||||
}
|
||||
if (!listeners[obj[cgid]][event]) {
|
||||
listeners[obj[cgid]][event] = [];
|
||||
}
|
||||
return listeners[obj[cgid]][event].push(callback);
|
||||
};
|
||||
fireCustomEvent = function(obj, event, memo) {
|
||||
var ev, _i, _len, _ref, _results;
|
||||
|
||||
if (obj[cgid] && listeners[obj[cgid]] && listeners[obj[cgid]][event]) {
|
||||
_ref = listeners[obj[cgid]][event];
|
||||
_results = [];
|
||||
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
||||
ev = _ref[_i];
|
||||
_results.push(ev(memo || {}));
|
||||
}
|
||||
return _results;
|
||||
}
|
||||
};
|
||||
return {
|
||||
add: addCustomEvent,
|
||||
fire: fireCustomEvent
|
||||
};
|
||||
})();
|
||||
|
||||
addEvent = (function() {
|
||||
var setListener;
|
||||
|
||||
setListener = false;
|
||||
return function(el, ev, fn) {
|
||||
if (!setListener) {
|
||||
if (el.addEventListener) {
|
||||
setListener = function(el, ev, fn) {
|
||||
return el.addEventListener(ev, fn, false);
|
||||
};
|
||||
} else if (el.attachEvent) {
|
||||
setListener = function(el, ev, fn) {
|
||||
return el.attachEvent('on' + ev, fn, false);
|
||||
};
|
||||
} else {
|
||||
setListener = function(el, ev, fn) {
|
||||
return el['on' + ev] = fn;
|
||||
};
|
||||
}
|
||||
}
|
||||
return setListener(el, ev, fn);
|
||||
};
|
||||
})();
|
||||
|
||||
fireEvent = function(element, event) {
|
||||
var evt;
|
||||
|
||||
if (doc.createEventObject) {
|
||||
return element.fireEvent('on' + event, evt);
|
||||
} else {
|
||||
evt = doc.createEvent('HTMLEvents');
|
||||
evt.initEvent(event, true, true);
|
||||
return !element.dispatchEvent(evt);
|
||||
}
|
||||
};
|
||||
|
||||
ie = (function() {
|
||||
var all, check, div, undef, v;
|
||||
|
||||
undef = void 0;
|
||||
v = 3;
|
||||
div = doc.createElement("div");
|
||||
all = div.getElementsByTagName("i");
|
||||
check = function() {
|
||||
return (div.innerHTML = "<!--[if gt IE " + (++v) + "]><i></i><![endif]-->", all[0]);
|
||||
};
|
||||
while (check()) {
|
||||
continue;
|
||||
}
|
||||
if (v > 4) {
|
||||
return v;
|
||||
} else {
|
||||
return undef;
|
||||
}
|
||||
})();
|
||||
|
||||
hidden = false;
|
||||
|
||||
visibilityChange = void 0;
|
||||
|
||||
if (typeof doc.hidden !== "undefined") {
|
||||
hidden = "hidden";
|
||||
visibilityChange = "visibilitychange";
|
||||
} else if (typeof doc.mozHidden !== "undefined") {
|
||||
hidden = "mozHidden";
|
||||
visibilityChange = "mozvisibilitychange";
|
||||
} else if (typeof doc.msHidden !== "undefined") {
|
||||
hidden = "msHidden";
|
||||
visibilityChange = "msvisibilitychange";
|
||||
} else if (typeof doc.webkitHidden !== "undefined") {
|
||||
hidden = "webkitHidden";
|
||||
visibilityChange = "webkitvisibilitychange";
|
||||
}
|
||||
|
||||
trackIdleStatus = function() {
|
||||
var timer, wakeUp;
|
||||
|
||||
timer = false;
|
||||
wakeUp = function() {
|
||||
clearTimeout(timer);
|
||||
if (status !== "active") {
|
||||
ifvisible.wakeup();
|
||||
}
|
||||
idleStartedTime = +(new Date());
|
||||
return timer = setTimeout(function() {
|
||||
if (status === "active") {
|
||||
return ifvisible.idle();
|
||||
}
|
||||
}, idleTime);
|
||||
};
|
||||
wakeUp();
|
||||
addEvent(doc, "mousemove", wakeUp);
|
||||
addEvent(doc, "keyup", wakeUp);
|
||||
addEvent(window, "scroll", wakeUp);
|
||||
return ifvisible.focus(wakeUp);
|
||||
};
|
||||
|
||||
init = function() {
|
||||
var blur;
|
||||
|
||||
if (initialized) {
|
||||
return true;
|
||||
}
|
||||
if (hidden === false) {
|
||||
blur = "blur";
|
||||
if (ie < 9) {
|
||||
blur = "focusout";
|
||||
}
|
||||
addEvent(window, blur, function() {
|
||||
return ifvisible.blur();
|
||||
});
|
||||
addEvent(window, "focus", function() {
|
||||
return ifvisible.focus();
|
||||
});
|
||||
} else {
|
||||
addEvent(doc, visibilityChange, function() {
|
||||
if (doc[hidden]) {
|
||||
return ifvisible.blur();
|
||||
} else {
|
||||
return ifvisible.focus();
|
||||
}
|
||||
}, false);
|
||||
}
|
||||
initialized = true;
|
||||
return trackIdleStatus();
|
||||
};
|
||||
|
||||
ifvisible = {
|
||||
setIdleDuration: function(seconds) {
|
||||
return idleTime = seconds * 1000;
|
||||
},
|
||||
getIdleDuration: function() {
|
||||
return idleTime;
|
||||
},
|
||||
getIdleInfo: function() {
|
||||
var now, res;
|
||||
|
||||
now = +(new Date());
|
||||
res = {};
|
||||
if (status === "idle") {
|
||||
res.isIdle = true;
|
||||
res.idleFor = now - idleStartedTime;
|
||||
res.timeLeft = 0;
|
||||
res.timeLeftPer = 100;
|
||||
} else {
|
||||
res.isIdle = false;
|
||||
res.idleFor = now - idleStartedTime;
|
||||
res.timeLeft = (idleStartedTime + idleTime) - now;
|
||||
res.timeLeftPer = (100 - (res.timeLeft * 100 / idleTime)).toFixed(2);
|
||||
}
|
||||
return res;
|
||||
},
|
||||
focus: function(callback) {
|
||||
if (typeof callback === "function") {
|
||||
return this.on("focus", callback);
|
||||
}
|
||||
status = "active";
|
||||
customEvent.fire(this, "focus");
|
||||
customEvent.fire(this, "wakeup");
|
||||
return customEvent.fire(this, "statusChanged", {
|
||||
status: status
|
||||
});
|
||||
},
|
||||
blur: function(callback) {
|
||||
if (typeof callback === "function") {
|
||||
return this.on("blur", callback);
|
||||
}
|
||||
status = "hidden";
|
||||
customEvent.fire(this, "blur");
|
||||
customEvent.fire(this, "idle");
|
||||
return customEvent.fire(this, "statusChanged", {
|
||||
status: status
|
||||
});
|
||||
},
|
||||
idle: function(callback) {
|
||||
if (typeof callback === "function") {
|
||||
return this.on("idle", callback);
|
||||
}
|
||||
status = "idle";
|
||||
customEvent.fire(this, "idle");
|
||||
return customEvent.fire(this, "statusChanged", {
|
||||
status: status
|
||||
});
|
||||
},
|
||||
wakeup: function(callback) {
|
||||
if (typeof callback === "function") {
|
||||
return this.on("wakeup", callback);
|
||||
}
|
||||
status = "active";
|
||||
customEvent.fire(this, "wakeup");
|
||||
return customEvent.fire(this, "statusChanged", {
|
||||
status: status
|
||||
});
|
||||
},
|
||||
on: function(name, callback) {
|
||||
init();
|
||||
return customEvent.add(this, name, callback);
|
||||
},
|
||||
onEvery: function(seconds, callback) {
|
||||
var t;
|
||||
|
||||
init();
|
||||
t = setInterval(function() {
|
||||
if (status === "active") {
|
||||
return callback();
|
||||
}
|
||||
}, seconds * 1000);
|
||||
return {
|
||||
stop: function() {
|
||||
return clearInterval(t);
|
||||
},
|
||||
code: t,
|
||||
callback: callback
|
||||
};
|
||||
},
|
||||
now: function() {
|
||||
init();
|
||||
return status === "active";
|
||||
}
|
||||
};
|
||||
|
||||
if (typeof define === "function" && define.amd) {
|
||||
define(function() {
|
||||
return ifvisible;
|
||||
});
|
||||
} else {
|
||||
window.ifvisible = ifvisible;
|
||||
}
|
||||
|
||||
}).call(this);
|
||||
|
||||
/*
|
||||
//@ sourceMappingURL=ifvisible.map
|
||||
*/
|
||||
10
vendors/ifvisible/src/ifvisible.map
vendored
Normal file
10
vendors/ifvisible/src/ifvisible.map
vendored
Normal file
File diff suppressed because one or more lines are too long
Loading…
Add table
Add a link
Reference in a new issue