/var/www/clients/client1/web2/web/latynfusion/js/wow/src
Edit: /var/www/clients/client1/web2/web/latynfusion/js/wow/src/wow.coffee (9156B)
#
# Name : wow
# Author : Matthieu Aussaguel, http://mynameismatthieu.com/, @mattaussaguel
# Version : 1.1.2
# Repo : https://github.com/matthieua/WOW
# Website : http://mynameismatthieu.com/wow
#
class Util
extend: (custom, defaults) ->
custom[key] ?= value for key, value of defaults
custom
isMobile: (agent) ->
/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(agent)
createEvent: (event, bubble = false, cancel = false, detail = null) ->
if document.createEvent? # W3C DOM
customEvent = document.createEvent('CustomEvent')
customEvent.initCustomEvent(event, bubble, cancel, detail)
else if document.createEventObject? # IE DOM < 9
customEvent = document.createEventObject()
customEvent.eventType = event
else
customEvent.eventName = event
customEvent
emitEvent: (elem, event) ->
if elem.dispatchEvent? # W3C DOM
elem.dispatchEvent(event)
else if event of elem?
elem[event]()
else if "on#{event}" of elem?
elem["on#{event}"]()
addEvent: (elem, event, fn) ->
if elem.addEventListener? # W3C DOM
elem.addEventListener event, fn, false
else if elem.attachEvent? # IE DOM
elem.attachEvent "on#{event}", fn
else # fallback
elem[event] = fn
removeEvent: (elem, event, fn) ->
if elem.removeEventListener? # W3C DOM
elem.removeEventListener event, fn, false
else if elem.detachEvent? # IE DOM
elem.detachEvent "on#{event}", fn
else # fallback
delete elem[event]
innerHeight: ->
if 'innerHeight' of window
window.innerHeight
else document.documentElement.clientHeight
# Minimalistic WeakMap shim, just in case.
WeakMap = @WeakMap or @MozWeakMap or \
class WeakMap
constructor: ->
@keys = []
@values = []
get: (key) ->
for item, i in @keys
if item is key
return @values[i]
set: (key, value) ->
for item, i in @keys
if item is key
@values[i] = value
return
@keys.push(key)
@values.push(value)
# Dummy MutationObserver, to avoid raising exceptions.
MutationObserver = @MutationObserver or @WebkitMutationObserver or @MozMutationObserver or \
class MutationObserver
constructor: ->
console?.warn 'MutationObserver is not supported by your browser.'
console?.warn 'WOW.js cannot detect dom mutations, please call .sync() after loading new content.'
@notSupported: true
observe: ->
# getComputedStyle shim, from http://stackoverflow.com/a/21797294
getComputedStyle = @getComputedStyle or \
(el, pseudo) ->
@getPropertyValue = (prop) ->
prop = 'styleFloat' if prop is 'float'
prop.replace(getComputedStyleRX, (_, _char)->
_char.toUpperCase()
) if getComputedStyleRX.test prop
el.currentStyle?[prop] or null
@
getComputedStyleRX = /(\-([a-z]){1})/g
class @WOW
defaults:
boxClass: 'wow'
animateClass: 'animated'
offset: 0
mobile: true
live: true
callback: null
scrollContainer: null
constructor: (options = {}) ->
@scrolled = true
@config = @util().extend(options, @defaults)
if options.scrollContainer?
@config.scrollContainer = document.querySelector(options.scrollContainer)
# Map of elements to animation names:
@animationNameCache = new WeakMap()
@wowEvent = @util().createEvent(@config.boxClass)
init: ->
@element = window.document.documentElement
if document.readyState in ["interactive", "complete"]
@start()
else
@util().addEvent document, 'DOMContentLoaded', @start
@finished = []
start: =>
@stopped = false
@boxes = (box for box in @element.querySelectorAll(".#{@config.boxClass}"))
@all = (box for box in @boxes)
if @boxes.length
if @disabled()
@resetStyle()
else
@applyStyle(box, true) for box in @boxes
if !@disabled()
@util().addEvent @config.scrollContainer || window, 'scroll', @scrollHandler
@util().addEvent window, 'resize', @scrollHandler
@interval = setInterval @scrollCallback, 50
if @config.live
new MutationObserver (records) =>
for record in records
@doSync(node) for node in record.addedNodes or []
.observe document.body,
childList: true
subtree: true
# unbind the scroll event
stop: ->
@stopped = true
@util().removeEvent @config.scrollContainer || window, 'scroll', @scrollHandler
@util().removeEvent window, 'resize', @scrollHandler
clearInterval @interval if @interval?
sync: (element) ->
@doSync(@element) if MutationObserver.notSupported
doSync: (element) ->
element ?= @element
return unless element.nodeType is 1
element = element.parentNode or element
for box in element.querySelectorAll(".#{@config.boxClass}")
unless box in @all
@boxes.push box
@all.push box
if @stopped or @disabled()
@resetStyle()
else
@applyStyle(box, true)
@scrolled = true
# show box element
show: (box) ->
@applyStyle(box)
box.className = "#{box.className} #{@config.animateClass}"
@config.callback(box) if @config.callback?
@util().emitEvent(box, @wowEvent)
@util().addEvent(box, 'animationend', @resetAnimation)
@util().addEvent(box, 'oanimationend', @resetAnimation)
@util().addEvent(box, 'webkitAnimationEnd', @resetAnimation)
@util().addEvent(box, 'MSAnimationEnd', @resetAnimation)
box
applyStyle: (box, hidden) ->
duration = box.getAttribute('data-wow-duration')
delay = box.getAttribute('data-wow-delay')
iteration = box.getAttribute('data-wow-iteration')
@animate => @customStyle(box, hidden, duration, delay, iteration)
animate: (->
if 'requestAnimationFrame' of window
(callback) ->
window.requestAnimationFrame callback
else
(callback) ->
callback()
)()
resetStyle: ->
box.style.visibility = 'visible' for box in @boxes
resetAnimation: (event) =>
if event.type.toLowerCase().indexOf('animationend') >= 0
target = event.target || event.srcElement
target.className = target.className.replace(@config.animateClass, '').trim()
customStyle: (box, hidden, duration, delay, iteration) ->
@cacheAnimationName(box) if hidden
box.style.visibility = if hidden then 'hidden' else 'visible'
@vendorSet box.style, animationDuration: duration if duration
@vendorSet box.style, animationDelay: delay if delay
@vendorSet box.style, animationIterationCount: iteration if iteration
@vendorSet box.style, animationName: if hidden then 'none' else @cachedAnimationName(box)
box
vendors: ["moz", "webkit"]
vendorSet: (elem, properties) ->
for name, value of properties
elem["#{name}"] = value
elem["#{vendor}#{name.charAt(0).toUpperCase()}#{name.substr 1}"] = value for vendor in @vendors
vendorCSS: (elem, property) ->
style = getComputedStyle(elem)
result = style.getPropertyCSSValue(property)
result = result or style.getPropertyCSSValue("-#{vendor}-#{property}") for vendor in @vendors
result
animationName: (box) ->
try
animationName = @vendorCSS(box, 'animation-name').cssText
catch # Opera, fall back to plain property value
animationName = getComputedStyle(box).getPropertyValue('animation-name')
if animationName is 'none'
'' # SVG/Firefox, unable to get animation name?
else
animationName
cacheAnimationName: (box) ->
# https://bugzilla.mozilla.org/show_bug.cgi?id=921834
# box.dataset is not supported for SVG elements in Firefox
@animationNameCache.set(box, @animationName(box))
cachedAnimationName: (box) ->
@animationNameCache.get(box)
# fast window.scroll callback
scrollHandler: =>
@scrolled = true
scrollCallback: =>
if @scrolled
@scrolled = false
@boxes = for box in @boxes when box
if @isVisible(box)
@show(box)
continue
box
@stop() unless @boxes.length or @config.live
# Calculate element offset top
offsetTop: (element) ->
# SVG elements don't have an offsetTop in Firefox.
# This will use their nearest parent that has an offsetTop.
# Also, using ('offsetTop' of element) causes an exception in Firefox.
element = element.parentNode while element.offsetTop is undefined
top = element.offsetTop
top += element.offsetTop while element = element.offsetParent
top
# check if box is visible
isVisible: (box) ->
offset = box.getAttribute('data-wow-offset') or @config.offset
viewTop = (@config.scrollContainer && @config.scrollContainer.scrollTop) || window.pageYOffset
viewBottom = viewTop + Math.min(@element.clientHeight, @util().innerHeight()) - offset
top = @offsetTop(box)
bottom = top + box.clientHeight
top <= viewBottom and bottom >= viewTop
util: ->
@_util ?= new Util()
disabled: ->
not @config.mobile and @util().isMobile(navigator.userAgent)