/** * 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/ */ ;(function (win,doc) { var humane, on, off, isArray, eventing = false, useTransitions = false, animationInProgress = false, humaneEl = null, timeout = null, useFilter = /msie [678]/i.test(navigator.userAgent), // sniff, sniff vendors = { Webkit: 'webkit', Moz: '', O: 'o', ms: 'MS' }, eventPrefix = "", isSetup = false, currentMessage = {}, noop = function(){}, events = { 'add': noop, 'show': noop, 'hide': noop }, queue = []; if ('addEventListener' in win) { on = function (obj,type,fn) { obj.addEventListener(type,fn,false) }; off = function (obj,type,fn) { obj.removeEventListener(type,fn,false) }; } else { on = function (obj,type,fn) { obj.attachEvent('on'+type,fn) }; off = function (obj,type,fn) { obj.detachEvent('on'+type,fn) }; } isArray = Array.isArray || function (obj) { return Object.prototype.toString.call(obj) === '[object Array]' }; function normalizeEvent(name) { return eventPrefix ? eventPrefix + name : name.toLowerCase(); } function getConfig(type, config) { return win.humane[type][config] !== void 0 ? win.humane[type][config] : win.humane[config]; } on (win,'load', setup); function setup() { humaneEl = doc.createElement('div'); humaneEl.id = 'humane'; humaneEl.className = 'humane'; doc.body.appendChild(humaneEl); for (vendor in vendors) { if (vendor + 'TransitionProperty' in humaneEl.style) { eventPrefix = vendors[vendor]; useTransitions = true; } } if (!useTransitions) animate = jsAnimateOpacity; // use js animation when no transition support isSetup = true; run(); } function run() { if (animationInProgress) return; if (!queue.length) return; after = null; animationInProgress = true; if (timeout) { clearTimeout(timeout); timeout = null; } var next = queue.shift(); currentMessage = { type: next[0], message: next[1], callback: next[2] }; var content = currentMessage.message, type = currentMessage.type; if ( getConfig(type, 'clickToClose') === true ) { on (humaneEl, 'click', remove); on (humaneEl, 'touchstart', remove); } var timeoutInMillis = getConfig(type, 'timeout'); if (timeoutInMillis > 0) { timeout = setTimeout(function(){ // allow notification to stay alive for timeout if (!eventing) { on (doc.body, 'mousemove', remove); on (doc.body, 'click', remove); on (doc.body, 'keypress', remove); on (doc.body, 'touchstart', remove); eventing = true; if( getConfig(type, 'waitForMove') !== true ) remove(); } }, timeoutInMillis); } events['show'](type,content,'show'); if ( isArray(content) ) content = ''; humaneEl.innerHTML = content; humaneEl.style.display = 'block'; setTimeout(function(){ animate(1,type); },50) // prevent queueing display in animation } function animate (level,type) { if (level === 1) { humaneEl.className = "humane humane-" + type + " humane-animate"; } else { humaneEl.className = humaneEl.className.replace(" humane-animate",""); on ( humaneEl, normalizeEvent('TransitionEnd'), end ); } } function remove() { off (doc.body, 'mousemove', remove); off (doc.body, 'click', remove); off (doc.body, 'keypress', remove); off (doc.body, 'touchstart', remove); // remove click and touchstart in case clickToClose was added off (humaneEl, 'click', remove); off (humaneEl, 'touchstart', remove); eventing = false; if (animationInProgress) animate(0); } function end() { // turn off animation event if supported, a little trigger happy if (useTransitions) off ( humaneEl, normalizeEvent('TransitionEnd'), end ); animationInProgress = false; if (currentMessage.callback) currentMessage.callback(); events['hide'](currentMessage.type, currentMessage.message,'hide'); humaneEl.style.display = 'none'; run(); } var setOpacity = useFilter ? function (opacity) { humaneEl.filters.item('DXImageTransform.Microsoft.Alpha').Opacity = opacity*100; } : function (opacity) { humaneEl.style.opacity = String(opacity); } function jsAnimateOpacity (level,type) { var interval; var opacity; if (level === 1) { opacity = 0; humaneEl.className = "humane humane-js-animate humane-" + type; if (useFilter) setOpacity(0); // reset value so hover states work humaneEl.style.zIndex = 1000000; interval = setInterval(function(){ if (opacity < 1) { opacity += 0.1; if (opacity > 1) opacity = 1; setOpacity(opacity); } else { clearInterval(interval); } }, 100 / 20); } else { opacity = 1; interval = setInterval(function(){ if(opacity > 0) { opacity -= 0.1; if (opacity < 0) opacity = 0; setOpacity(opacity); } else { humaneEl.className = humaneEl.className.replace(" humane-js-animate",""); humaneEl.style.zIndex = -1; clearInterval(interval); end(); } }, 100 / 20); } } function notifier (type) { return function (message, cb) { queue.push( [type, message, cb] ); events['add'](type,message,'add'); if (isSetup) run(); } } // types humane = notifier('log'); humane.log = notifier('log'); humane.error = notifier('error'); humane.info = notifier('info'); humane.success = notifier('success'); humane.remove = remove; // options humane.timeout = 2500; humane.waitForMove = false; humane.clickToClose = false; // events humane.on = function(type, handler){ events[type] = handler; }; win.humane = humane; })( window, document );