2024-12-27 23:05:39 +01:00
/ * *
* alertifyjs 1.14 . 0 http : //alertifyjs.com
* AlertifyJS is a javascript framework for developing pretty browser dialogs and notifications .
* Copyright 2024 Mohammad Younes < Mohammad @ alertifyjs . com > ( http : //alertifyjs.com)
* Licensed under GPL 3 < https : //opensource.org/licenses/gpl-3.0>*/
( function ( window ) {
'use strict' ;
var NOT _DISABLED _NOT _RESET = ':not(:disabled):not(.ajs-reset)' ;
/ * *
* Keys enum
* @ type { Object }
* /
var keys = {
ENTER : 13 ,
ESC : 27 ,
F1 : 112 ,
F12 : 123 ,
LEFT : 37 ,
RIGHT : 39 ,
TAB : 9
} ;
/ * *
* Default options
* @ type { Object }
* /
var defaults = {
autoReset : true ,
basic : false ,
closable : true ,
closableByDimmer : true ,
invokeOnCloseOff : false ,
frameless : false ,
defaultFocusOff : false ,
maintainFocus : true , //global default not per instance, applies to all dialogs
maximizable : true ,
modal : true ,
movable : true ,
moveBounded : false ,
overflow : true ,
padding : true ,
pinnable : true ,
pinned : true ,
preventBodyShift : false , //global default not per instance, applies to all dialogs
resizable : true ,
startMaximized : false ,
transition : 'pulse' ,
transitionOff : false ,
tabbable : [ 'button' , '[href]' , 'input' , 'select' , 'textarea' , '[tabindex]:not([tabindex^="-"])' + NOT _DISABLED _NOT _RESET ] . join ( NOT _DISABLED _NOT _RESET + ',' ) , //global
notifier : {
delay : 5 ,
position : 'bottom-right' ,
closeButton : false ,
classes : {
base : 'alertify-notifier' ,
prefix : 'ajs-' ,
message : 'ajs-message' ,
top : 'ajs-top' ,
right : 'ajs-right' ,
bottom : 'ajs-bottom' ,
left : 'ajs-left' ,
center : 'ajs-center' ,
visible : 'ajs-visible' ,
hidden : 'ajs-hidden' ,
close : 'ajs-close'
}
} ,
glossary : {
title : 'AlertifyJS' ,
ok : 'OK' ,
cancel : 'Cancel' ,
acccpt : 'Accept' ,
deny : 'Deny' ,
confirm : 'Confirm' ,
decline : 'Decline' ,
close : 'Close' ,
maximize : 'Maximize' ,
restore : 'Restore' ,
} ,
theme : {
input : 'ajs-input' ,
ok : 'ajs-ok' ,
cancel : 'ajs-cancel' ,
} ,
hooks : {
preinit : function ( ) { } ,
postinit : function ( ) { }
}
} ;
//holds open dialogs instances
var openDialogs = [ ] ;
/ * *
* [ Helper ] Adds the specified class ( es ) to the element .
*
* @ element { node } The element
* @ className { string } One or more space - separated classes to be added to the class attribute of the element .
*
* @ return { undefined }
* /
function addClass ( element , classNames ) {
element . className += ' ' + classNames ;
}
/ * *
* [ Helper ] Removes the specified class ( es ) from the element .
*
* @ element { node } The element
* @ className { string } One or more space - separated classes to be removed from the class attribute of the element .
*
* @ return { undefined }
* /
function removeClass ( element , classNames ) {
var original = element . className . split ( ' ' ) ;
var toBeRemoved = classNames . split ( ' ' ) ;
for ( var x = 0 ; x < toBeRemoved . length ; x += 1 ) {
var index = original . indexOf ( toBeRemoved [ x ] ) ;
if ( index > - 1 ) {
original . splice ( index , 1 ) ;
}
}
element . className = original . join ( ' ' ) ;
}
/ * *
* [ Helper ] Checks if the document is RTL
*
* @ return { Boolean } True if the document is RTL , false otherwise .
* /
function isRightToLeft ( ) {
return window . getComputedStyle ( document . body ) . direction === 'rtl' ;
}
/ * *
* [ Helper ] Get the document current scrollTop
*
* @ return { Number } current document scrollTop value
* /
function getScrollTop ( ) {
return ( ( document . documentElement && document . documentElement . scrollTop ) || document . body . scrollTop ) ;
}
/ * *
* [ Helper ] Get the document current scrollLeft
*
* @ return { Number } current document scrollLeft value
* /
function getScrollLeft ( ) {
return ( ( document . documentElement && document . documentElement . scrollLeft ) || document . body . scrollLeft ) ;
}
/ * *
* Helper : clear contents
*
* /
function clearContents ( element ) {
while ( element . lastChild ) {
element . removeChild ( element . lastChild ) ;
}
}
/ * *
* detects strings , checks for both string and String instances
* this is unlike typeof ( x ) === 'string' which only accepts primitive strings
*
* /
function isString ( thing ) {
return Object . prototype . toString . call ( thing ) === '[object String]' ;
}
/ * *
* Extends a given prototype by merging properties from base into sub .
*
* @ sub { Object } sub The prototype being overwritten .
* @ base { Object } base The prototype being written .
*
* @ return { Object } The extended prototype .
* /
function copy ( src ) {
if ( null === src ) {
return src ;
}
var cpy ;
if ( Array . isArray ( src ) ) {
cpy = [ ] ;
for ( var x = 0 ; x < src . length ; x += 1 ) {
cpy . push ( copy ( src [ x ] ) ) ;
}
return cpy ;
}
if ( src instanceof Date ) {
return new Date ( src . getTime ( ) ) ;
}
if ( src instanceof RegExp ) {
cpy = new RegExp ( src . source ) ;
cpy . global = src . global ;
cpy . ignoreCase = src . ignoreCase ;
cpy . multiline = src . multiline ;
cpy . lastIndex = src . lastIndex ;
return cpy ;
}
if ( typeof src === 'object' ) {
cpy = { } ;
// copy dialog pototype over definition.
for ( var prop in src ) {
if ( src . hasOwnProperty ( prop ) ) {
cpy [ prop ] = copy ( src [ prop ] ) ;
}
}
return cpy ;
}
return src ;
}
/ * *
* Helper : destruct the dialog
*
* /
function destruct ( instance , initialize ) {
if ( instance . elements ) {
//delete the dom and it's references.
var root = instance . elements . root ;
root . parentNode . removeChild ( root ) ;
delete instance . elements ;
//copy back initial settings.
instance . settings = copy ( instance . _ _settings ) ;
//re-reference init function.
instance . _ _init = initialize ;
//delete __internal variable to allow re-initialization.
delete instance . _ _internal ;
}
}
/ * *
* Test to check if passive event listeners are supported .
* /
var IsPassiveSupported = false ;
try {
var options = Object . defineProperty ( { } , 'passive' , {
get : function ( ) {
IsPassiveSupported = true ;
}
} ) ;
window . addEventListener ( 'test' , options , options ) ;
window . removeEventListener ( 'test' , options , options ) ;
} catch ( e ) { }
/ * *
* Removes an event listener
*
* @ param { HTMLElement } el The EventTarget to register the listenr on .
* @ param { string } event The event type to listen for .
* @ param { Function } handler The function to handle the event .
* @ param { boolean } useCapture Specifices if the event to be dispatched to the registered listener before being dispatched to any EventTarget beneath it in the DOM tree .
* @ param { boolean } passive A Boolean which , if true , indicates that the function specified by listener will never call preventDefault ( ) .
* /
var on = function ( el , event , fn , useCapture , passive ) {
el . addEventListener ( event , fn , IsPassiveSupported ? { capture : useCapture , passive : passive } : useCapture === true ) ;
} ;
/ * *
* Removes an event listener
*
* @ param { HTMLElement } el The EventTarget to unregister the listenr from .
* @ param { string } event The event type to remove .
* @ param { Function } fn The event handler to remove .
* @ param { boolean } useCapture Specifices if the event to be dispatched to the registered listener before being dispatched to any EventTarget beneath it in the DOM tree .
* @ param { boolean } passive A Boolean which , if true , indicates that the function specified by listener will never call preventDefault ( ) .
* /
var off = function ( el , event , fn , useCapture , passive ) {
el . removeEventListener ( event , fn , IsPassiveSupported ? { capture : useCapture , passive : passive } : useCapture === true ) ;
} ;
/ * *
* Prevent default event from firing
*
* @ param { Event } event Event object
* @ return { undefined }
function prevent ( event ) {
if ( event ) {
if ( event . preventDefault ) {
event . preventDefault ( ) ;
} else {
event . returnValue = false ;
}
}
}
* /
var transition = ( function ( ) {
var t , type ;
var supported = false ;
var transitions = {
'animation' : 'animationend' ,
'OAnimation' : 'oAnimationEnd oanimationend' ,
'msAnimation' : 'MSAnimationEnd' ,
'MozAnimation' : 'animationend' ,
'WebkitAnimation' : 'webkitAnimationEnd'
} ;
for ( t in transitions ) {
if ( document . documentElement . style [ t ] !== undefined ) {
type = transitions [ t ] ;
supported = true ;
break ;
}
}
return {
type : type ,
supported : supported
} ;
} ( ) ) ;
/ * *
* Creates event handler delegate that sends the instance as last argument .
*
* @ return { Function } a function wrapper which sends the instance as last argument .
* /
function delegate ( context , method ) {
return function ( ) {
if ( arguments . length > 0 ) {
var args = [ ] ;
for ( var x = 0 ; x < arguments . length ; x += 1 ) {
args . push ( arguments [ x ] ) ;
}
args . push ( context ) ;
return method . apply ( context , args ) ;
}
return method . apply ( context , [ null , context ] ) ;
} ;
}
/ * *
* Helper for creating a dialog close event .
*
* @ return { object }
* /
function createCloseEvent ( index , button ) {
return {
index : index ,
button : button ,
cancel : false
} ;
}
/ * *
* Helper for dispatching events .
*
* @ param { string } evenType The type of the event to disptach .
* @ param { object } instance The dialog instance disptaching the event .
*
* @ return { any } The result of the invoked function .
* /
function dispatchEvent ( eventType , instance ) {
if ( typeof instance . get ( eventType ) === 'function' ) {
return instance . get ( eventType ) . call ( instance ) ;
}
}
/ * *
* Super class for all dialogs
*
* @ return { Object } base dialog prototype
* /
var dialog = ( function ( ) {
var //holds the list of used keys.
usedKeys = [ ] ,
//dummy variable, used to trigger dom reflow.
reflow = null ,
//holds body tab index in case it has any.
tabindex = false ,
//condition for detecting safari
isSafari = window . navigator . userAgent . indexOf ( 'Safari' ) > - 1 && window . navigator . userAgent . indexOf ( 'Chrome' ) < 0 ,
//dialog building blocks
templates = {
dimmer : '<div class="ajs-dimmer"></div>' ,
/*tab index required to fire click event before body focus*/
modal : '<div class="ajs-modal" tabindex="0"></div>' ,
dialog : '<div class="ajs-dialog" tabindex="0"></div>' ,
reset : '<button class="ajs-reset"></button>' ,
commands : '<div class="ajs-commands"><button class="ajs-pin"></button><button class="ajs-maximize"></button><button class="ajs-close"></button></div>' ,
header : '<div class="ajs-header"></div>' ,
body : '<div class="ajs-body"></div>' ,
content : '<div class="ajs-content"></div>' ,
footer : '<div class="ajs-footer"></div>' ,
buttons : { primary : '<div class="ajs-primary ajs-buttons"></div>' , auxiliary : '<div class="ajs-auxiliary ajs-buttons"></div>' } ,
button : '<button class="ajs-button"></button>' ,
resizeHandle : '<div class="ajs-handle"></div>' ,
} ,
//common class names
classes = {
animationIn : 'ajs-in' ,
animationOut : 'ajs-out' ,
base : 'alertify' ,
basic : 'ajs-basic' ,
capture : 'ajs-capture' ,
closable : 'ajs-closable' ,
fixed : 'ajs-fixed' ,
frameless : 'ajs-frameless' ,
hidden : 'ajs-hidden' ,
maximize : 'ajs-maximize' ,
maximized : 'ajs-maximized' ,
maximizable : 'ajs-maximizable' ,
modeless : 'ajs-modeless' ,
movable : 'ajs-movable' ,
noSelection : 'ajs-no-selection' ,
noOverflow : 'ajs-no-overflow' ,
noPadding : 'ajs-no-padding' ,
pin : 'ajs-pin' ,
pinnable : 'ajs-pinnable' ,
prefix : 'ajs-' ,
resizable : 'ajs-resizable' ,
restore : 'ajs-restore' ,
shake : 'ajs-shake' ,
unpinned : 'ajs-unpinned' ,
noTransition : 'ajs-no-transition'
} ;
/ * *
* Helper : initializes the dialog instance
*
* @ return { Number } The total count of currently open modals .
* /
function initialize ( instance ) {
if ( ! instance . _ _internal ) {
//invoke preinit global hook
alertify . defaults . hooks . preinit ( instance ) ;
//no need to expose init after this.
delete instance . _ _init ;
//keep a copy of initial dialog settings
if ( ! instance . _ _settings ) {
instance . _ _settings = copy ( instance . settings ) ;
}
//get dialog buttons/focus setup
var setup ;
if ( typeof instance . setup === 'function' ) {
setup = instance . setup ( ) ;
setup . options = setup . options || { } ;
setup . focus = setup . focus || { } ;
} else {
setup = {
buttons : [ ] ,
focus : {
element : null ,
select : false
} ,
options : {
}
} ;
}
//initialize hooks object.
if ( typeof instance . hooks !== 'object' ) {
instance . hooks = { } ;
}
//copy buttons defintion
var buttonsDefinition = [ ] ;
if ( Array . isArray ( setup . buttons ) ) {
for ( var b = 0 ; b < setup . buttons . length ; b += 1 ) {
var ref = setup . buttons [ b ] ,
cpy = { } ;
for ( var i in ref ) {
if ( ref . hasOwnProperty ( i ) ) {
cpy [ i ] = ref [ i ] ;
}
}
buttonsDefinition . push ( cpy ) ;
}
}
var internal = instance . _ _internal = {
/ * *
* Flag holding the open state of the dialog
*
* @ type { Boolean }
* /
isOpen : false ,
/ * *
* Active element is the element that will receive focus after
* closing the dialog . It defaults as the body tag , but gets updated
* to the last focused element before the dialog was opened .
*
* @ type { Node }
* /
activeElement : document . body ,
timerIn : undefined ,
timerOut : undefined ,
buttons : buttonsDefinition ,
focus : setup . focus ,
options : {
title : undefined ,
modal : undefined ,
basic : undefined ,
frameless : undefined ,
defaultFocusOff : undefined ,
pinned : undefined ,
movable : undefined ,
moveBounded : undefined ,
resizable : undefined ,
autoReset : undefined ,
closable : undefined ,
closableByDimmer : undefined ,
invokeOnCloseOff : undefined ,
maximizable : undefined ,
startMaximized : undefined ,
pinnable : undefined ,
transition : undefined ,
transitionOff : undefined ,
padding : undefined ,
overflow : undefined ,
onshow : undefined ,
onclosing : undefined ,
onclose : undefined ,
onfocus : undefined ,
onmove : undefined ,
onmoved : undefined ,
onresize : undefined ,
onresized : undefined ,
onmaximize : undefined ,
onmaximized : undefined ,
onrestore : undefined ,
onrestored : undefined
} ,
resetHandler : undefined ,
beginMoveHandler : undefined ,
beginResizeHandler : undefined ,
bringToFrontHandler : undefined ,
modalClickHandler : undefined ,
buttonsClickHandler : undefined ,
commandsClickHandler : undefined ,
transitionInHandler : undefined ,
transitionOutHandler : undefined ,
destroy : undefined
} ;
var elements = { } ;
//root node
elements . root = document . createElement ( 'div' ) ;
//prevent FOUC in case of async styles loading.
elements . root . style . display = 'none' ;
elements . root . className = classes . base + ' ' + classes . hidden + ' ' ;
elements . root . innerHTML = templates . dimmer + templates . modal ;
//dimmer
elements . dimmer = elements . root . firstChild ;
//dialog
elements . modal = elements . root . lastChild ;
elements . modal . innerHTML = templates . dialog ;
elements . dialog = elements . modal . firstChild ;
elements . dialog . innerHTML = templates . reset + templates . commands + templates . header + templates . body + templates . footer + templates . resizeHandle + templates . reset ;
//reset links
elements . reset = [ ] ;
elements . reset . push ( elements . dialog . firstChild ) ;
elements . reset . push ( elements . dialog . lastChild ) ;
//commands
elements . commands = { } ;
elements . commands . container = elements . reset [ 0 ] . nextSibling ;
elements . commands . pin = elements . commands . container . firstChild ;
elements . commands . maximize = elements . commands . pin . nextSibling ;
elements . commands . close = elements . commands . maximize . nextSibling ;
//header
elements . header = elements . commands . container . nextSibling ;
//body
elements . body = elements . header . nextSibling ;
elements . body . innerHTML = templates . content ;
elements . content = elements . body . firstChild ;
//footer
elements . footer = elements . body . nextSibling ;
elements . footer . innerHTML = templates . buttons . auxiliary + templates . buttons . primary ;
//resize handle
elements . resizeHandle = elements . footer . nextSibling ;
//buttons
elements . buttons = { } ;
elements . buttons . auxiliary = elements . footer . firstChild ;
elements . buttons . primary = elements . buttons . auxiliary . nextSibling ;
elements . buttons . primary . innerHTML = templates . button ;
elements . buttonTemplate = elements . buttons . primary . firstChild ;
//remove button template
elements . buttons . primary . removeChild ( elements . buttonTemplate ) ;
for ( var x = 0 ; x < instance . _ _internal . buttons . length ; x += 1 ) {
var button = instance . _ _internal . buttons [ x ] ;
// add to the list of used keys.
if ( usedKeys . indexOf ( button . key ) < 0 ) {
usedKeys . push ( button . key ) ;
}
button . element = elements . buttonTemplate . cloneNode ( ) ;
button . element . innerHTML = button . text ;
if ( typeof button . className === 'string' && button . className !== '' ) {
addClass ( button . element , button . className ) ;
}
for ( var key in button . attrs ) {
if ( key !== 'className' && button . attrs . hasOwnProperty ( key ) ) {
button . element . setAttribute ( key , button . attrs [ key ] ) ;
}
}
if ( button . scope === 'auxiliary' ) {
elements . buttons . auxiliary . appendChild ( button . element ) ;
} else {
elements . buttons . primary . appendChild ( button . element ) ;
}
}
//make elements pubic
instance . elements = elements ;
//save event handlers delegates
internal . resetHandler = delegate ( instance , onReset ) ;
internal . beginMoveHandler = delegate ( instance , beginMove ) ;
internal . beginResizeHandler = delegate ( instance , beginResize ) ;
internal . bringToFrontHandler = delegate ( instance , bringToFront ) ;
internal . modalClickHandler = delegate ( instance , modalClickHandler ) ;
internal . buttonsClickHandler = delegate ( instance , buttonsClickHandler ) ;
internal . commandsClickHandler = delegate ( instance , commandsClickHandler ) ;
internal . transitionInHandler = delegate ( instance , handleTransitionInEvent ) ;
internal . transitionOutHandler = delegate ( instance , handleTransitionOutEvent ) ;
//settings
for ( var opKey in internal . options ) {
if ( setup . options [ opKey ] !== undefined ) {
// if found in user options
instance . set ( opKey , setup . options [ opKey ] ) ;
} else if ( alertify . defaults . hasOwnProperty ( opKey ) ) {
// else if found in defaults options
instance . set ( opKey , alertify . defaults [ opKey ] ) ;
} else if ( opKey === 'title' ) {
// else if title key, use alertify.defaults.glossary
instance . set ( opKey , alertify . defaults . glossary [ opKey ] ) ;
}
}
// allow dom customization
if ( typeof instance . build === 'function' ) {
instance . build ( ) ;
}
//invoke postinit global hook
alertify . defaults . hooks . postinit ( instance ) ;
}
//add to the end of the DOM tree.
document . body . appendChild ( instance . elements . root ) ;
}
/ * *
* Helper : maintains scroll position
*
* /
var scrollX , scrollY ;
function saveScrollPosition ( ) {
scrollX = getScrollLeft ( ) ;
scrollY = getScrollTop ( ) ;
}
function restoreScrollPosition ( ) {
window . scrollTo ( scrollX , scrollY ) ;
}
/ * *
* Helper : adds / removes no - overflow class from body
*
* /
function ensureNoOverflow ( ) {
var requiresNoOverflow = 0 ;
for ( var x = 0 ; x < openDialogs . length ; x += 1 ) {
var instance = openDialogs [ x ] ;
if ( instance . isModal ( ) || instance . isMaximized ( ) ) {
requiresNoOverflow += 1 ;
}
}
if ( requiresNoOverflow === 0 && document . body . className . indexOf ( classes . noOverflow ) >= 0 ) {
//last open modal or last maximized one
removeClass ( document . body , classes . noOverflow ) ;
preventBodyShift ( false ) ;
} else if ( requiresNoOverflow > 0 && document . body . className . indexOf ( classes . noOverflow ) < 0 ) {
//first open modal or first maximized one
preventBodyShift ( true ) ;
addClass ( document . body , classes . noOverflow ) ;
}
}
var top = '' , topScroll = 0 ;
/ * *
* Helper : prevents body shift .
*
* /
function preventBodyShift ( add ) {
if ( alertify . defaults . preventBodyShift ) {
if ( add && document . documentElement . scrollHeight > document . documentElement . clientHeight ) { //&& openDialogs[openDialogs.length-1].elements.dialog.clientHeight <= document.documentElement.clientHeight){
topScroll = scrollY ;
top = window . getComputedStyle ( document . body ) . top ;
addClass ( document . body , classes . fixed ) ;
document . body . style . top = - scrollY + 'px' ;
} else if ( ! add ) {
scrollY = topScroll ;
document . body . style . top = top ;
removeClass ( document . body , classes . fixed ) ;
restoreScrollPosition ( ) ;
}
}
}
/ * *
* Sets the name of the transition used to show / hide the dialog
*
* @ param { Object } instance The dilog instance .
*
* /
function updateTransition ( instance , value , oldValue ) {
if ( isString ( oldValue ) ) {
removeClass ( instance . elements . root , classes . prefix + oldValue ) ;
}
addClass ( instance . elements . root , classes . prefix + value ) ;
reflow = instance . elements . root . offsetWidth ;
}
/ * *
* Toggles the dialog no transition
*
* @ param { Object } instance The dilog instance .
*
* @ return { undefined }
* /
function updateTransitionOff ( instance ) {
if ( instance . get ( 'transitionOff' ) ) {
// add class
addClass ( instance . elements . root , classes . noTransition ) ;
} else {
// remove class
removeClass ( instance . elements . root , classes . noTransition ) ;
}
}
/ * *
* Toggles the dialog display mode
*
* @ param { Object } instance The dilog instance .
*
* @ return { undefined }
* /
function updateDisplayMode ( instance ) {
if ( instance . get ( 'modal' ) ) {
//make modal
removeClass ( instance . elements . root , classes . modeless ) ;
//only if open
if ( instance . isOpen ( ) ) {
unbindModelessEvents ( instance ) ;
//in case a pinned modless dialog was made modal while open.
updateAbsPositionFix ( instance ) ;
ensureNoOverflow ( ) ;
}
} else {
//make modelss
addClass ( instance . elements . root , classes . modeless ) ;
//only if open
if ( instance . isOpen ( ) ) {
bindModelessEvents ( instance ) ;
//in case pin/unpin was called while a modal is open
updateAbsPositionFix ( instance ) ;
ensureNoOverflow ( ) ;
}
}
}
/ * *
* Toggles the dialog basic view mode
*
* @ param { Object } instance The dilog instance .
*
* @ return { undefined }
* /
function updateBasicMode ( instance ) {
if ( instance . get ( 'basic' ) ) {
// add class
addClass ( instance . elements . root , classes . basic ) ;
} else {
// remove class
removeClass ( instance . elements . root , classes . basic ) ;
}
}
/ * *
* Toggles the dialog frameless view mode
*
* @ param { Object } instance The dilog instance .
*
* @ return { undefined }
* /
function updateFramelessMode ( instance ) {
if ( instance . get ( 'frameless' ) ) {
// add class
addClass ( instance . elements . root , classes . frameless ) ;
} else {
// remove class
removeClass ( instance . elements . root , classes . frameless ) ;
}
}
/ * *
* Helper : Brings the modeless dialog to front , attached to modeless dialogs .
*
* @ param { Event } event Focus event
* @ param { Object } instance The dilog instance .
*
* @ return { undefined }
* /
function bringToFront ( event , instance ) {
// Do not bring to front if preceeded by an open modal
var index = openDialogs . indexOf ( instance ) ;
for ( var x = index + 1 ; x < openDialogs . length ; x += 1 ) {
if ( openDialogs [ x ] . isModal ( ) ) {
return ;
}
}
// Bring to front by making it the last child.
if ( document . body . lastChild !== instance . elements . root ) {
document . body . appendChild ( instance . elements . root ) ;
//also make sure its at the end of the list
openDialogs . splice ( openDialogs . indexOf ( instance ) , 1 ) ;
openDialogs . push ( instance ) ;
setFocus ( instance ) ;
}
return false ;
}
/ * *
* Helper : reflects dialogs options updates
*
* @ param { Object } instance The dilog instance .
* @ param { String } option The updated option name .
*
* @ return { undefined }
* /
function optionUpdated ( instance , option , oldValue , newValue ) {
switch ( option ) {
case 'title' :
instance . setHeader ( newValue ) ;
break ;
case 'modal' :
updateDisplayMode ( instance ) ;
break ;
case 'basic' :
updateBasicMode ( instance ) ;
break ;
case 'frameless' :
updateFramelessMode ( instance ) ;
break ;
case 'pinned' :
updatePinned ( instance ) ;
break ;
case 'closable' :
updateClosable ( instance ) ;
break ;
case 'maximizable' :
updateMaximizable ( instance ) ;
break ;
case 'pinnable' :
updatePinnable ( instance ) ;
break ;
case 'movable' :
updateMovable ( instance ) ;
break ;
case 'resizable' :
updateResizable ( instance ) ;
break ;
case 'padding' :
if ( newValue ) {
removeClass ( instance . elements . root , classes . noPadding ) ;
} else if ( instance . elements . root . className . indexOf ( classes . noPadding ) < 0 ) {
addClass ( instance . elements . root , classes . noPadding ) ;
}
break ;
case 'overflow' :
if ( newValue ) {
removeClass ( instance . elements . root , classes . noOverflow ) ;
} else if ( instance . elements . root . className . indexOf ( classes . noOverflow ) < 0 ) {
addClass ( instance . elements . root , classes . noOverflow ) ;
}
break ;
case 'transition' :
updateTransition ( instance , newValue , oldValue ) ;
break ;
case 'transitionOff' :
updateTransitionOff ( instance ) ;
break ;
}
// internal on option updated event
if ( typeof instance . hooks . onupdate === 'function' ) {
instance . hooks . onupdate . call ( instance , option , oldValue , newValue ) ;
}
}
/ * *
* Helper : reflects dialogs options updates
*
* @ param { Object } instance The dilog instance .
* @ param { Object } obj The object to set / get a value on / from .
* @ param { Function } callback The callback function to call if the key was found .
* @ 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 ) .
* @ param { String } option The updated option name .
*
* @ return { Object } result object
* The result objects has an 'op' property , indicating of this is a SET or GET operation .
* GET :
* - found : a flag indicating if the key was found or not .
* - value : the property value .
* SET :
* - items : a list of key value pairs of the properties being set .
* each contains :
* - found : a flag indicating if the key was found or not .
* - key : the property key .
* - value : the property value .
* /
function update ( instance , obj , callback , key , value ) {
var result = { op : undefined , items : [ ] } ;
if ( typeof value === 'undefined' && typeof key === 'string' ) {
//get
result . op = 'get' ;
if ( obj . hasOwnProperty ( key ) ) {
result . found = true ;
result . value = obj [ key ] ;
} else {
result . found = false ;
result . value = undefined ;
}
}
else
{
var old ;
//set
result . op = 'set' ;
if ( typeof key === 'object' ) {
//set multiple
var args = key ;
for ( var prop in args ) {
if ( obj . hasOwnProperty ( prop ) ) {
if ( obj [ prop ] !== args [ prop ] ) {
old = obj [ prop ] ;
obj [ prop ] = args [ prop ] ;
callback . call ( instance , prop , old , args [ prop ] ) ;
}
result . items . push ( { 'key' : prop , 'value' : args [ prop ] , 'found' : true } ) ;
} else {
result . items . push ( { 'key' : prop , 'value' : args [ prop ] , 'found' : false } ) ;
}
}
} else if ( typeof key === 'string' ) {
//set single
if ( obj . hasOwnProperty ( key ) ) {
if ( obj [ key ] !== value ) {
old = obj [ key ] ;
obj [ key ] = value ;
callback . call ( instance , key , old , value ) ;
}
result . items . push ( { 'key' : key , 'value' : value , 'found' : true } ) ;
} else {
result . items . push ( { 'key' : key , 'value' : value , 'found' : false } ) ;
}
} else {
//invalid params
throw new Error ( 'args must be a string or object' ) ;
}
}
return result ;
}
/ * *
* Triggers a close event .
*
* @ param { Object } instance The dilog instance .
*
* @ return { undefined }
* /
function triggerClose ( instance ) {
var found ;
triggerCallback ( instance , function ( button ) {
return found = instance . get ( 'invokeOnCloseOff' ) !== true && ( button . invokeOnClose === true ) ;
} ) ;
//none of the buttons registered as onclose callback
//close the dialog
if ( ! found && instance . isOpen ( ) ) {
instance . close ( ) ;
}
}
/ * *
* Dialogs commands event handler , attached to the dialog commands element .
*
* @ param { Event } event DOM event object .
* @ param { Object } instance The dilog instance .
*
* @ return { undefined }
* /
function commandsClickHandler ( event , instance ) {
var target = event . srcElement || event . target ;
switch ( target ) {
case instance . elements . commands . pin :
if ( ! instance . isPinned ( ) ) {
pin ( instance ) ;
} else {
unpin ( instance ) ;
}
break ;
case instance . elements . commands . maximize :
if ( ! instance . isMaximized ( ) ) {
maximize ( instance ) ;
} else {
restore ( instance ) ;
}
break ;
case instance . elements . commands . close :
triggerClose ( instance ) ;
break ;
}
return false ;
}
/ * *
* Helper : pins the modeless dialog .
*
* @ param { Object } instance The dialog instance .
*
* @ return { undefined }
* /
function pin ( instance ) {
//pin the dialog
instance . set ( 'pinned' , true ) ;
}
/ * *
* Helper : unpins the modeless dialog .
*
* @ param { Object } instance The dilog instance .
*
* @ return { undefined }
* /
function unpin ( instance ) {
//unpin the dialog
instance . set ( 'pinned' , false ) ;
}
/ * *
* Helper : enlarges the dialog to fill the entire screen .
*
* @ param { Object } instance The dilog instance .
*
* @ return { undefined }
* /
function maximize ( instance ) {
// allow custom `onmaximize` method
dispatchEvent ( 'onmaximize' , instance ) ;
//maximize the dialog
addClass ( instance . elements . root , classes . maximized ) ;
if ( instance . isOpen ( ) ) {
ensureNoOverflow ( ) ;
}
// allow custom `onmaximized` method
dispatchEvent ( 'onmaximized' , instance ) ;
}
/ * *
* Helper : returns the dialog to its former size .
*
* @ param { Object } instance The dilog instance .
*
* @ return { undefined }
* /
function restore ( instance ) {
// allow custom `onrestore` method
dispatchEvent ( 'onrestore' , instance ) ;
//maximize the dialog
removeClass ( instance . elements . root , classes . maximized ) ;
if ( instance . isOpen ( ) ) {
ensureNoOverflow ( ) ;
}
// allow custom `onrestored` method
dispatchEvent ( 'onrestored' , instance ) ;
}
/ * *
* Show or hide the maximize box .
*
* @ param { Object } instance The dilog instance .
* @ param { Boolean } on True to add the behavior , removes it otherwise .
*
* @ return { undefined }
* /
function updatePinnable ( instance ) {
if ( instance . get ( 'pinnable' ) ) {
// add class
addClass ( instance . elements . root , classes . pinnable ) ;
} else {
// remove class
removeClass ( instance . elements . root , classes . pinnable ) ;
}
}
/ * *
* Helper : Fixes the absolutly positioned modal div position .
*
* @ param { Object } instance The dialog instance .
*
* @ return { undefined }
* /
function addAbsPositionFix ( instance ) {
var scrollLeft = getScrollLeft ( ) ;
instance . elements . modal . style . marginTop = getScrollTop ( ) + 'px' ;
instance . elements . modal . style . marginLeft = scrollLeft + 'px' ;
instance . elements . modal . style . marginRight = ( - scrollLeft ) + 'px' ;
}
/ * *
* Helper : Removes the absolutly positioned modal div position fix .
*
* @ param { Object } instance The dialog instance .
*
* @ return { undefined }
* /
function removeAbsPositionFix ( instance ) {
var marginTop = parseInt ( instance . elements . modal . style . marginTop , 10 ) ;
var marginLeft = parseInt ( instance . elements . modal . style . marginLeft , 10 ) ;
instance . elements . modal . style . marginTop = '' ;
instance . elements . modal . style . marginLeft = '' ;
instance . elements . modal . style . marginRight = '' ;
if ( instance . isOpen ( ) ) {
var top = 0 ,
left = 0
;
if ( instance . elements . dialog . style . top !== '' ) {
top = parseInt ( instance . elements . dialog . style . top , 10 ) ;
}
instance . elements . dialog . style . top = ( top + ( marginTop - getScrollTop ( ) ) ) + 'px' ;
if ( instance . elements . dialog . style . left !== '' ) {
left = parseInt ( instance . elements . dialog . style . left , 10 ) ;
}
instance . elements . dialog . style . left = ( left + ( marginLeft - getScrollLeft ( ) ) ) + 'px' ;
}
}
/ * *
* Helper : Adds / Removes the absolutly positioned modal div position fix based on its pinned setting .
*
* @ param { Object } instance The dialog instance .
*
* @ return { undefined }
* /
function updateAbsPositionFix ( instance ) {
// if modeless and unpinned add fix
if ( ! instance . get ( 'modal' ) && ! instance . get ( 'pinned' ) ) {
addAbsPositionFix ( instance ) ;
} else {
removeAbsPositionFix ( instance ) ;
}
}
/ * *
* Toggles the dialog position lock | modeless only .
*
* @ param { Object } instance The dilog instance .
* @ param { Boolean } on True to make it modal , false otherwise .
*
* @ return { undefined }
* /
function updatePinned ( instance ) {
if ( instance . get ( 'pinned' ) ) {
removeClass ( instance . elements . root , classes . unpinned ) ;
if ( instance . isOpen ( ) ) {
removeAbsPositionFix ( instance ) ;
}
} else {
addClass ( instance . elements . root , classes . unpinned ) ;
if ( instance . isOpen ( ) && ! instance . isModal ( ) ) {
addAbsPositionFix ( instance ) ;
}
}
}
/ * *
* Show or hide the maximize box .
*
* @ param { Object } instance The dilog instance .
* @ param { Boolean } on True to add the behavior , removes it otherwise .
*
* @ return { undefined }
* /
function updateMaximizable ( instance ) {
if ( instance . get ( 'maximizable' ) ) {
// add class
addClass ( instance . elements . root , classes . maximizable ) ;
} else {
// remove class
removeClass ( instance . elements . root , classes . maximizable ) ;
}
}
/ * *
* Show or hide the close box .
*
* @ param { Object } instance The dilog instance .
* @ param { Boolean } on True to add the behavior , removes it otherwise .
*
* @ return { undefined }
* /
function updateClosable ( instance ) {
if ( instance . get ( 'closable' ) ) {
// add class
addClass ( instance . elements . root , classes . closable ) ;
bindClosableEvents ( instance ) ;
} else {
// remove class
removeClass ( instance . elements . root , classes . closable ) ;
unbindClosableEvents ( instance ) ;
}
}
var cancelClick = false , // flag to cancel click event if already handled by end resize event (the mousedown, mousemove, mouseup sequence fires a click event.).
modalClickHandlerTS = 0 // stores last click timestamp to prevent executing the handler twice on double click.
;
/ * *
* Helper : closes the modal dialog when clicking the modal
*
* @ param { Event } event DOM event object .
* @ param { Object } instance The dilog instance .
*
* @ return { undefined }
* /
function modalClickHandler ( event , instance ) {
if ( event . timeStamp - modalClickHandlerTS > 200 && ( modalClickHandlerTS = event . timeStamp ) && ! cancelClick ) {
var target = event . srcElement || event . target ;
if ( instance . get ( 'closableByDimmer' ) === true && target === instance . elements . modal ) {
triggerClose ( instance ) ;
}
}
cancelClick = false ;
}
// stores last call timestamp to prevent triggering the callback twice.
var callbackTS = 0 ;
// flag to cancel keyup event if already handled by click event (pressing Enter on a focusted button).
var cancelKeyup = false ;
/ * *
* Helper : triggers a button callback
*
* @ param { Object } The dilog instance .
* @ param { Function } Callback to check which button triggered the event .
*
* @ return { undefined }
* /
function triggerCallback ( instance , check ) {
if ( Date . now ( ) - callbackTS > 200 && ( callbackTS = Date . now ( ) ) ) {
for ( var idx = 0 ; idx < instance . _ _internal . buttons . length ; idx += 1 ) {
var button = instance . _ _internal . buttons [ idx ] ;
if ( ! button . element . disabled && check ( button ) ) {
var closeEvent = createCloseEvent ( idx , button ) ;
if ( typeof instance . callback === 'function' ) {
instance . callback . apply ( instance , [ closeEvent ] ) ;
}
//close the dialog only if not canceled.
if ( closeEvent . cancel === false ) {
instance . close ( ) ;
}
break ;
}
}
}
}
/ * *
* Clicks event handler , attached to the dialog footer .
*
* @ param { Event } DOM event object .
* @ param { Object } The dilog instance .
*
* @ return { undefined }
* /
function buttonsClickHandler ( event , instance ) {
var target = event . srcElement || event . target ;
triggerCallback ( instance , function ( button ) {
// if this button caused the click, cancel keyup event
return button . element . contains ( target ) && ( cancelKeyup = true ) ;
} ) ;
}
/ * *
* Keyup event handler , attached to the document . body
*
* @ param { Event } DOM event object .
* @ param { Object } The dilog instance .
*
* @ return { undefined }
* /
function keyupHandler ( event ) {
//hitting enter while button has focus will trigger keyup too.
//ignore if handled by clickHandler
if ( cancelKeyup ) {
cancelKeyup = false ;
return ;
}
var instance = openDialogs [ openDialogs . length - 1 ] ;
var keyCode = event . keyCode ;
if ( instance . _ _internal . buttons . length === 0 && keyCode === keys . ESC && instance . get ( 'closable' ) === true ) {
triggerClose ( instance ) ;
return false ;
} else if ( usedKeys . indexOf ( keyCode ) > - 1 ) {
triggerCallback ( instance , function ( button ) {
return button . key === keyCode ;
} ) ;
return false ;
}
}
/ * *
* Keydown event handler , attached to the document . body
*
* @ param { Event } DOM event object .
* @ param { Object } The dilog instance .
*
* @ return { undefined }
* /
function keydownHandler ( event ) {
var instance = openDialogs [ openDialogs . length - 1 ] ;
var keyCode = event . keyCode ;
if ( keyCode === keys . LEFT || keyCode === keys . RIGHT ) {
var buttons = instance . _ _internal . buttons ;
for ( var x = 0 ; x < buttons . length ; x += 1 ) {
if ( document . activeElement === buttons [ x ] . element ) {
switch ( keyCode ) {
case keys . LEFT :
buttons [ ( x || buttons . length ) - 1 ] . element . focus ( ) ;
return ;
case keys . RIGHT :
buttons [ ( x + 1 ) % buttons . length ] . element . focus ( ) ;
return ;
}
}
}
} else if ( keyCode < keys . F12 + 1 && keyCode > keys . F1 - 1 && usedKeys . indexOf ( keyCode ) > - 1 ) {
event . preventDefault ( ) ;
event . stopPropagation ( ) ;
triggerCallback ( instance , function ( button ) {
return button . key === keyCode ;
} ) ;
return false ;
}
}
/ * *
* Sets focus to proper dialog element
*
* @ param { Object } instance The dilog instance .
* @ param { Node } [ resetTarget = undefined ] DOM element to reset focus to .
*
* @ return { undefined }
* /
function setFocus ( instance , resetTarget ) {
// reset target has already been determined.
if ( resetTarget ) {
resetTarget . focus ( ) ;
} else {
// current instance focus settings
var focus = instance . _ _internal . focus ;
// the focus element.
var element = focus . element ;
switch ( typeof focus . element ) {
// a number means a button index
case 'number' :
if ( instance . _ _internal . buttons . length > focus . element ) {
//in basic view, skip focusing the buttons.
if ( instance . get ( 'basic' ) === true ) {
element = instance . elements . reset [ 0 ] ;
} else {
element = instance . _ _internal . buttons [ focus . element ] . element ;
}
}
break ;
// a string means querySelector to select from dialog body contents.
case 'string' :
element = instance . elements . body . querySelector ( focus . element ) ;
break ;
// a function should return the focus element.
case 'function' :
element = focus . element . call ( instance ) ;
break ;
}
// if no focus element, default to first reset element.
if ( instance . get ( 'defaultFocusOff' ) === true || ( ( typeof element === 'undefined' || element === null ) && instance . _ _internal . buttons . length === 0 ) ) {
element = instance . elements . reset [ 0 ] ;
}
// focus
if ( element && element . focus ) {
element . focus ( ) ;
// if selectable
if ( focus . select && element . select ) {
element . select ( ) ;
}
}
}
}
/ * *
* Focus event handler , attached to document . body and dialogs own reset links .
* handles the focus for modal dialogs only .
*
* @ param { Event } event DOM focus event object .
* @ param { Object } instance The dilog instance .
*
* @ return { undefined }
* /
function onReset ( event , instance ) {
// should work on last modal if triggered from document.body
if ( ! instance ) {
for ( var x = openDialogs . length - 1 ; x > - 1 ; x -= 1 ) {
if ( openDialogs [ x ] . isModal ( ) ) {
instance = openDialogs [ x ] ;
break ;
}
}
}
if ( instance ) {
// if modal
if ( instance . isModal ( ) ) {
// determine reset target to enable forward/backward tab cycle.
var firstReset = instance . elements . reset [ 0 ] ,
lastReset = instance . elements . reset [ 1 ] ,
lastFocusedElement = event . relatedTarget ,
within = instance . elements . root . contains ( lastFocusedElement ) ,
target = event . srcElement || event . target ,
resetTarget ;
//if the previous focused element element was outside the modal do nthing
if ( /*first show */
( target === firstReset && ! within ) ||
/*focus cycle */
( target === lastReset && lastFocusedElement === firstReset ) ) {
return ;
} else if ( target === lastReset || target === document . body ) {
resetTarget = firstReset ;
} else if ( target === firstReset && lastFocusedElement === lastReset ) {
resetTarget = findTabbable ( instance ) ;
} else if ( target === firstReset && within ) {
resetTarget = findTabbable ( instance , true ) ;
}
// focus
setFocus ( instance , resetTarget ) ;
}
}
}
function findTabbable ( instance , last ) {
var tabbables = [ ] . slice . call ( instance . elements . dialog . querySelectorAll ( defaults . tabbable ) ) ;
if ( last ) {
tabbables . reverse ( ) ;
}
for ( var x = 0 ; x < tabbables . length ; x += 1 ) {
var tabbable = tabbables [ x ] ;
//check if visible
if ( ! ! ( tabbable . offsetParent || tabbable . offsetWidth || tabbable . offsetHeight || tabbable . getClientRects ( ) . length ) ) {
return tabbable ;
}
}
}
function recycleTab ( event ) {
var instance = openDialogs [ openDialogs . length - 1 ] ;
if ( instance && event . shiftKey && event . keyCode === keys . TAB ) {
instance . elements . reset [ 1 ] . focus ( ) ;
}
}
/ * *
* Transition in transitionend event handler .
*
* @ param { Event } TransitionEnd event object .
* @ param { Object } The dilog instance .
*
* @ return { undefined }
* /
function handleTransitionInEvent ( event , instance ) {
// clear the timer
clearTimeout ( instance . _ _internal . timerIn ) ;
// once transition is complete, set focus
setFocus ( instance ) ;
// allow handling key up after transition ended.
cancelKeyup = false ;
// allow custom `onfocus` method
dispatchEvent ( 'onfocus' , instance ) ;
// unbind the event
off ( instance . elements . dialog , transition . type , instance . _ _internal . transitionInHandler ) ;
removeClass ( instance . elements . root , classes . animationIn ) ;
}
/ * *
* Transition out transitionend event handler .
*
* @ param { Event } TransitionEnd event object .
* @ param { Object } The dilog instance .
*
* @ return { undefined }
* /
function handleTransitionOutEvent ( event , instance ) {
// clear the timer
clearTimeout ( instance . _ _internal . timerOut ) ;
// unbind the event
off ( instance . elements . dialog , transition . type , instance . _ _internal . transitionOutHandler ) ;
// reset move updates
resetMove ( instance ) ;
// reset resize updates
resetResize ( instance ) ;
// restore if maximized
if ( instance . isMaximized ( ) && ! instance . get ( 'startMaximized' ) ) {
restore ( instance ) ;
}
//destory the instance
if ( typeof instance . _ _internal . destroy === 'function' ) {
instance . _ _internal . destroy . apply ( instance ) ;
}
}
/* Controls moving a dialog around */
//holde the current moving instance
var movable = null ,
//holds the current X offset when move starts
offsetX = 0 ,
//holds the current Y offset when move starts
offsetY = 0 ,
xProp = 'pageX' ,
yProp = 'pageY' ,
bounds = null ,
refreshTop = false ,
moveDelegate = null
;
/ * *
* Helper : sets the element top / left coordinates
*
* @ param { Event } event DOM event object .
* @ param { Node } element The element being moved .
*
* @ return { undefined }
* /
function moveElement ( event , element ) {
var left = ( event [ xProp ] - offsetX ) ,
top = ( event [ yProp ] - offsetY ) ;
if ( refreshTop ) {
top -= document . body . scrollTop ;
}
element . style . left = left + 'px' ;
element . style . top = top + 'px' ;
}
/ * *
* Helper : sets the element top / left coordinates within screen bounds
*
* @ param { Event } event DOM event object .
* @ param { Node } element The element being moved .
*
* @ return { undefined }
* /
function moveElementBounded ( event , element ) {
var left = ( event [ xProp ] - offsetX ) ,
top = ( event [ yProp ] - offsetY ) ;
if ( refreshTop ) {
top -= document . body . scrollTop ;
}
element . style . left = Math . min ( bounds . maxLeft , Math . max ( bounds . minLeft , left ) ) + 'px' ;
if ( refreshTop ) {
element . style . top = Math . min ( bounds . maxTop , Math . max ( bounds . minTop , top ) ) + 'px' ;
} else {
element . style . top = Math . max ( bounds . minTop , top ) + 'px' ;
}
}
/ * *
* Triggers the start of a move event , attached to the header element mouse down event .
* Adds no - selection class to the body , disabling selection while moving .
*
* @ param { Event } event DOM event object .
* @ param { Object } instance The dilog instance .
*
* @ return { Boolean } false
* /
function beginMove ( event , instance ) {
if ( resizable === null && ! instance . isMaximized ( ) && instance . get ( 'movable' ) ) {
var eventSrc , left = 0 , top = 0 ;
if ( event . type === 'touchstart' ) {
event . preventDefault ( ) ;
eventSrc = event . targetTouches [ 0 ] ;
xProp = 'clientX' ;
yProp = 'clientY' ;
} else if ( event . button === 0 ) {
eventSrc = event ;
}
if ( eventSrc ) {
var element = instance . elements . dialog ;
addClass ( element , classes . capture ) ;
if ( element . style . left ) {
left = parseInt ( element . style . left , 10 ) ;
}
if ( element . style . top ) {
top = parseInt ( element . style . top , 10 ) ;
}
offsetX = eventSrc [ xProp ] - left ;
offsetY = eventSrc [ yProp ] - top ;
if ( instance . isModal ( ) ) {
offsetY += instance . elements . modal . scrollTop ;
} else if ( instance . isPinned ( ) ) {
offsetY -= document . body . scrollTop ;
}
if ( instance . get ( 'moveBounded' ) ) {
var current = element ,
offsetLeft = - left ,
offsetTop = - top ;
//calc offset
do {
offsetLeft += current . offsetLeft ;
offsetTop += current . offsetTop ;
} while ( current = current . offsetParent ) ;
bounds = {
maxLeft : offsetLeft ,
minLeft : - offsetLeft ,
maxTop : document . documentElement . clientHeight - element . clientHeight - offsetTop ,
minTop : - offsetTop
} ;
moveDelegate = moveElementBounded ;
} else {
bounds = null ;
moveDelegate = moveElement ;
}
// allow custom `onmove` method
dispatchEvent ( 'onmove' , instance ) ;
refreshTop = ! instance . isModal ( ) && instance . isPinned ( ) ;
movable = instance ;
moveDelegate ( eventSrc , element ) ;
addClass ( document . body , classes . noSelection ) ;
return false ;
}
}
}
/ * *
* The actual move handler , attached to document . body mousemove event .
*
* @ param { Event } event DOM event object .
*
* @ return { undefined }
* /
function move ( event ) {
if ( movable ) {
var eventSrc ;
if ( event . type === 'touchmove' ) {
event . preventDefault ( ) ;
eventSrc = event . targetTouches [ 0 ] ;
} else if ( event . button === 0 ) {
eventSrc = event ;
}
if ( eventSrc ) {
moveDelegate ( eventSrc , movable . elements . dialog ) ;
}
}
}
/ * *
* Triggers the end of a move event , attached to document . body mouseup event .
* Removes no - selection class from document . body , allowing selection .
*
* @ return { undefined }
* /
function endMove ( ) {
if ( movable ) {
var instance = movable ;
movable = bounds = null ;
removeClass ( document . body , classes . noSelection ) ;
removeClass ( instance . elements . dialog , classes . capture ) ;
// allow custom `onmoved` method
dispatchEvent ( 'onmoved' , instance ) ;
}
}
/ * *
* Resets any changes made by moving the element to its original state ,
*
* @ param { Object } instance The dilog instance .
*
* @ return { undefined }
* /
function resetMove ( instance ) {
movable = null ;
var element = instance . elements . dialog ;
element . style . left = element . style . top = '' ;
}
/ * *
* Updates the dialog move behavior .
*
* @ param { Object } instance The dilog instance .
* @ param { Boolean } on True to add the behavior , removes it otherwise .
*
* @ return { undefined }
* /
function updateMovable ( instance ) {
if ( instance . get ( 'movable' ) ) {
// add class
addClass ( instance . elements . root , classes . movable ) ;
if ( instance . isOpen ( ) ) {
bindMovableEvents ( instance ) ;
}
} else {
//reset
resetMove ( instance ) ;
// remove class
removeClass ( instance . elements . root , classes . movable ) ;
if ( instance . isOpen ( ) ) {
unbindMovableEvents ( instance ) ;
}
}
}
/* Controls moving a dialog around */
//holde the current instance being resized
var resizable = null ,
//holds the staring left offset when resize starts.
startingLeft = Number . Nan ,
//holds the staring width when resize starts.
startingWidth = 0 ,
//holds the initial width when resized for the first time.
minWidth = 0 ,
//holds the offset of the resize handle.
handleOffset = 0
;
/ * *
* Helper : sets the element width / height and updates left coordinate if neccessary .
*
* @ param { Event } event DOM mousemove event object .
* @ param { Node } element The element being moved .
* @ param { Boolean } pinned A flag indicating if the element being resized is pinned to the screen .
*
* @ return { undefined }
* /
function resizeElement ( event , element , pageRelative ) {
//calculate offsets from 0,0
var current = element ;
var offsetLeft = 0 ;
var offsetTop = 0 ;
do {
offsetLeft += current . offsetLeft ;
offsetTop += current . offsetTop ;
} while ( current = current . offsetParent ) ;
// determine X,Y coordinates.
var X , Y ;
if ( pageRelative === true ) {
X = event . pageX ;
Y = event . pageY ;
} else {
X = event . clientX ;
Y = event . clientY ;
}
// rtl handling
var isRTL = isRightToLeft ( ) ;
if ( isRTL ) {
// reverse X
X = document . body . offsetWidth - X ;
// if has a starting left, calculate offsetRight
if ( ! isNaN ( startingLeft ) ) {
offsetLeft = document . body . offsetWidth - offsetLeft - element . offsetWidth ;
}
}
// set width/height
element . style . height = ( Y - offsetTop + handleOffset ) + 'px' ;
element . style . width = ( X - offsetLeft + handleOffset ) + 'px' ;
// if the element being resized has a starting left, maintain it.
// the dialog is centered, divide by half the offset to maintain the margins.
if ( ! isNaN ( startingLeft ) ) {
var diff = Math . abs ( element . offsetWidth - startingWidth ) * 0.5 ;
if ( isRTL ) {
//negate the diff, why?
//when growing it should decrease left
//when shrinking it should increase left
diff *= - 1 ;
}
if ( element . offsetWidth > startingWidth ) {
//growing
element . style . left = ( startingLeft + diff ) + 'px' ;
} else if ( element . offsetWidth >= minWidth ) {
//shrinking
element . style . left = ( startingLeft - diff ) + 'px' ;
}
}
}
/ * *
* Triggers the start of a resize event , attached to the resize handle element mouse down event .
* Adds no - selection class to the body , disabling selection while moving .
*
* @ param { Event } event DOM event object .
* @ param { Object } instance The dilog instance .
*
* @ return { Boolean } false
* /
function beginResize ( event , instance ) {
if ( ! instance . isMaximized ( ) ) {
var eventSrc ;
if ( event . type === 'touchstart' ) {
event . preventDefault ( ) ;
eventSrc = event . targetTouches [ 0 ] ;
} else if ( event . button === 0 ) {
eventSrc = event ;
}
if ( eventSrc ) {
// allow custom `onresize` method
dispatchEvent ( 'onresize' , instance ) ;
resizable = instance ;
handleOffset = instance . elements . resizeHandle . offsetHeight / 2 ;
var element = instance . elements . dialog ;
addClass ( element , classes . capture ) ;
startingLeft = parseInt ( element . style . left , 10 ) ;
element . style . height = element . offsetHeight + 'px' ;
element . style . minHeight = instance . elements . header . offsetHeight + instance . elements . footer . offsetHeight + 'px' ;
element . style . width = ( startingWidth = element . offsetWidth ) + 'px' ;
if ( element . style . maxWidth !== 'none' ) {
element . style . minWidth = ( minWidth = element . offsetWidth ) + 'px' ;
}
element . style . maxWidth = 'none' ;
addClass ( document . body , classes . noSelection ) ;
return false ;
}
}
}
/ * *
* The actual resize handler , attached to document . body mousemove event .
*
* @ param { Event } event DOM event object .
*
* @ return { undefined }
* /
function resize ( event ) {
if ( resizable ) {
var eventSrc ;
if ( event . type === 'touchmove' ) {
event . preventDefault ( ) ;
eventSrc = event . targetTouches [ 0 ] ;
} else if ( event . button === 0 ) {
eventSrc = event ;
}
if ( eventSrc ) {
resizeElement ( eventSrc , resizable . elements . dialog , ! resizable . get ( 'modal' ) && ! resizable . get ( 'pinned' ) ) ;
}
}
}
/ * *
* Triggers the end of a resize event , attached to document . body mouseup event .
* Removes no - selection class from document . body , allowing selection .
*
* @ return { undefined }
* /
function endResize ( ) {
if ( resizable ) {
var instance = resizable ;
resizable = null ;
removeClass ( document . body , classes . noSelection ) ;
removeClass ( instance . elements . dialog , classes . capture ) ;
cancelClick = true ;
// allow custom `onresized` method
dispatchEvent ( 'onresized' , instance ) ;
}
}
/ * *
* Resets any changes made by resizing the element to its original state .
*
* @ param { Object } instance The dilog instance .
*
* @ return { undefined }
* /
function resetResize ( instance ) {
resizable = null ;
var element = instance . elements . dialog ;
if ( element . style . maxWidth === 'none' ) {
//clear inline styles.
element . style . maxWidth = element . style . minWidth = element . style . width = element . style . height = element . style . minHeight = element . style . left = '' ;
//reset variables.
startingLeft = Number . Nan ;
startingWidth = minWidth = handleOffset = 0 ;
}
}
/ * *
* Updates the dialog move behavior .
*
* @ param { Object } instance The dilog instance .
* @ param { Boolean } on True to add the behavior , removes it otherwise .
*
* @ return { undefined }
* /
function updateResizable ( instance ) {
if ( instance . get ( 'resizable' ) ) {
// add class
addClass ( instance . elements . root , classes . resizable ) ;
if ( instance . isOpen ( ) ) {
bindResizableEvents ( instance ) ;
}
} else {
//reset
resetResize ( instance ) ;
// remove class
removeClass ( instance . elements . root , classes . resizable ) ;
if ( instance . isOpen ( ) ) {
unbindResizableEvents ( instance ) ;
}
}
}
/ * *
* Reset move / resize on window resize .
*
* @ param { Event } event window resize event object .
*
* @ return { undefined }
* /
function windowResize ( /*event*/ ) {
for ( var x = 0 ; x < openDialogs . length ; x += 1 ) {
var instance = openDialogs [ x ] ;
if ( instance . get ( 'autoReset' ) ) {
resetMove ( instance ) ;
resetResize ( instance ) ;
}
}
}
/ * *
* Bind dialogs events
*
* @ param { Object } instance The dilog instance .
*
* @ return { undefined }
* /
function bindEvents ( instance ) {
// if first dialog, hook global handlers
if ( openDialogs . length === 1 ) {
//global
on ( window , 'resize' , windowResize ) ;
on ( document . body , 'keyup' , keyupHandler ) ;
on ( document . body , 'keydown' , keydownHandler ) ;
on ( document . body , 'focus' , onReset ) ;
//move
on ( document . documentElement , 'mousemove' , move ) ;
on ( document . documentElement , 'touchmove' , move , false , false ) ;
on ( document . documentElement , 'mouseup' , endMove ) ;
on ( document . documentElement , 'touchend' , endMove ) ;
//resize
on ( document . documentElement , 'mousemove' , resize ) ;
on ( document . documentElement , 'touchmove' , resize , false , false ) ;
on ( document . documentElement , 'mouseup' , endResize ) ;
on ( document . documentElement , 'touchend' , endResize ) ;
}
// common events
on ( instance . elements . commands . container , 'click' , instance . _ _internal . commandsClickHandler ) ;
on ( instance . elements . footer , 'click' , instance . _ _internal . buttonsClickHandler ) ;
on ( instance . elements . reset [ 0 ] , 'focusin' , instance . _ _internal . resetHandler ) ;
on ( instance . elements . reset [ 0 ] , 'keydown' , recycleTab ) ;
on ( instance . elements . reset [ 1 ] , 'focusin' , instance . _ _internal . resetHandler ) ;
//prevent handling key up when dialog is being opened by a key stroke.
cancelKeyup = true ;
// hook in transition handler
on ( instance . elements . dialog , transition . type , instance . _ _internal . transitionInHandler ) ;
// modelss only events
if ( ! instance . get ( 'modal' ) ) {
bindModelessEvents ( instance ) ;
}
// resizable
if ( instance . get ( 'resizable' ) ) {
bindResizableEvents ( instance ) ;
}
// movable
if ( instance . get ( 'movable' ) ) {
bindMovableEvents ( instance ) ;
}
}
/ * *
* Unbind dialogs events
*
* @ param { Object } instance The dilog instance .
*
* @ return { undefined }
* /
function unbindEvents ( instance ) {
// if last dialog, remove global handlers
if ( openDialogs . length === 1 ) {
//global
off ( window , 'resize' , windowResize ) ;
off ( document . body , 'keyup' , keyupHandler ) ;
off ( document . body , 'keydown' , keydownHandler ) ;
off ( document . body , 'focus' , onReset ) ;
//move
off ( document . documentElement , 'mousemove' , move ) ;
off ( document . documentElement , 'mouseup' , endMove ) ;
//resize
off ( document . documentElement , 'mousemove' , resize ) ;
off ( document . documentElement , 'mouseup' , endResize ) ;
}
// common events
off ( instance . elements . commands . container , 'click' , instance . _ _internal . commandsClickHandler ) ;
off ( instance . elements . footer , 'click' , instance . _ _internal . buttonsClickHandler ) ;
off ( instance . elements . reset [ 0 ] , 'focusin' , instance . _ _internal . resetHandler ) ;
off ( instance . elements . reset [ 0 ] , 'keydown' , recycleTab ) ;
off ( instance . elements . reset [ 1 ] , 'focusin' , instance . _ _internal . resetHandler ) ;
// hook out transition handler
on ( instance . elements . dialog , transition . type , instance . _ _internal . transitionOutHandler ) ;
// modelss only events
if ( ! instance . get ( 'modal' ) ) {
unbindModelessEvents ( instance ) ;
}
// movable
if ( instance . get ( 'movable' ) ) {
unbindMovableEvents ( instance ) ;
}
// resizable
if ( instance . get ( 'resizable' ) ) {
unbindResizableEvents ( instance ) ;
}
}
/ * *
* Bind modeless specific events
*
* @ param { Object } instance The dilog instance .
*
* @ return { undefined }
* /
function bindModelessEvents ( instance ) {
on ( instance . elements . dialog , 'focus' , instance . _ _internal . bringToFrontHandler , true ) ;
}
/ * *
* Unbind modeless specific events
*
* @ param { Object } instance The dilog instance .
*
* @ return { undefined }
* /
function unbindModelessEvents ( instance ) {
off ( instance . elements . dialog , 'focus' , instance . _ _internal . bringToFrontHandler , true ) ;
}
/ * *
* Bind movable specific events
*
* @ param { Object } instance The dilog instance .
*
* @ return { undefined }
* /
function bindMovableEvents ( instance ) {
on ( instance . elements . header , 'mousedown' , instance . _ _internal . beginMoveHandler ) ;
on ( instance . elements . header , 'touchstart' , instance . _ _internal . beginMoveHandler , false , false ) ;
}
/ * *
* Unbind movable specific events
*
* @ param { Object } instance The dilog instance .
*
* @ return { undefined }
* /
function unbindMovableEvents ( instance ) {
off ( instance . elements . header , 'mousedown' , instance . _ _internal . beginMoveHandler ) ;
off ( instance . elements . header , 'touchstart' , instance . _ _internal . beginMoveHandler , false , false ) ;
}
/ * *
* Bind resizable specific events
*
* @ param { Object } instance The dilog instance .
*
* @ return { undefined }
* /
function bindResizableEvents ( instance ) {
on ( instance . elements . resizeHandle , 'mousedown' , instance . _ _internal . beginResizeHandler ) ;
on ( instance . elements . resizeHandle , 'touchstart' , instance . _ _internal . beginResizeHandler , false , false ) ;
}
/ * *
* Unbind resizable specific events
*
* @ param { Object } instance The dilog instance .
*
* @ return { undefined }
* /
function unbindResizableEvents ( instance ) {
off ( instance . elements . resizeHandle , 'mousedown' , instance . _ _internal . beginResizeHandler ) ;
off ( instance . elements . resizeHandle , 'touchstart' , instance . _ _internal . beginResizeHandler , false , false ) ;
}
/ * *
* Bind closable events
*
* @ param { Object } instance The dilog instance .
*
* @ return { undefined }
* /
function bindClosableEvents ( instance ) {
on ( instance . elements . modal , 'click' , instance . _ _internal . modalClickHandler ) ;
}
/ * *
* Unbind closable specific events
*
* @ param { Object } instance The dilog instance .
*
* @ return { undefined }
* /
function unbindClosableEvents ( instance ) {
off ( instance . elements . modal , 'click' , instance . _ _internal . modalClickHandler ) ;
}
// 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 ;
} ,
} ;
} ( ) ) ;
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 ( ) ;
}
}
}
} ;
} ) ( ) ;
/ * *
* Alertify public API
* This contains everything that is exposed through the alertify object .
*
* @ return { Object }
* /
function Alertify ( ) {
// holds a references of created dialogs
var dialogs = { } ;
/ * *
* Extends a given prototype by merging properties from base into sub .
*
* @ sub { Object } sub The prototype being overwritten .
* @ base { Object } base The prototype being written .
*
* @ return { Object } The extended prototype .
* /
function extend ( sub , base ) {
// copy dialog pototype over definition.
for ( var prop in base ) {
if ( base . hasOwnProperty ( prop ) ) {
sub [ prop ] = base [ prop ] ;
}
}
return sub ;
}
/ * *
* Helper : returns a dialog instance from saved dialogs .
* and initializes the dialog if its not already initialized .
*
* @ name { String } name The dialog name .
*
* @ return { Object } The dialog instance .
* /
function get _dialog ( name ) {
var dialog = dialogs [ name ] . dialog ;
//initialize the dialog if its not already initialized.
if ( dialog && typeof dialog . _ _init === 'function' ) {
dialog . _ _init ( dialog ) ;
}
return dialog ;
}
/ * *
* Helper : registers a new dialog definition .
*
* @ name { String } name The dialog name .
* @ Factory { Function } Factory a function resposible for creating dialog prototype .
* @ transient { Boolean } transient True to create a new dialog instance each time the dialog is invoked , false otherwise .
* @ base { String } base the name of another dialog to inherit from .
*
* @ return { Object } The dialog definition .
* /
function register ( name , Factory , transient , base ) {
var definition = {
dialog : null ,
factory : Factory
} ;
//if this is based on an existing dialog, create a new definition
//by applying the new protoype over the existing one.
if ( base !== undefined ) {
definition . factory = function ( ) {
return extend ( new dialogs [ base ] . factory ( ) , new Factory ( ) ) ;
} ;
}
if ( ! transient ) {
//create a new definition based on dialog
definition . dialog = extend ( new definition . factory ( ) , dialog ) ;
}
return dialogs [ name ] = definition ;
}
return {
/ * *
* Alertify defaults
*
* @ type { Object }
* /
defaults : defaults ,
/ * *
* Dialogs factory
*
* @ param { string } Dialog name .
* @ param { Function } A Dialog factory function .
* @ param { Boolean } Indicates whether to create a singleton or transient dialog .
* @ param { String } The name of the base type to inherit from .
* /
dialog : function ( name , Factory , transient , base ) {
// get request, create a new instance and return it.
if ( typeof Factory !== 'function' ) {
return get _dialog ( name ) ;
}
if ( this . hasOwnProperty ( name ) ) {
throw new Error ( 'alertify.dialog: name already exists' ) ;
}
// register the dialog
var definition = register ( name , Factory , transient , base ) ;
if ( transient ) {
// make it public
this [ name ] = function ( ) {
//if passed with no params, consider it a get request
if ( arguments . length === 0 ) {
return definition . dialog ;
} else {
var instance = extend ( new definition . factory ( ) , dialog ) ;
//ensure init
if ( instance && typeof instance . _ _init === 'function' ) {
instance . _ _init ( instance ) ;
}
instance [ 'main' ] . apply ( instance , arguments ) ;
return instance [ 'show' ] . apply ( instance ) ;
}
} ;
} else {
// make it public
this [ name ] = function ( ) {
//ensure init
if ( definition . dialog && typeof definition . dialog . _ _init === 'function' ) {
definition . dialog . _ _init ( definition . dialog ) ;
}
//if passed with no params, consider it a get request
if ( arguments . length === 0 ) {
return definition . dialog ;
} else {
var dialog = definition . dialog ;
dialog [ 'main' ] . apply ( definition . dialog , arguments ) ;
return dialog [ 'show' ] . apply ( definition . dialog ) ;
}
} ;
}
} ,
/ * *
* Close all open dialogs .
*
* @ param { Object } excpet [ optional ] The dialog object to exclude from closing .
*
* @ return { undefined }
* /
closeAll : function ( except ) {
var clone = openDialogs . slice ( 0 ) ;
for ( var x = 0 ; x < clone . length ; x += 1 ) {
var instance = clone [ x ] ;
if ( except === undefined || except !== instance ) {
instance . close ( ) ;
}
}
} ,
/ * *
* Gets or Sets dialog settings / options . if the dialog is transient , this call does nothing .
*
* @ param { string } name The dialog name .
* @ param { String | Object } key A string specifying a propery name or a collection of key / value pairs .
* @ param { Variant } value Optional , the value associated with the key ( in case it was a string ) .
*
* @ return { undefined }
* /
setting : function ( name , key , value ) {
if ( name === 'notifier' ) {
return notifier . setting ( key , value ) ;
}
var dialog = get _dialog ( name ) ;
if ( dialog ) {
return dialog . setting ( key , value ) ;
}
} ,
/ * *
* [ Alias ] Sets dialog settings / options
* /
set : function ( name , key , value ) {
return this . setting ( name , key , value ) ;
} ,
/ * *
* [ Alias ] Gets dialog settings / options
* /
get : function ( name , key ) {
return this . setting ( name , key ) ;
} ,
/ * *
* Creates a new notification message .
* If a type is passed , a class name "ajs-{type}" will be added .
* This allows for custom look and feel for various types of notifications .
*
* @ param { String | DOMElement } [ message = undefined ] Message text
* @ param { String } [ type = '' ] Type of log message
* @ param { String } [ wait = '' ] Time ( in seconds ) to wait before auto - close
* @ param { Function } [ callback = undefined ] A callback function to be invoked when the log is closed .
*
* @ return { Object } Notification object .
* /
notify : function ( message , type , wait , callback ) {
return notifier . create ( type , callback ) . push ( message , wait ) ;
} ,
/ * *
* Creates a new notification message .
*
* @ param { String } [ message = undefined ] Message text
* @ param { String } [ wait = '' ] Time ( in seconds ) to wait before auto - close
* @ param { Function } [ callback = undefined ] A callback function to be invoked when the log is closed .
*
* @ return { Object } Notification object .
* /
message : function ( message , wait , callback ) {
return notifier . create ( null , callback ) . push ( message , wait ) ;
} ,
/ * *
* Creates a new notification message of type 'success' .
*
* @ param { String } [ message = undefined ] Message text
* @ param { String } [ wait = '' ] Time ( in seconds ) to wait before auto - close
* @ param { Function } [ callback = undefined ] A callback function to be invoked when the log is closed .
*
* @ return { Object } Notification object .
* /
success : function ( message , wait , callback ) {
return notifier . create ( 'success' , callback ) . push ( message , wait ) ;
} ,
/ * *
* Creates a new notification message of type 'error' .
*
* @ param { String } [ message = undefined ] Message text
* @ param { String } [ wait = '' ] Time ( in seconds ) to wait before auto - close
* @ param { Function } [ callback = undefined ] A callback function to be invoked when the log is closed .
*
* @ return { Object } Notification object .
* /
error : function ( message , wait , callback ) {
return notifier . create ( 'error' , callback ) . push ( message , wait ) ;
} ,
/ * *
* Creates a new notification message of type 'warning' .
*
* @ param { String } [ message = undefined ] Message text
* @ param { String } [ wait = '' ] Time ( in seconds ) to wait before auto - close
* @ param { Function } [ callback = undefined ] A callback function to be invoked when the log is closed .
*
* @ return { Object } Notification object .
* /
warning : function ( message , wait , callback ) {
return notifier . create ( 'warning' , callback ) . push ( message , wait ) ;
} ,
/ * *
* Dismisses all open notifications
*
* @ return { undefined }
* /
dismissAll : function ( ) {
notifier . dismissAll ( ) ;
}
} ;
}
var alertify = new Alertify ( ) ;
/ * *
* Alert dialog definition
*
* invoked by :
* alertify . alert ( message ) ;
* alertify . alert ( title , message ) ;
* alertify . alert ( message , onok ) ;
* alertify . alert ( title , message , onok ) ;
* /
alertify . dialog ( 'alert' , function ( ) {
return {
main : function ( _title , _message , _onok ) {
var title , message , onok ;
switch ( arguments . length ) {
case 1 :
message = _title ;
break ;
case 2 :
if ( typeof _message === 'function' ) {
message = _title ;
onok = _message ;
} else {
title = _title ;
message = _message ;
}
break ;
case 3 :
title = _title ;
message = _message ;
onok = _onok ;
break ;
}
this . set ( 'title' , title ) ;
this . set ( 'message' , message ) ;
this . set ( 'onok' , onok ) ;
return this ;
} ,
setup : function ( ) {
return {
buttons : [
{
text : alertify . defaults . glossary . ok ,
key : keys . ESC ,
invokeOnClose : true ,
className : alertify . defaults . theme . ok ,
}
] ,
focus : {
element : 0 ,
select : false
} ,
options : {
maximizable : false ,
resizable : false
}
} ;
} ,
build : function ( ) {
// nothing
} ,
prepare : function ( ) {
//nothing
} ,
setMessage : function ( message ) {
this . setContent ( message ) ;
} ,
settings : {
message : undefined ,
onok : undefined ,
label : undefined ,
} ,
settingUpdated : function ( key , oldValue , newValue ) {
switch ( key ) {
case 'message' :
this . setMessage ( newValue ) ;
break ;
case 'label' :
if ( this . _ _internal . buttons [ 0 ] . element ) {
this . _ _internal . buttons [ 0 ] . element . innerHTML = newValue ;
}
break ;
}
} ,
callback : function ( closeEvent ) {
if ( typeof this . get ( 'onok' ) === 'function' ) {
var returnValue = this . get ( 'onok' ) . call ( this , closeEvent ) ;
if ( typeof returnValue !== 'undefined' ) {
closeEvent . cancel = ! returnValue ;
}
}
}
} ;
} ) ;
/ * *
* Confirm dialog object
*
* alertify . confirm ( message ) ;
* alertify . confirm ( message , onok ) ;
* alertify . confirm ( message , onok , oncancel ) ;
* alertify . confirm ( title , message , onok , oncancel ) ;
* /
alertify . dialog ( 'confirm' , function ( ) {
var autoConfirm = {
timer : null ,
index : null ,
text : null ,
duration : null ,
task : function ( event , self ) {
if ( self . isOpen ( ) ) {
self . _ _internal . buttons [ autoConfirm . index ] . element . innerHTML = autoConfirm . text + ' (‏' + autoConfirm . duration + '‏) ' ;
autoConfirm . duration -= 1 ;
if ( autoConfirm . duration === - 1 ) {
clearAutoConfirm ( self ) ;
var button = self . _ _internal . buttons [ autoConfirm . index ] ;
var closeEvent = createCloseEvent ( autoConfirm . index , button ) ;
if ( typeof self . callback === 'function' ) {
self . callback . apply ( self , [ closeEvent ] ) ;
}
//close the dialog.
if ( closeEvent . close !== false ) {
self . close ( ) ;
}
}
} else {
clearAutoConfirm ( self ) ;
}
}
} ;
function clearAutoConfirm ( self ) {
if ( autoConfirm . timer !== null ) {
clearInterval ( autoConfirm . timer ) ;
autoConfirm . timer = null ;
self . _ _internal . buttons [ autoConfirm . index ] . element . innerHTML = autoConfirm . text ;
}
}
function startAutoConfirm ( self , index , duration ) {
clearAutoConfirm ( self ) ;
autoConfirm . duration = duration ;
autoConfirm . index = index ;
autoConfirm . text = self . _ _internal . buttons [ index ] . element . innerHTML ;
autoConfirm . timer = setInterval ( delegate ( self , autoConfirm . task ) , 1000 ) ;
autoConfirm . task ( null , self ) ;
}
return {
main : function ( _title , _message , _onok , _oncancel ) {
var title , message , onok , oncancel ;
switch ( arguments . length ) {
case 1 :
message = _title ;
break ;
case 2 :
message = _title ;
onok = _message ;
break ;
case 3 :
message = _title ;
onok = _message ;
oncancel = _onok ;
break ;
case 4 :
title = _title ;
message = _message ;
onok = _onok ;
oncancel = _oncancel ;
break ;
}
this . set ( 'title' , title ) ;
this . set ( 'message' , message ) ;
this . set ( 'onok' , onok ) ;
this . set ( 'oncancel' , oncancel ) ;
return this ;
} ,
setup : function ( ) {
return {
buttons : [
{
text : alertify . defaults . glossary . ok ,
key : keys . ENTER ,
className : alertify . defaults . theme . ok ,
} ,
{
text : alertify . defaults . glossary . cancel ,
key : keys . ESC ,
invokeOnClose : true ,
className : alertify . defaults . theme . cancel ,
}
] ,
focus : {
element : 0 ,
select : false
} ,
options : {
maximizable : false ,
resizable : false
}
} ;
} ,
build : function ( ) {
//nothing
} ,
prepare : function ( ) {
//nothing
} ,
setMessage : function ( message ) {
this . setContent ( message ) ;
} ,
settings : {
message : null ,
labels : null ,
onok : null ,
oncancel : null ,
defaultFocus : null ,
reverseButtons : null ,
} ,
settingUpdated : function ( key , oldValue , newValue ) {
switch ( key ) {
case 'message' :
this . setMessage ( newValue ) ;
break ;
case 'labels' :
if ( 'ok' in newValue && this . _ _internal . buttons [ 0 ] . element ) {
this . _ _internal . buttons [ 0 ] . text = newValue . ok ;
this . _ _internal . buttons [ 0 ] . element . innerHTML = newValue . ok ;
}
if ( 'cancel' in newValue && this . _ _internal . buttons [ 1 ] . element ) {
this . _ _internal . buttons [ 1 ] . text = newValue . cancel ;
this . _ _internal . buttons [ 1 ] . element . innerHTML = newValue . cancel ;
}
break ;
case 'reverseButtons' :
if ( newValue === true ) {
this . elements . buttons . primary . appendChild ( this . _ _internal . buttons [ 0 ] . element ) ;
} else {
this . elements . buttons . primary . appendChild ( this . _ _internal . buttons [ 1 ] . element ) ;
}
break ;
case 'defaultFocus' :
this . _ _internal . focus . element = newValue === 'ok' ? 0 : 1 ;
break ;
}
} ,
callback : function ( closeEvent ) {
clearAutoConfirm ( this ) ;
var returnValue ;
switch ( closeEvent . index ) {
case 0 :
if ( typeof this . get ( 'onok' ) === 'function' ) {
returnValue = this . get ( 'onok' ) . call ( this , closeEvent ) ;
if ( typeof returnValue !== 'undefined' ) {
closeEvent . cancel = ! returnValue ;
}
}
break ;
case 1 :
if ( typeof this . get ( 'oncancel' ) === 'function' ) {
returnValue = this . get ( 'oncancel' ) . call ( this , closeEvent ) ;
if ( typeof returnValue !== 'undefined' ) {
closeEvent . cancel = ! returnValue ;
}
}
break ;
}
} ,
autoOk : function ( duration ) {
startAutoConfirm ( this , 0 , duration ) ;
return this ;
} ,
autoCancel : function ( duration ) {
startAutoConfirm ( this , 1 , duration ) ;
return this ;
}
} ;
} ) ;
/ * *
* Prompt dialog object
*
* invoked by :
* alertify . prompt ( message ) ;
* alertify . prompt ( message , value ) ;
* alertify . prompt ( message , value , onok ) ;
* alertify . prompt ( message , value , onok , oncancel ) ;
* alertify . prompt ( title , message , value , onok , oncancel ) ;
* /
alertify . dialog ( 'prompt' , function ( ) {
var input = document . createElement ( 'INPUT' ) ;
var p = document . createElement ( 'P' ) ;
return {
main : function ( _title , _message , _value , _onok , _oncancel ) {
var title , message , value , onok , oncancel ;
switch ( arguments . length ) {
case 1 :
message = _title ;
break ;
case 2 :
message = _title ;
value = _message ;
break ;
case 3 :
message = _title ;
value = _message ;
onok = _value ;
break ;
case 4 :
message = _title ;
value = _message ;
onok = _value ;
oncancel = _onok ;
break ;
case 5 :
title = _title ;
message = _message ;
value = _value ;
onok = _onok ;
oncancel = _oncancel ;
break ;
}
this . set ( 'title' , title ) ;
this . set ( 'message' , message ) ;
this . set ( 'value' , value ) ;
this . set ( 'onok' , onok ) ;
this . set ( 'oncancel' , oncancel ) ;
return this ;
} ,
setup : function ( ) {
return {
buttons : [
{
text : alertify . defaults . glossary . ok ,
key : keys . ENTER ,
className : alertify . defaults . theme . ok ,
} ,
{
text : alertify . defaults . glossary . cancel ,
key : keys . ESC ,
invokeOnClose : true ,
className : alertify . defaults . theme . cancel ,
}
] ,
focus : {
element : input ,
select : true
} ,
options : {
maximizable : false ,
resizable : false
}
} ;
} ,
build : function ( ) {
input . className = alertify . defaults . theme . input ;
input . setAttribute ( 'type' , 'text' ) ;
input . value = this . get ( 'value' ) ;
this . elements . content . appendChild ( p ) ;
this . elements . content . appendChild ( input ) ;
} ,
prepare : function ( ) {
//nothing
} ,
setMessage : function ( message ) {
if ( isString ( message ) ) {
clearContents ( p ) ;
p . innerHTML = message ;
} else if ( message instanceof window . HTMLElement && p . firstChild !== message ) {
clearContents ( p ) ;
p . appendChild ( message ) ;
}
} ,
settings : {
message : undefined ,
labels : undefined ,
onok : undefined ,
oncancel : undefined ,
value : '' ,
type : 'text' ,
reverseButtons : undefined ,
} ,
settingUpdated : function ( key , oldValue , newValue ) {
switch ( key ) {
case 'message' :
this . setMessage ( newValue ) ;
break ;
case 'value' :
input . value = newValue ;
break ;
case 'type' :
switch ( newValue ) {
case 'text' :
case 'color' :
case 'date' :
case 'datetime-local' :
case 'email' :
case 'month' :
case 'number' :
case 'password' :
case 'search' :
case 'tel' :
case 'time' :
case 'week' :
input . type = newValue ;
break ;
default :
input . type = 'text' ;
break ;
}
break ;
case 'labels' :
if ( newValue . ok && this . _ _internal . buttons [ 0 ] . element ) {
this . _ _internal . buttons [ 0 ] . element . innerHTML = newValue . ok ;
}
if ( newValue . cancel && this . _ _internal . buttons [ 1 ] . element ) {
this . _ _internal . buttons [ 1 ] . element . innerHTML = newValue . cancel ;
}
break ;
case 'reverseButtons' :
if ( newValue === true ) {
this . elements . buttons . primary . appendChild ( this . _ _internal . buttons [ 0 ] . element ) ;
} else {
this . elements . buttons . primary . appendChild ( this . _ _internal . buttons [ 1 ] . element ) ;
}
break ;
}
} ,
callback : function ( closeEvent ) {
var returnValue ;
switch ( closeEvent . index ) {
case 0 :
this . settings . value = input . value ;
if ( typeof this . get ( 'onok' ) === 'function' ) {
returnValue = this . get ( 'onok' ) . call ( this , closeEvent , this . settings . value ) ;
if ( typeof returnValue !== 'undefined' ) {
closeEvent . cancel = ! returnValue ;
}
}
break ;
case 1 :
if ( typeof this . get ( 'oncancel' ) === 'function' ) {
returnValue = this . get ( 'oncancel' ) . call ( this , closeEvent ) ;
if ( typeof returnValue !== 'undefined' ) {
closeEvent . cancel = ! returnValue ;
}
}
if ( ! closeEvent . cancel ) {
input . value = this . settings . value ;
}
break ;
}
}
} ;
} ) ;
// CommonJS
if ( typeof module === 'object' && typeof module . exports === 'object' ) {
module . exports = alertify ;
// AMD
} else if ( typeof define === 'function' && define . amd ) {
define ( [ ] , function ( ) {
return alertify ;
} ) ;
// window
} else if ( ! window . alertify ) {
window . alertify = alertify ;
}
} ( typeof window !== 'undefined' ? window : this ) ) ;