Skip to content

Instantly share code, notes, and snippets.

@alanhogan
Created February 4, 2012 05:06
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save alanhogan/1735493 to your computer and use it in GitHub Desktop.
Save alanhogan/1735493 to your computer and use it in GitHub Desktop.
Modified humane.js
# humane.js
# Humanized Messages for Notifications
# @author Marc Harter (@wavded)
# @example
# humane('hello world');
# See more usage examples at: http://wavded.github.com/humane-js/
#
# Modified by Alan Hogan (@alanhogan)
# (Diverged 2012-01-27.)
# Now has underscore.js as a dependency.
# (But it would be easy to remove.)
# Now returns an id , whether you set one or not, when new notifications are created.
# You can call remove(id) to remove
# that message (whether it has shown yet, or not).
# IDs do not have to be unique, but the ones we generate will be.
# The use case is that sometimes you will want to clear some messages
# immediately if some other event happens (e.g., user reconnects →
# clear offline notice, or ajax completes → remove "sending" message)
root = this
((win, doc) ->
doc = win.document
normalizeEvent = (name) ->
(if eventPrefix then eventPrefix + name else name.toLowerCase())
getConfig = (type, config) ->
(if win.humane[type][config] isnt undefined then win.humane[type][config] else win.humane[config])
setup = ->
humaneEl = doc.createElement("div")
humaneEl.id = "humane"
humaneEl.className = "humane"
doc.body.appendChild humaneEl
for vendor of vendors
if vendor + "TransitionProperty" of humaneEl.style
eventPrefix = vendors[vendor]
useTransitions = true
animate = jsAnimateOpacity unless useTransitions
isSetup = true
run()
run = ->
return if animationInProgress
return unless queue.length
after = null
animationInProgress = true
if timeout
clearTimeout timeout
timeout = null
next = queue.shift()
currentMessage =
type: next[0]
message: next[1]
opts: next[2]
content = currentMessage.message
type = currentMessage.type
if getConfig(type, "clickToClose") is true
on_ humaneEl, "click", remove
on_ humaneEl, "touchstart", remove
timeoutInMillis = currentMessage.opts.timeout
if timeoutInMillis > 0
timeout = setTimeout(->
unless eventing
on_ doc.body, "mousemove", remove
on_ doc.body, "click", remove
on_ doc.body, "keypress", remove
on_ doc.body, "touchstart", remove
eventing = true
remove() if currentMessage.opts.waitForMove isnt true
, timeoutInMillis)
events["show"] type, content, "show"
content = "<ul><li>" + content.join("<li>") + "</ul>" if isArray(content)
humaneEl.innerHTML = content
humaneEl.style.display = "block"
setTimeout (->
animate 1, type
), 50
animate = (level, type) ->
if level is 1
humaneEl.className = "humane humane-" + type + " humane-animate"
else
humaneEl.className = humaneEl.className.replace(" humane-animate", "")
on_ humaneEl, normalizeEvent("TransitionEnd"), end
remove = (id) ->
removeCurrent = false
if id isnt undefined
# Remove any messages from the queue with this id
queue = _.reject(queue, (msg) -> msg.id == id)
if currentMessage and currentMessage.id == id
removeCurrent = true
else
removeCurrent = true
if removeCurrent
currentMessage = {}
off_ doc.body, "mousemove", remove
off_ doc.body, "click", remove
off_ doc.body, "keypress", remove
off_ doc.body, "touchstart", remove
off_ humaneEl, "click", remove
off_ humaneEl, "touchstart", remove
eventing = false
animate 0 if animationInProgress
end = ->
off_ humaneEl, normalizeEvent("TransitionEnd"), end if useTransitions
animationInProgress = false
currentMessage.opts.callback() if currentMessage.opts.callback
events["hide"] currentMessage.type, currentMessage.message, "hide"
humaneEl.style.display = "none"
run()
jsAnimateOpacity = (level, type) ->
interval = undefined
opacity = undefined
if level is 1
opacity = 0
humaneEl.className = "humane humane-js-animate humane-" + type
setOpacity 0 if useFilter
humaneEl.style.zIndex = 1000000
interval = setInterval(->
if opacity < 1
opacity += 0.1
opacity = 1 if opacity > 1
setOpacity opacity
else
clearInterval interval
, 100 / 20)
else
opacity = 1
interval = setInterval(->
if opacity > 0
opacity -= 0.1
opacity = 0 if opacity < 0
setOpacity opacity
else
humaneEl.className = humaneEl.className.replace(" humane-js-animate", "")
humaneEl.style.zIndex = -1
clearInterval interval
end()
, 100 / 20)
notifier = (type) ->
(message, opts) ->
opts ||= {}
_.defaults(opts, {
timeout: getConfig(type, 'timeout')
waitForMove: getConfig(type, 'waitForMove')
clickToClose: getConfig(type, 'clickToClose')
id: _.uniqueId("humane_#{type}_")
})
queue.push [ type, message, opts ]
events["add"] type, message, "add"
run() if isSetup
return opts.id
humane = undefined
on_ = undefined
off_ = undefined
isArray = undefined
eventing = false
useTransitions = false
animationInProgress = false
humaneEl = null
timeout = null
useFilter = /msie [678]/i.test(navigator.userAgent)
vendors =
Webkit: "webkit"
Moz: ""
O: "o"
ms: "MS"
eventPrefix = ""
isSetup = false
currentMessage = {}
noop = ->
events =
add: noop
show: noop
hide: noop
queue = []
if "addEventListener" of win
on_ = (obj, type, fn) ->
obj.addEventListener type, fn, false
off_ = (obj, type, fn) ->
obj.removeEventListener type, fn, false
else
on_ = (obj, type, fn) ->
obj.attachEvent "on" + type, fn
off_ = (obj, type, fn) ->
obj.detachEvent "on" + type, fn
isArray = Array.isArray or (obj) ->
Object::toString.call(obj) is "[object Array]"
on_ win, "load", setup
setOpacity = (if useFilter then (opacity) ->
humaneEl.filters.item("DXImageTransform.Microsoft.Alpha").Opacity = opacity * 100
else (opacity) ->
humaneEl.style.opacity = String(opacity)
)
humane = notifier("log")
humane.log = notifier("log")
humane.error = notifier("error")
humane.info = notifier("info")
humane.success = notifier("success")
humane.remove = remove
humane.timeout = 2500
humane.waitForMove = false
humane.clickToClose = false
humane.on = (type, handler) ->
events[type] = handler
win.humane = humane
)(root)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment