mirror of
https://github.com/the-djmaze/snappymail.git
synced 2026-09-01 21:49:21 +03:00
417 lines
11 KiB
CoffeeScript
417 lines
11 KiB
CoffeeScript
# # 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`
|