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,
|
"ko" : true,
|
||||||
"ssm" : true,
|
"ssm" : true,
|
||||||
"moment" : true,
|
"moment" : true,
|
||||||
|
"ifvisible" : true,
|
||||||
"crossroads" : true,
|
"crossroads" : true,
|
||||||
"hasher" : true,
|
"hasher" : true,
|
||||||
"Jua" : true,
|
"Jua" : true,
|
||||||
|
|
|
||||||
14
Gruntfile.js
14
Gruntfile.js
|
|
@ -45,6 +45,14 @@ module.exports = function (grunt) {
|
||||||
src: 'vendors/jquery-cookie/jquery.cookie.js',
|
src: 'vendors/jquery-cookie/jquery.cookie.js',
|
||||||
dest: 'vendors/jquery-cookie/jquery.cookie-1.4.0.min.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: {
|
wakeup: {
|
||||||
options: {
|
options: {
|
||||||
banner: '/*! jQuery WakeUp plugin (c) 2013 Paul Okopny <paul.okopny@gmail.com> | MIT */\n',
|
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/knockout-projections/knockout-projections-1.0.0.min.js",
|
||||||
"vendors/ssm/ssm.min.js",
|
"vendors/ssm/ssm.min.js",
|
||||||
"vendors/jua/jua.min.js",
|
"vendors/jua/jua.min.js",
|
||||||
|
"vendors/ifvisible/ifvisible.min.js",
|
||||||
"vendors/jquery-magnific-popup/jquery.magnific-popup.min.js",
|
"vendors/jquery-magnific-popup/jquery.magnific-popup.min.js",
|
||||||
"vendors/bootstrap/js/bootstrap.min.js",
|
"vendors/bootstrap/js/bootstrap.min.js",
|
||||||
"dev/Common/_LibsEnd.js"
|
"dev/Common/_LibsEnd.js"
|
||||||
|
|
@ -217,8 +226,8 @@ module.exports = function (grunt) {
|
||||||
options: {
|
options: {
|
||||||
stripBanners: true,
|
stripBanners: true,
|
||||||
banner: '/*! RainLoop Webmail Main Module (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */\n' +
|
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',
|
'(function (window, $, ko, crossroads, hasher, moment, Jua, _, ifvisible) {\n',
|
||||||
footer: '\n\n}(window, jQuery, ko, crossroads, hasher, moment, Jua, _));'
|
footer: '\n\n}(window, jQuery, ko, crossroads, hasher, moment, Jua, _, ifvisible));'
|
||||||
},
|
},
|
||||||
src: [
|
src: [
|
||||||
"dev/Common/_Begin.js",
|
"dev/Common/_Begin.js",
|
||||||
|
|
@ -445,6 +454,7 @@ module.exports = function (grunt) {
|
||||||
grunt.registerTask('cookie', ['uglify:cookie']);
|
grunt.registerTask('cookie', ['uglify:cookie']);
|
||||||
grunt.registerTask('mousewheel', ['uglify:mousewheel']);
|
grunt.registerTask('mousewheel', ['uglify:mousewheel']);
|
||||||
grunt.registerTask('inputosaurus', ['uglify:inputosaurus']);
|
grunt.registerTask('inputosaurus', ['uglify:inputosaurus']);
|
||||||
|
grunt.registerTask('ifvisible', ['uglify:ifvisible']);
|
||||||
// ---
|
// ---
|
||||||
|
|
||||||
grunt.registerTask('default', ['less', 'concat', 'cssmin', 'jshint', 'rlmin']);
|
grunt.registerTask('default', ['less', 'concat', 'cssmin', 'jshint', 'rlmin']);
|
||||||
|
|
|
||||||
|
|
@ -17,8 +17,6 @@ function MessageModel()
|
||||||
this.toEmailsString = ko.observable('');
|
this.toEmailsString = ko.observable('');
|
||||||
this.senderEmailsString = ko.observable('');
|
this.senderEmailsString = ko.observable('');
|
||||||
|
|
||||||
this.prefetched = false;
|
|
||||||
|
|
||||||
this.emails = [];
|
this.emails = [];
|
||||||
|
|
||||||
this.from = [];
|
this.from = [];
|
||||||
|
|
@ -228,8 +226,6 @@ MessageModel.prototype.clear = function ()
|
||||||
this.toEmailsString('');
|
this.toEmailsString('');
|
||||||
this.senderEmailsString('');
|
this.senderEmailsString('');
|
||||||
|
|
||||||
this.prefetched = false;
|
|
||||||
|
|
||||||
this.emails = [];
|
this.emails = [];
|
||||||
|
|
||||||
this.from = [];
|
this.from = [];
|
||||||
|
|
@ -299,8 +295,6 @@ MessageModel.prototype.initByJson = function (oJsonMessage)
|
||||||
this.uid = oJsonMessage.Uid;
|
this.uid = oJsonMessage.Uid;
|
||||||
this.requestHash = oJsonMessage.RequestHash;
|
this.requestHash = oJsonMessage.RequestHash;
|
||||||
|
|
||||||
this.prefetched = false;
|
|
||||||
|
|
||||||
this.size(Utils.pInt(oJsonMessage.Size));
|
this.size(Utils.pInt(oJsonMessage.Size));
|
||||||
|
|
||||||
this.from = MessageModel.initEmailsFromJson(oJsonMessage.From);
|
this.from = MessageModel.initEmailsFromJson(oJsonMessage.From);
|
||||||
|
|
|
||||||
|
|
@ -41,7 +41,7 @@ function AdminLoginViewModel()
|
||||||
|
|
||||||
RL.remote().adminLogin(_.bind(function (sResult, oData) {
|
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)
|
if (oData.Result)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ function MailBoxMessageListViewModel()
|
||||||
KnoinAbstractViewModel.call(this, 'Right', 'MailMessageList');
|
KnoinAbstractViewModel.call(this, 'Right', 'MailMessageList');
|
||||||
|
|
||||||
this.sLastUid = null;
|
this.sLastUid = null;
|
||||||
|
this.bPrefetch = false;
|
||||||
this.emptySubjectValue = '';
|
this.emptySubjectValue = '';
|
||||||
|
|
||||||
var oData = RL.data();
|
var oData = RL.data();
|
||||||
|
|
@ -796,6 +797,51 @@ MailBoxMessageListViewModel.prototype.onBuild = function (oDom)
|
||||||
}, this).extend({'notify': 'always'});
|
}, this).extend({'notify': 'always'});
|
||||||
|
|
||||||
this.initUploaderForAppend();
|
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 ()
|
MailBoxMessageListViewModel.prototype.composeClick = function ()
|
||||||
|
|
|
||||||
|
|
@ -909,6 +909,7 @@ class Actions
|
||||||
'AllowAdditionalAccounts' => (bool) $oConfig->Get('webmail', 'allow_additional_accounts', true),
|
'AllowAdditionalAccounts' => (bool) $oConfig->Get('webmail', 'allow_additional_accounts', true),
|
||||||
'AllowIdentities' => (bool) $oConfig->Get('webmail', 'allow_identities', true),
|
'AllowIdentities' => (bool) $oConfig->Get('webmail', 'allow_identities', true),
|
||||||
'DetermineUserLanguage' => (bool) $oConfig->Get('labs', 'determine_user_language', false),
|
'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),
|
'AllowCustomLogin' => (bool) $oConfig->Get('login', 'allow_custom_login', false),
|
||||||
'LoginDefaultDomain' => $oConfig->Get('login', 'default_domain', ''),
|
'LoginDefaultDomain' => $oConfig->Get('login', 'default_domain', ''),
|
||||||
'AllowThemes' => (bool) $oConfig->Get('webmail', 'allow_themes', true),
|
'AllowThemes' => (bool) $oConfig->Get('webmail', 'allow_themes', true),
|
||||||
|
|
|
||||||
|
|
@ -229,6 +229,7 @@ Enables caching in the system'),
|
||||||
'imap_forwarded_flag' => array('$Forwarded'),
|
'imap_forwarded_flag' => array('$Forwarded'),
|
||||||
'imap_read_receipt_flag' => array('$ReadReceipt'),
|
'imap_read_receipt_flag' => array('$ReadReceipt'),
|
||||||
'smtp_show_server_errors' => array(false),
|
'smtp_show_server_errors' => array(false),
|
||||||
|
'allow_prefetch' => array(true),
|
||||||
'autocreate_system_folders' => array(true),
|
'autocreate_system_folders' => array(true),
|
||||||
'repo_type' => array('stable'),
|
'repo_type' => array('stable'),
|
||||||
'custom_repo' => array(''),
|
'custom_repo' => array(''),
|
||||||
|
|
|
||||||
|
|
@ -1153,7 +1153,7 @@ Utils.log = function (sDesc)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {number} iCode
|
* @param {number} iCode
|
||||||
* @param {ыекштп=} mMessage = ''
|
* @param {*=} mMessage = ''
|
||||||
* @return {string}
|
* @return {string}
|
||||||
*/
|
*/
|
||||||
Utils.getNotification = function (iCode, mMessage)
|
Utils.getNotification = function (iCode, mMessage)
|
||||||
|
|
@ -5139,7 +5139,7 @@ function AdminLoginViewModel()
|
||||||
|
|
||||||
RL.remote().adminLogin(_.bind(function (sResult, oData) {
|
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)
|
if (oData.Result)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
/*! RainLoop Webmail Main Module (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */
|
/*! 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';
|
'use strict';
|
||||||
|
|
||||||
|
|
@ -1153,7 +1153,7 @@ Utils.log = function (sDesc)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {number} iCode
|
* @param {number} iCode
|
||||||
* @param {ыекштп=} mMessage = ''
|
* @param {*=} mMessage = ''
|
||||||
* @return {string}
|
* @return {string}
|
||||||
*/
|
*/
|
||||||
Utils.getNotification = function (iCode, mMessage)
|
Utils.getNotification = function (iCode, mMessage)
|
||||||
|
|
@ -6328,8 +6328,6 @@ function MessageModel()
|
||||||
this.toEmailsString = ko.observable('');
|
this.toEmailsString = ko.observable('');
|
||||||
this.senderEmailsString = ko.observable('');
|
this.senderEmailsString = ko.observable('');
|
||||||
|
|
||||||
this.prefetched = false;
|
|
||||||
|
|
||||||
this.emails = [];
|
this.emails = [];
|
||||||
|
|
||||||
this.from = [];
|
this.from = [];
|
||||||
|
|
@ -6539,8 +6537,6 @@ MessageModel.prototype.clear = function ()
|
||||||
this.toEmailsString('');
|
this.toEmailsString('');
|
||||||
this.senderEmailsString('');
|
this.senderEmailsString('');
|
||||||
|
|
||||||
this.prefetched = false;
|
|
||||||
|
|
||||||
this.emails = [];
|
this.emails = [];
|
||||||
|
|
||||||
this.from = [];
|
this.from = [];
|
||||||
|
|
@ -6610,8 +6606,6 @@ MessageModel.prototype.initByJson = function (oJsonMessage)
|
||||||
this.uid = oJsonMessage.Uid;
|
this.uid = oJsonMessage.Uid;
|
||||||
this.requestHash = oJsonMessage.RequestHash;
|
this.requestHash = oJsonMessage.RequestHash;
|
||||||
|
|
||||||
this.prefetched = false;
|
|
||||||
|
|
||||||
this.size(Utils.pInt(oJsonMessage.Size));
|
this.size(Utils.pInt(oJsonMessage.Size));
|
||||||
|
|
||||||
this.from = MessageModel.initEmailsFromJson(oJsonMessage.From);
|
this.from = MessageModel.initEmailsFromJson(oJsonMessage.From);
|
||||||
|
|
@ -11220,6 +11214,7 @@ function MailBoxMessageListViewModel()
|
||||||
KnoinAbstractViewModel.call(this, 'Right', 'MailMessageList');
|
KnoinAbstractViewModel.call(this, 'Right', 'MailMessageList');
|
||||||
|
|
||||||
this.sLastUid = null;
|
this.sLastUid = null;
|
||||||
|
this.bPrefetch = false;
|
||||||
this.emptySubjectValue = '';
|
this.emptySubjectValue = '';
|
||||||
|
|
||||||
var oData = RL.data();
|
var oData = RL.data();
|
||||||
|
|
@ -12007,6 +12002,51 @@ MailBoxMessageListViewModel.prototype.onBuild = function (oDom)
|
||||||
}, this).extend({'notify': 'always'});
|
}, this).extend({'notify': 'always'});
|
||||||
|
|
||||||
this.initUploaderForAppend();
|
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 ()
|
MailBoxMessageListViewModel.prototype.composeClick = function ()
|
||||||
|
|
@ -17509,4 +17549,4 @@ if (window.SimplePace) {
|
||||||
window.SimplePace.add(10);
|
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.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;
|
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
|
/*! Magnific Popup - v0.9.8 - 2013-10-26
|
||||||
* http://dimsemenov.com/plugins/magnific-popup/
|
* http://dimsemenov.com/plugins/magnific-popup/
|
||||||
* Copyright (c) 2013 Dmitry Semenov; MIT */
|
* 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