UNPKG

alertifyjs

Version:

AlertifyJS is a javascript framework for developing pretty browser dialogs and notifications.

415 lines (371 loc) 16.9 kB
// dialog API return { __init:initialize, /** * Check if dialog is currently open * * @return {Boolean} */ isOpen: function () { return this.__internal.isOpen; }, isModal: function (){ return this.elements.root.className.indexOf(classes.modeless) < 0; }, isMaximized:function(){ return this.elements.root.className.indexOf(classes.maximized) > -1; }, isPinned:function(){ return this.elements.root.className.indexOf(classes.unpinned) < 0; }, maximize:function(){ if(!this.isMaximized()){ maximize(this); } return this; }, restore:function(){ if(this.isMaximized()){ restore(this); } return this; }, pin:function(){ if(!this.isPinned()){ pin(this); } return this; }, unpin:function(){ if(this.isPinned()){ unpin(this); } return this; }, bringToFront:function(){ bringToFront(null, this); return this; }, /** * Move the dialog to a specific x/y coordinates * * @param {Number} x The new dialog x coordinate in pixels. * @param {Number} y The new dialog y coordinate in pixels. * * @return {Object} The dialog instance. */ moveTo:function(x,y){ if(!isNaN(x) && !isNaN(y)){ // allow custom `onmove` method dispatchEvent('onmove', this); var element = this.elements.dialog, current = element, offsetLeft = 0, offsetTop = 0; //subtract existing left,top if (element.style.left) { offsetLeft -= parseInt(element.style.left, 10); } if (element.style.top) { offsetTop -= parseInt(element.style.top, 10); } //calc offset do { offsetLeft += current.offsetLeft; offsetTop += current.offsetTop; } while (current = current.offsetParent); //calc left, top var left = (x - offsetLeft); var top = (y - offsetTop); //// rtl handling if (isRightToLeft()) { left *= -1; } element.style.left = left + 'px'; element.style.top = top + 'px'; // allow custom `onmoved` method dispatchEvent('onmoved', this); } return this; }, /** * Resize the dialog to a specific width/height (the dialog must be 'resizable'). * The dialog can be resized to: * A minimum width equal to the initial display width * A minimum height equal to the sum of header/footer heights. * * * @param {Number or String} width The new dialog width in pixels or in percent. * @param {Number or String} height The new dialog height in pixels or in percent. * * @return {Object} The dialog instance. */ resizeTo:function(width,height){ var w = parseFloat(width), h = parseFloat(height), regex = /(\d*\.\d+|\d+)%/ ; if(!isNaN(w) && !isNaN(h) && this.get('resizable') === true){ // allow custom `onresize` method dispatchEvent('onresize', this); if(('' + width).match(regex)){ w = w / 100 * document.documentElement.clientWidth ; } if(('' + height).match(regex)){ h = h / 100 * document.documentElement.clientHeight; } var element = this.elements.dialog; if (element.style.maxWidth !== 'none') { element.style.minWidth = (minWidth = element.offsetWidth) + 'px'; } element.style.maxWidth = 'none'; element.style.minHeight = this.elements.header.offsetHeight + this.elements.footer.offsetHeight + 'px'; element.style.width = w + 'px'; element.style.height = h + 'px'; // allow custom `onresized` method dispatchEvent('onresized', this); } return this; }, /** * Gets or Sets dialog settings/options * * @param {String|Object} key A string specifying a propery name or a collection of key/value pairs. * @param {Object} value Optional, the value associated with the key (in case it was a string). * * @return {undefined} */ setting : function (key, value) { var self = this; var result = update(this, this.__internal.options, function(k,o,n){ optionUpdated(self,k,o,n); }, key, value); if(result.op === 'get'){ if(result.found){ return result.value; }else if(typeof this.settings !== 'undefined'){ return update(this, this.settings, this.settingUpdated || function(){}, key, value).value; }else{ return undefined; } }else if(result.op === 'set'){ if(result.items.length > 0){ var callback = this.settingUpdated || function(){}; for(var x=0;x<result.items.length;x+=1){ var item = result.items[x]; if(!item.found && typeof this.settings !== 'undefined'){ update(this, this.settings, callback, item.key, item.value); } } } 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); }, /** * Sets dialog header * @content {string or element} * * @return {undefined} */ setHeader:function(content){ if(isString(content)){ clearContents(this.elements.header); this.elements.header.innerHTML = content; }else if (content instanceof window.HTMLElement && this.elements.header.firstChild !== content){ clearContents(this.elements.header); this.elements.header.appendChild(content); } return this; }, /** * Sets dialog contents * @content {string or element} * * @return {undefined} */ setContent:function(content){ if(isString(content)){ clearContents(this.elements.content); this.elements.content.innerHTML = content; }else if (content instanceof window.HTMLElement && this.elements.content.firstChild !== content){ clearContents(this.elements.content); this.elements.content.appendChild(content); } return this; }, /** * Show the dialog as modal * * @return {Object} the dialog instance. */ showModal: function(className){ return this.show(true, className); }, /** * Show the dialog * * @return {Object} the dialog instance. */ show: function (modal, className) { // ensure initialization initialize(this); if ( !this.__internal.isOpen ) { // add to open dialogs this.__internal.isOpen = true; openDialogs.push(this); // save last focused element if(alertify.defaults.maintainFocus){ this.__internal.activeElement = document.activeElement; } // set tabindex attribute on body element this allows script to give it focusable if(!document.body.hasAttribute('tabindex')) { document.body.setAttribute( 'tabindex', tabindex = '0'); } //allow custom dom manipulation updates before showing the dialog. if(typeof this.prepare === 'function'){ this.prepare(); } bindEvents(this); if(modal !== undefined){ this.set('modal', modal); } //save scroll to prevent document jump saveScrollPosition(); ensureNoOverflow(); // allow custom dialog class on show if(typeof className === 'string' && className !== ''){ this.__internal.className = className; addClass(this.elements.root, className); } // maximize if start maximized if ( this.get('startMaximized')) { this.maximize(); }else if(this.isMaximized()){ restore(this); } updateAbsPositionFix(this); this.elements.root.removeAttribute('style'); removeClass(this.elements.root, classes.animationOut); addClass(this.elements.root, classes.animationIn); // set 1s fallback in case transition event doesn't fire clearTimeout( this.__internal.timerIn); this.__internal.timerIn = setTimeout( this.__internal.transitionInHandler, transition.supported ? 1000 : 100 ); if(isSafari){ // force desktop safari reflow var root = this.elements.root; root.style.display = 'none'; setTimeout(function(){root.style.display = 'block';}, 0); } //reflow reflow = this.elements.root.offsetWidth; // show dialog removeClass(this.elements.root, classes.hidden); //restore scroll to prevent document jump restoreScrollPosition(); // internal on show event if(typeof this.hooks.onshow === 'function'){ this.hooks.onshow.call(this); } // allow custom `onshow` method dispatchEvent('onshow', this); }else{ // reset move updates resetMove(this); // reset resize updates resetResize(this); // shake the dialog to indicate its already open addClass(this.elements.dialog, classes.shake); var self = this; setTimeout(function(){ removeClass(self.elements.dialog, classes.shake); },200); } return this; }, /** * Close the dialog * * @return {Object} The dialog instance */ close: function () { if (this.__internal.isOpen ) { // custom `onclosing` event if(dispatchEvent('onclosing', this) !== false){ unbindEvents(this); removeClass(this.elements.root, classes.animationIn); addClass(this.elements.root, classes.animationOut); // set 1s fallback in case transition event doesn't fire clearTimeout( this.__internal.timerOut ); this.__internal.timerOut = setTimeout( this.__internal.transitionOutHandler, transition.supported ? 1000 : 100 ); // hide dialog addClass(this.elements.root, classes.hidden); //reflow reflow = this.elements.modal.offsetWidth; // return focus to the last active element if (alertify.defaults.maintainFocus && this.__internal.activeElement) { this.__internal.activeElement.focus(); this.__internal.activeElement = null; } // remove custom dialog class on hide if (typeof this.__internal.className !== 'undefined' && this.__internal.className !== '') { removeClass(this.elements.root, this.__internal.className); } // internal on close event if(typeof this.hooks.onclose === 'function'){ this.hooks.onclose.call(this); } // allow custom `onclose` method dispatchEvent('onclose', this); //remove from open dialogs openDialogs.splice(openDialogs.indexOf(this),1); this.__internal.isOpen = false; ensureNoOverflow(); } } // last dialog and tab index was set by us, remove it. if(!openDialogs.length && tabindex === '0'){ document.body.removeAttribute('tabindex'); } return this; }, /** * Close all open dialogs except this. * * @return {undefined} */ closeOthers:function(){ alertify.closeAll(this); return this; }, /** * Destroys this dialog instance * * @return {undefined} */ destroy:function(){ if(this.__internal) { if (this.__internal.isOpen ) { //mark dialog for destruction, this will be called on tranistionOut event. this.__internal.destroy = function(){ destruct(this, initialize); }; //close the dialog to unbind all events. this.close(); }else if(!this.__internal.destroy){ destruct(this, initialize); } } return this; }, };