alertifyjs
Version:
AlertifyJS is a javascript framework for developing pretty browser dialogs and notifications.
327 lines (312 loc) • 13.8 kB
JavaScript
var notifier = (function () {
var reflow,
element,
openInstances = [],
classes = defaults.notifier.classes,
baseClass = classes.base;
/**
* Helper: initializes the notifier instance
*
*/
function initialize(instance) {
if (!instance.__internal) {
instance.__internal = {
position: alertify.defaults.notifier.position,
delay: alertify.defaults.notifier.delay,
};
element = document.createElement('DIV');
var transitionOff = 'transitionOff' in defaults.notifier ? defaults.notifier.transitionOff : defaults.transitionOff;
if(transitionOff){
baseClass = classes.base + ' ajs-no-transition';
}
updatePosition(instance);
}
//add to DOM tree.
if (element.parentNode !== document.body) {
document.body.appendChild(element);
}
}
function pushInstance(instance) {
instance.__internal.pushed = true;
openInstances.push(instance);
}
function popInstance(instance) {
openInstances.splice(openInstances.indexOf(instance), 1);
instance.__internal.pushed = false;
}
/**
* Helper: update the notifier instance position
*
*/
function updatePosition(instance) {
element.className = baseClass;
switch (instance.__internal.position) {
case 'top-right':
addClass(element, classes.top + ' ' + classes.right);
break;
case 'top-left':
addClass(element, classes.top + ' ' + classes.left);
break;
case 'top-center':
addClass(element, classes.top + ' ' + classes.center);
break;
case 'bottom-left':
addClass(element, classes.bottom + ' ' + classes.left);
break;
case 'bottom-center':
addClass(element, classes.bottom + ' ' + classes.center);
break;
default:
case 'bottom-right':
addClass(element, classes.bottom + ' ' + classes.right);
break;
}
}
/**
* creates a new notification message
*
* @param {DOMElement} message The notifier message element
* @param {Number} wait Time (in ms) to wait before the message is dismissed, a value of 0 means keep open till clicked.
* @param {Function} callback A callback function to be invoked when the message is dismissed.
*
* @return {undefined}
*/
function create(div, callback) {
function clickDelegate(event, instance) {
if(!instance.__internal.closeButton || event.target.getAttribute('data-close') === 'true'){
instance.dismiss(true);
}
}
function transitionDone(event, instance) {
// unbind event
off(instance.element, transition.type, transitionDone);
// remove the message
element.removeChild(instance.element);
}
function initialize(instance) {
if (!instance.__internal) {
instance.__internal = {
pushed: false,
delay : undefined,
timer: undefined,
clickHandler: undefined,
transitionEndHandler: undefined,
transitionTimeout: undefined
};
instance.__internal.clickHandler = delegate(instance, clickDelegate);
instance.__internal.transitionEndHandler = delegate(instance, transitionDone);
}
return instance;
}
function clearTimers(instance) {
clearTimeout(instance.__internal.timer);
clearTimeout(instance.__internal.transitionTimeout);
}
return initialize({
/* notification DOM element*/
element: div,
/*
* Pushes a notification message
* @param {string or DOMElement} content The notification message content
* @param {Number} wait The time (in seconds) to wait before the message is dismissed, a value of 0 means keep open till clicked.
*
*/
push: function (_content, _wait) {
if (!this.__internal.pushed) {
pushInstance(this);
clearTimers(this);
var content, wait;
switch (arguments.length) {
case 0:
wait = this.__internal.delay;
break;
case 1:
if (typeof (_content) === 'number') {
wait = _content;
} else {
content = _content;
wait = this.__internal.delay;
}
break;
case 2:
content = _content;
wait = _wait;
break;
}
this.__internal.closeButton = alertify.defaults.notifier.closeButton;
// set contents
if (typeof content !== 'undefined') {
this.setContent(content);
}
// append or insert
if (notifier.__internal.position.indexOf('top') < 0) {
element.appendChild(this.element);
} else {
element.insertBefore(this.element, element.firstChild);
}
reflow = this.element.offsetWidth;
addClass(this.element, classes.visible);
// attach click event
on(this.element, 'click', this.__internal.clickHandler);
return this.delay(wait);
}
return this;
},
/*
* {Function} callback function to be invoked before dismissing the notification message.
* Remarks: A return value === 'false' will cancel the dismissal
*
*/
ondismiss: function () { },
/*
* {Function} callback function to be invoked when the message is dismissed.
*
*/
callback: callback,
/*
* Dismisses the notification message
* @param {Boolean} clicked A flag indicating if the dismissal was caused by a click.
*
*/
dismiss: function (clicked) {
if (this.__internal.pushed) {
clearTimers(this);
if (!(typeof this.ondismiss === 'function' && this.ondismiss.call(this) === false)) {
//detach click event
off(this.element, 'click', this.__internal.clickHandler);
// ensure element exists
if (typeof this.element !== 'undefined' && this.element.parentNode === element) {
//transition end or fallback
this.__internal.transitionTimeout = setTimeout(this.__internal.transitionEndHandler, transition.supported ? 1000 : 100);
removeClass(this.element, classes.visible);
// custom callback on dismiss
if (typeof this.callback === 'function') {
this.callback.call(this, clicked);
}
}
popInstance(this);
}
}
return this;
},
/*
* Delays the notification message dismissal
* @param {Number} wait The time (in seconds) to wait before the message is dismissed, a value of 0 means keep open till clicked.
*
*/
delay: function (wait) {
clearTimers(this);
this.__internal.delay = typeof wait !== 'undefined' && !isNaN(+wait) ? +wait : notifier.__internal.delay;
if (this.__internal.delay > 0) {
var self = this;
this.__internal.timer = setTimeout(function () { self.dismiss(); }, this.__internal.delay * 1000);
}
return this;
},
/*
* Sets the notification message contents
* @param {string or DOMElement} content The notification message content
*
*/
setContent: function (content) {
if (isString(content)) {
clearContents(this.element);
this.element.innerHTML = content;
} else if (content instanceof window.HTMLElement && this.element.firstChild !== content) {
clearContents(this.element);
this.element.appendChild(content);
}
if(this.__internal.closeButton){
var close = document.createElement('span');
addClass(close, classes.close);
close.setAttribute('data-close', true);
this.element.appendChild(close);
}
return this;
},
/*
* Dismisses all open notifications except this.
*
*/
dismissOthers: function () {
notifier.dismissAll(this);
return this;
}
});
}
//notifier api
return {
/**
* Gets or Sets notifier settings.
*
* @param {string} key The setting name
* @param {Variant} value The setting value.
*
* @return {Object} if the called as a setter, return the notifier instance.
*/
setting: function (key, value) {
//ensure init
initialize(this);
if (typeof value === 'undefined') {
//get
return this.__internal[key];
} else {
//set
switch (key) {
case 'position':
this.__internal.position = value;
updatePosition(this);
break;
case 'delay':
this.__internal.delay = value;
break;
}
}
return this;
},
/**
* [Alias] Sets dialog settings/options
*/
set:function(key,value){
this.setting(key,value);
return this;
},
/**
* [Alias] Gets dialog settings/options
*/
get:function(key){
return this.setting(key);
},
/**
* Creates a new notification message
*
* @param {string} type The type of notification message (simply a CSS class name 'ajs-{type}' to be added).
* @param {Function} callback A callback function to be invoked when the message is dismissed.
*
* @return {undefined}
*/
create: function (type, callback) {
//ensure notifier init
initialize(this);
//create new notification message
var div = document.createElement('div');
div.className = classes.message + ((typeof type === 'string' && type !== '') ? ' ' + classes.prefix + type : '');
return create(div, callback);
},
/**
* Dismisses all open notifications.
*
* @param {Object} excpet [optional] The notification object to exclude from dismissal.
*
*/
dismissAll: function (except) {
var clone = openInstances.slice(0);
for (var x = 0; x < clone.length; x += 1) {
var instance = clone[x];
if (except === undefined || except !== instance) {
instance.dismiss();
}
}
}
};
})();