Commit 0c24cb1d authored by bingchuan's avatar bingchuan

Update alertify.js

parent e89d8d43
/** /**
* alertifyjs 1.14.0 http://alertifyjs.com * alertifyjs 1.8.0 http://alertifyjs.com
* AlertifyJS is a javascript framework for developing pretty browser dialogs and notifications. * AlertifyJS is a javascript framework for developing pretty browser dialogs and notifications.
* Copyright 2024 Mohammad Younes <Mohammad@alertifyjs.com> (http://alertifyjs.com) * Copyright 2016 Mohammad Younes <Mohammad@alertifyjs.com> (http://alertifyjs.com)
* Licensed under GPL 3 <https://opensource.org/licenses/gpl-3.0>*/ * Licensed under GPL 3 <https://opensource.org/licenses/gpl-3.0>*/
( function ( window ) { ( function ( window ) {
'use strict'; 'use strict';
var NOT_DISABLED_NOT_RESET = ':not(:disabled):not(.ajs-reset)';
/** /**
* Keys enum * Keys enum
* @type {Object} * @type {Object}
...@@ -16,8 +16,7 @@ ...@@ -16,8 +16,7 @@
F1: 112, F1: 112,
F12: 123, F12: 123,
LEFT: 37, LEFT: 37,
RIGHT: 39, RIGHT: 39
TAB: 9
}; };
/** /**
* Default options * Default options
...@@ -28,9 +27,7 @@ ...@@ -28,9 +27,7 @@
basic:false, basic:false,
closable:true, closable:true,
closableByDimmer:true, closableByDimmer:true,
invokeOnCloseOff:false,
frameless:false, frameless:false,
defaultFocusOff:false,
maintainFocus:true, //global default not per instance, applies to all dialogs maintainFocus:true, //global default not per instance, applies to all dialogs
maximizable:true, maximizable:true,
modal:true, modal:true,
...@@ -44,25 +41,9 @@ ...@@ -44,25 +41,9 @@
resizable:true, resizable:true,
startMaximized:false, startMaximized:false,
transition:'pulse', transition:'pulse',
transitionOff:false,
tabbable:['button', '[href]', 'input', 'select', 'textarea', '[tabindex]:not([tabindex^="-"])'+NOT_DISABLED_NOT_RESET].join(NOT_DISABLED_NOT_RESET+','),//global
notifier:{ notifier:{
delay:5, delay:5,
position:'bottom-right', 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:{ glossary:{
title:'AlertifyJS', title:'AlertifyJS',
...@@ -80,10 +61,6 @@ ...@@ -80,10 +61,6 @@
input:'ajs-input', input:'ajs-input',
ok:'ajs-ok', ok:'ajs-ok',
cancel:'ajs-cancel', cancel:'ajs-cancel',
},
hooks:{
preinit:function(){},
postinit:function(){}
} }
}; };
...@@ -157,16 +134,6 @@ ...@@ -157,16 +134,6 @@
element.removeChild(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. * Extends a given prototype by merging properties from base into sub.
* *
...@@ -218,7 +185,6 @@ ...@@ -218,7 +185,6 @@
* *
*/ */
function destruct(instance, initialize){ function destruct(instance, initialize){
if(instance.elements){
//delete the dom and it's references. //delete the dom and it's references.
var root = instance.elements.root; var root = instance.elements.root;
root.parentNode.removeChild(root); root.parentNode.removeChild(root);
...@@ -230,47 +196,52 @@ ...@@ -230,47 +196,52 @@
//delete __internal variable to allow re-initialization. //delete __internal variable to allow re-initialization.
delete instance.__internal; 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 * Use a closure to return proper event listener method. Try to use
* `addEventListener` by default but fallback to `attachEvent` for
* unsupported browser. The closure simply ensures that the test doesn't
* happen every time the method is called.
* *
* @param {HTMLElement} el The EventTarget to register the listenr on. * @param {Node} el Node element
* @param {string} event The event type to listen for. * @param {String} event Event type
* @param {Function} handler The function to handle the event. * @param {Function} fn Callback of 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. * @return {Function}
* @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) { var on = (function () {
el.addEventListener(event, fn, IsPassiveSupported ? { capture: useCapture, passive: passive } : useCapture === true); if (document.addEventListener) {
return function (el, event, fn, useCapture) {
el.addEventListener(event, fn, useCapture === true);
};
} else if (document.attachEvent) {
return function (el, event, fn) {
el.attachEvent('on' + event, fn);
}; };
}
}());
/** /**
* Removes an event listener * Use a closure to return proper event listener method. Try to use
* `removeEventListener` by default but fallback to `detachEvent` for
* unsupported browser. The closure simply ensures that the test doesn't
* happen every time the method is called.
* *
* @param {HTMLElement} el The EventTarget to unregister the listenr from. * @param {Node} el Node element
* @param {string} event The event type to remove. * @param {String} event Event type
* @param {Function} fn The event handler to remove. * @param {Function} fn Callback of 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. * @return {Function}
* @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) { var off = (function () {
el.removeEventListener(event, fn, IsPassiveSupported ? { capture: useCapture, passive: passive } : useCapture === true); if (document.removeEventListener) {
return function (el, event, fn, useCapture) {
el.removeEventListener(event, fn, useCapture === true);
}; };
} else if (document.detachEvent) {
return function (el, event, fn) {
el.detachEvent('on' + event, fn);
};
}
}());
/** /**
* Prevent default event from firing * Prevent default event from firing
...@@ -349,11 +320,11 @@ ...@@ -349,11 +320,11 @@
* @param {string} evenType The type of the event to disptach. * @param {string} evenType The type of the event to disptach.
* @param {object} instance The dialog instance disptaching the event. * @param {object} instance The dialog instance disptaching the event.
* *
* @return {any} The result of the invoked function. * @return {object}
*/ */
function dispatchEvent(eventType, instance) { function dispatchEvent(eventType, instance) {
if ( typeof instance.get(eventType) === 'function' ) { if ( typeof instance.get(eventType) === 'function' ) {
return instance.get(eventType).call(instance); instance.get(eventType).call(instance);
} }
} }
...@@ -368,8 +339,6 @@ ...@@ -368,8 +339,6 @@
usedKeys = [], usedKeys = [],
//dummy variable, used to trigger dom reflow. //dummy variable, used to trigger dom reflow.
reflow = null, reflow = null,
//holds body tab index in case it has any.
tabindex = false,
//condition for detecting safari //condition for detecting safari
isSafari = window.navigator.userAgent.indexOf('Safari') > -1 && window.navigator.userAgent.indexOf('Chrome') < 0, isSafari = window.navigator.userAgent.indexOf('Safari') > -1 && window.navigator.userAgent.indexOf('Chrome') < 0,
//dialog building blocks //dialog building blocks
...@@ -414,7 +383,6 @@ ...@@ -414,7 +383,6 @@
restore: 'ajs-restore', restore: 'ajs-restore',
shake:'ajs-shake', shake:'ajs-shake',
unpinned:'ajs-unpinned', unpinned:'ajs-unpinned',
noTransition:'ajs-no-transition'
}; };
/** /**
...@@ -424,9 +392,8 @@ ...@@ -424,9 +392,8 @@
*/ */
function initialize(instance){ function initialize(instance){
if(!instance.__internal){ if(!instance.__internal||instance.settings.type=='text'){
//invoke preinit global hook
alertify.defaults.hooks.preinit(instance);
//no need to expose init after this. //no need to expose init after this.
delete instance.__init; delete instance.__init;
...@@ -434,6 +401,13 @@ ...@@ -434,6 +401,13 @@
if(!instance.__settings){ if(!instance.__settings){
instance.__settings = copy(instance.settings); instance.__settings = copy(instance.settings);
} }
//in case the script was included before body.
//after first dialog gets initialized, it won't be null anymore!
if(null === reflow){
// set tabindex attribute on body element this allows script to give it
// focus after the dialog is closed
document.body.setAttribute( 'tabindex', '0' );
}
//get dialog buttons/focus setup //get dialog buttons/focus setup
var setup; var setup;
...@@ -497,7 +471,6 @@ ...@@ -497,7 +471,6 @@
modal: undefined, modal: undefined,
basic:undefined, basic:undefined,
frameless:undefined, frameless:undefined,
defaultFocusOff:undefined,
pinned: undefined, pinned: undefined,
movable: undefined, movable: undefined,
moveBounded:undefined, moveBounded:undefined,
...@@ -505,16 +478,13 @@ ...@@ -505,16 +478,13 @@
autoReset: undefined, autoReset: undefined,
closable: undefined, closable: undefined,
closableByDimmer: undefined, closableByDimmer: undefined,
invokeOnCloseOff:undefined,
maximizable: undefined, maximizable: undefined,
startMaximized: undefined, startMaximized: undefined,
pinnable: undefined, pinnable: undefined,
transition: undefined, transition: undefined,
transitionOff: undefined,
padding:undefined, padding:undefined,
overflow:undefined, overflow:undefined,
onshow:undefined, onshow:undefined,
onclosing:undefined,
onclose:undefined, onclose:undefined,
onfocus:undefined, onfocus:undefined,
onmove:undefined, onmove:undefined,
...@@ -541,8 +511,7 @@ ...@@ -541,8 +511,7 @@
var elements = {}; var elements = {};
//root node //root node
elements.root = document.createElement('div'); 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.className = classes.base + ' ' + classes.hidden + ' ';
elements.root.innerHTML = templates.dimmer + templates.modal; elements.root.innerHTML = templates.dimmer + templates.modal;
...@@ -602,7 +571,14 @@ ...@@ -602,7 +571,14 @@
} }
button.element = elements.buttonTemplate.cloneNode(); button.element = elements.buttonTemplate.cloneNode();
button.element.innerHTML = button.text; // Apply instance labels if they exist, otherwise use default button text
var buttonText = button.text;
if(instance.settings.labels) {
if(x === 0 && instance.settings.labels.ok) buttonText = instance.settings.labels.ok;
if(x === 1 && instance.settings.labels.cancel) buttonText = instance.settings.labels.cancel;
}
button.element.innerHTML = buttonText;
button.text = buttonText; // Update button.text to match the displayed text
if(typeof button.className === 'string' && button.className !== ''){ if(typeof button.className === 'string' && button.className !== ''){
addClass(button.element, button.className); addClass(button.element, button.className);
} }
...@@ -649,9 +625,6 @@ ...@@ -649,9 +625,6 @@
if(typeof instance.build === 'function'){ if(typeof instance.build === 'function'){
instance.build(); instance.build();
} }
//invoke postinit global hook
alertify.defaults.hooks.postinit(instance);
} }
//add to the end of the DOM tree. //add to the end of the DOM tree.
...@@ -699,13 +672,13 @@ ...@@ -699,13 +672,13 @@
* *
*/ */
function preventBodyShift(add){ function preventBodyShift(add){
if(alertify.defaults.preventBodyShift){ if(alertify.defaults.preventBodyShift && document.documentElement.scrollHeight > document.documentElement.clientHeight){
if(add && document.documentElement.scrollHeight > document.documentElement.clientHeight ){//&& openDialogs[openDialogs.length-1].elements.dialog.clientHeight <= document.documentElement.clientHeight){ if(add ){//&& openDialogs[openDialogs.length-1].elements.dialog.clientHeight <= document.documentElement.clientHeight){
topScroll = scrollY; topScroll = scrollY;
top = window.getComputedStyle(document.body).top; top = window.getComputedStyle(document.body).top;
addClass(document.body, classes.fixed); addClass(document.body, classes.fixed);
document.body.style.top = -scrollY + 'px'; document.body.style.top = -scrollY + 'px';
} else if(!add) { } else {
scrollY = topScroll; scrollY = topScroll;
document.body.style.top = top; document.body.style.top = top;
removeClass(document.body, classes.fixed); removeClass(document.body, classes.fixed);
...@@ -721,30 +694,13 @@ ...@@ -721,30 +694,13 @@
* *
*/ */
function updateTransition(instance, value, oldValue){ function updateTransition(instance, value, oldValue){
if(isString(oldValue)){ if(typeof oldValue === 'string'){
removeClass(instance.elements.root,classes.prefix + oldValue); removeClass(instance.elements.root,classes.prefix + oldValue);
} }
addClass(instance.elements.root, classes.prefix + value); addClass(instance.elements.root, classes.prefix + value);
reflow = instance.elements.root.offsetWidth; 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 * Toggles the dialog display mode
* *
...@@ -887,6 +843,9 @@ ...@@ -887,6 +843,9 @@
case 'resizable': case 'resizable':
updateResizable(instance); updateResizable(instance);
break; break;
case 'transition':
updateTransition(instance,newValue, oldValue);
break;
case 'padding': case 'padding':
if(newValue){ if(newValue){
removeClass(instance.elements.root, classes.noPadding); removeClass(instance.elements.root, classes.noPadding);
...@@ -901,12 +860,7 @@ ...@@ -901,12 +860,7 @@
addClass(instance.elements.root, classes.noOverflow); addClass(instance.elements.root, classes.noOverflow);
} }
break; break;
case 'transition':
updateTransition(instance,newValue, oldValue);
break;
case 'transitionOff':
updateTransitionOff(instance);
break;
} }
// internal on option updated event // internal on option updated event
...@@ -1002,7 +956,7 @@ ...@@ -1002,7 +956,7 @@
function triggerClose(instance) { function triggerClose(instance) {
var found; var found;
triggerCallback(instance, function (button) { triggerCallback(instance, function (button) {
return found = instance.get('invokeOnCloseOff') !== true && (button.invokeOnClose === true); return found = (button.invokeOnClose === true);
}); });
//none of the buttons registered as onclose callback //none of the buttons registered as onclose callback
//close the dialog //close the dialog
...@@ -1242,10 +1196,8 @@ ...@@ -1242,10 +1196,8 @@
} }
} }
// flag to cancel click event if already handled by end resize event (the mousedown, mousemove, mouseup sequence fires a click event.).
var cancelClick = false,// flag to cancel click event if already handled by end resize event (the mousedown, mousemove, mouseup sequence fires a click event.). var cancelClick = false;
modalClickHandlerTS=0 // stores last click timestamp to prevent executing the handler twice on double click.
;
/** /**
* Helper: closes the modal dialog when clicking the modal * Helper: closes the modal dialog when clicking the modal
...@@ -1256,17 +1208,14 @@ ...@@ -1256,17 +1208,14 @@
* @return {undefined} * @return {undefined}
*/ */
function modalClickHandler(event, instance) { function modalClickHandler(event, instance) {
if(event.timeStamp - modalClickHandlerTS > 200 && (modalClickHandlerTS = event.timeStamp) && !cancelClick){
var target = event.srcElement || event.target; var target = event.srcElement || event.target;
if (instance.get('closableByDimmer') === true && target === instance.elements.modal) { if (!cancelClick && target === instance.elements.modal && instance.get('closableByDimmer') === true) {
triggerClose(instance); triggerClose(instance);
} }
}
cancelClick = false; cancelClick = false;
return 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). // flag to cancel keyup event if already handled by click event (pressing Enter on a focusted button).
var cancelKeyup = false; var cancelKeyup = false;
/** /**
...@@ -1278,7 +1227,6 @@ ...@@ -1278,7 +1227,6 @@
* @return {undefined} * @return {undefined}
*/ */
function triggerCallback(instance, check) { function triggerCallback(instance, check) {
if(Date.now() - callbackTS > 200 && (callbackTS = Date.now())){
for (var idx = 0; idx < instance.__internal.buttons.length; idx += 1) { for (var idx = 0; idx < instance.__internal.buttons.length; idx += 1) {
var button = instance.__internal.buttons[idx]; var button = instance.__internal.buttons[idx];
if (!button.element.disabled && check(button)) { if (!button.element.disabled && check(button)) {
...@@ -1294,7 +1242,6 @@ ...@@ -1294,7 +1242,6 @@
} }
} }
} }
}
/** /**
* Clicks event handler, attached to the dialog footer. * Clicks event handler, attached to the dialog footer.
...@@ -1308,7 +1255,7 @@ ...@@ -1308,7 +1255,7 @@
var target = event.srcElement || event.target; var target = event.srcElement || event.target;
triggerCallback(instance, function (button) { triggerCallback(instance, function (button) {
// if this button caused the click, cancel keyup event // if this button caused the click, cancel keyup event
return button.element.contains(target) && (cancelKeyup = true); return button.element === target && (cancelKeyup = true);
}); });
} }
...@@ -1416,7 +1363,7 @@ ...@@ -1416,7 +1363,7 @@
} }
// if no focus element, default to first reset element. // if no focus element, default to first reset element.
if (instance.get('defaultFocusOff') === true || ((typeof element === 'undefined' || element === null) && instance.__internal.buttons.length === 0)) { if ((typeof element === 'undefined' || element === null) && instance.__internal.buttons.length === 0) {
element = instance.elements.reset[0]; element = instance.elements.reset[0];
} }
// focus // focus
...@@ -1450,53 +1397,40 @@ ...@@ -1450,53 +1397,40 @@
} }
} }
} }
if(instance) {
// if modal // if modal
if (instance.isModal()) { if (instance && instance.isModal()) {
// determine reset target to enable forward/backward tab cycle. // determine reset target to enable forward/backward tab cycle.
var firstReset = instance.elements.reset[0], var resetTarget, target = event.srcElement || event.target;
lastReset = instance.elements.reset[1], var lastResetElement = target === instance.elements.reset[1] || (instance.__internal.buttons.length === 0 && target === document.body);
lastFocusedElement = event.relatedTarget,
within = instance.elements.root.contains(lastFocusedElement), // if last reset link, then go to maximize or close
target = event.srcElement || event.target, if (lastResetElement) {
resetTarget; if (instance.get('maximizable')) {
resetTarget = instance.elements.commands.maximize;
//if the previous focused element element was outside the modal do nthing } else if (instance.get('closable')) {
if( /*first show */ resetTarget = instance.elements.commands.close;
(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){ // if no reset target found, try finding the best button
var tabbables = [].slice.call(instance.elements.dialog.querySelectorAll(defaults.tabbable)); if (resetTarget === undefined) {
if(last){ if (typeof instance.__internal.focus.element === 'number') {
tabbables.reverse(); // button focus element, go to first available button
if (target === instance.elements.reset[0]) {
resetTarget = instance.elements.buttons.auxiliary.firstChild || instance.elements.buttons.primary.firstChild;
} else if (lastResetElement) {
//restart the cycle by going to first reset link
resetTarget = instance.elements.reset[0];
} }
for(var x=0;x<tabbables.length;x+=1){ } else {
var tabbable = tabbables[x]; // will reach here when tapping backwards, so go to last child
//check if visible // The focus element SHOULD NOT be a button (logically!).
if(!!(tabbable.offsetParent || tabbable.offsetWidth || tabbable.offsetHeight || tabbable.getClientRects().length)){ if (target === instance.elements.reset[0]) {
return tabbable; resetTarget = instance.elements.buttons.primary.lastChild || instance.elements.buttons.auxiliary.lastChild;
} }
} }
} }
function recycleTab(event) { // focus
var instance = openDialogs[openDialogs.length - 1]; setFocus(instance, resetTarget);
if (instance && event.shiftKey && event.keyCode === keys.TAB) {
instance.elements.reset[1].focus();
} }
} }
/** /**
...@@ -1514,6 +1448,9 @@ ...@@ -1514,6 +1448,9 @@
// once transition is complete, set focus // once transition is complete, set focus
setFocus(instance); setFocus(instance);
//restore scroll to prevent document jump
restoreScrollPosition();
// allow handling key up after transition ended. // allow handling key up after transition ended.
cancelKeyup = false; cancelKeyup = false;
...@@ -1550,6 +1487,12 @@ ...@@ -1550,6 +1487,12 @@
restore(instance); restore(instance);
} }
// return focus to the last active element
if (alertify.defaults.maintainFocus && instance.__internal.activeElement) {
instance.__internal.activeElement.focus();
instance.__internal.activeElement = null;
}
//destory the instance //destory the instance
if (typeof instance.__internal.destroy === 'function') { if (typeof instance.__internal.destroy === 'function') {
instance.__internal.destroy.apply(instance); instance.__internal.destroy.apply(instance);
...@@ -2009,12 +1952,12 @@ ...@@ -2009,12 +1952,12 @@
//move //move
on(document.documentElement, 'mousemove', move); on(document.documentElement, 'mousemove', move);
on(document.documentElement, 'touchmove', move, false, false); on(document.documentElement, 'touchmove', move);
on(document.documentElement, 'mouseup', endMove); on(document.documentElement, 'mouseup', endMove);
on(document.documentElement, 'touchend', endMove); on(document.documentElement, 'touchend', endMove);
//resize //resize
on(document.documentElement, 'mousemove', resize); on(document.documentElement, 'mousemove', resize);
on(document.documentElement, 'touchmove', resize, false, false); on(document.documentElement, 'touchmove', resize);
on(document.documentElement, 'mouseup', endResize); on(document.documentElement, 'mouseup', endResize);
on(document.documentElement, 'touchend', endResize); on(document.documentElement, 'touchend', endResize);
} }
...@@ -2022,9 +1965,8 @@ ...@@ -2022,9 +1965,8 @@
// common events // common events
on(instance.elements.commands.container, 'click', instance.__internal.commandsClickHandler); on(instance.elements.commands.container, 'click', instance.__internal.commandsClickHandler);
on(instance.elements.footer, 'click', instance.__internal.buttonsClickHandler); on(instance.elements.footer, 'click', instance.__internal.buttonsClickHandler);
on(instance.elements.reset[0], 'focusin', instance.__internal.resetHandler); on(instance.elements.reset[0], 'focus', instance.__internal.resetHandler);
on(instance.elements.reset[0], 'keydown', recycleTab); on(instance.elements.reset[1], 'focus', instance.__internal.resetHandler);
on(instance.elements.reset[1], 'focusin', instance.__internal.resetHandler);
//prevent handling key up when dialog is being opened by a key stroke. //prevent handling key up when dialog is being opened by a key stroke.
cancelKeyup = true; cancelKeyup = true;
...@@ -2073,9 +2015,8 @@ ...@@ -2073,9 +2015,8 @@
// common events // common events
off(instance.elements.commands.container, 'click', instance.__internal.commandsClickHandler); off(instance.elements.commands.container, 'click', instance.__internal.commandsClickHandler);
off(instance.elements.footer, 'click', instance.__internal.buttonsClickHandler); off(instance.elements.footer, 'click', instance.__internal.buttonsClickHandler);
off(instance.elements.reset[0], 'focusin', instance.__internal.resetHandler); off(instance.elements.reset[0], 'focus', instance.__internal.resetHandler);
off(instance.elements.reset[0], 'keydown', recycleTab); off(instance.elements.reset[1], 'focus', instance.__internal.resetHandler);
off(instance.elements.reset[1], 'focusin', instance.__internal.resetHandler);
// hook out transition handler // hook out transition handler
on(instance.elements.dialog, transition.type, instance.__internal.transitionOutHandler); on(instance.elements.dialog, transition.type, instance.__internal.transitionOutHandler);
...@@ -2130,7 +2071,7 @@ ...@@ -2130,7 +2071,7 @@
*/ */
function bindMovableEvents(instance) { function bindMovableEvents(instance) {
on(instance.elements.header, 'mousedown', instance.__internal.beginMoveHandler); on(instance.elements.header, 'mousedown', instance.__internal.beginMoveHandler);
on(instance.elements.header, 'touchstart', instance.__internal.beginMoveHandler, false, false); on(instance.elements.header, 'touchstart', instance.__internal.beginMoveHandler);
} }
/** /**
...@@ -2142,7 +2083,7 @@ ...@@ -2142,7 +2083,7 @@
*/ */
function unbindMovableEvents(instance) { function unbindMovableEvents(instance) {
off(instance.elements.header, 'mousedown', instance.__internal.beginMoveHandler); off(instance.elements.header, 'mousedown', instance.__internal.beginMoveHandler);
off(instance.elements.header, 'touchstart', instance.__internal.beginMoveHandler, false, false); off(instance.elements.header, 'touchstart', instance.__internal.beginMoveHandler);
} }
...@@ -2156,7 +2097,7 @@ ...@@ -2156,7 +2097,7 @@
*/ */
function bindResizableEvents(instance) { function bindResizableEvents(instance) {
on(instance.elements.resizeHandle, 'mousedown', instance.__internal.beginResizeHandler); on(instance.elements.resizeHandle, 'mousedown', instance.__internal.beginResizeHandler);
on(instance.elements.resizeHandle, 'touchstart', instance.__internal.beginResizeHandler, false, false); on(instance.elements.resizeHandle, 'touchstart', instance.__internal.beginResizeHandler);
} }
/** /**
...@@ -2168,7 +2109,7 @@ ...@@ -2168,7 +2109,7 @@
*/ */
function unbindResizableEvents(instance) { function unbindResizableEvents(instance) {
off(instance.elements.resizeHandle, 'mousedown', instance.__internal.beginResizeHandler); off(instance.elements.resizeHandle, 'mousedown', instance.__internal.beginResizeHandler);
off(instance.elements.resizeHandle, 'touchstart', instance.__internal.beginResizeHandler, false, false); off(instance.elements.resizeHandle, 'touchstart', instance.__internal.beginResizeHandler);
} }
/** /**
...@@ -2385,7 +2326,7 @@ ...@@ -2385,7 +2326,7 @@
* @return {undefined} * @return {undefined}
*/ */
setHeader:function(content){ setHeader:function(content){
if(isString(content)){ if(typeof content === 'string'){
clearContents(this.elements.header); clearContents(this.elements.header);
this.elements.header.innerHTML = content; this.elements.header.innerHTML = content;
}else if (content instanceof window.HTMLElement && this.elements.header.firstChild !== content){ }else if (content instanceof window.HTMLElement && this.elements.header.firstChild !== content){
...@@ -2401,7 +2342,7 @@ ...@@ -2401,7 +2342,7 @@
* @return {undefined} * @return {undefined}
*/ */
setContent:function(content){ setContent:function(content){
if(isString(content)){ if(typeof content === 'string'){
clearContents(this.elements.content); clearContents(this.elements.content);
this.elements.content.innerHTML = content; this.elements.content.innerHTML = content;
}else if (content instanceof window.HTMLElement && this.elements.content.firstChild !== content){ }else if (content instanceof window.HTMLElement && this.elements.content.firstChild !== content){
...@@ -2439,16 +2380,35 @@ ...@@ -2439,16 +2380,35 @@
this.__internal.activeElement = document.activeElement; 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. //allow custom dom manipulation updates before showing the dialog.
if(typeof this.prepare === 'function'){ if(typeof this.prepare === 'function'){
this.prepare(); this.prepare();
} }
// Update button labels based on current settings before showing
if(this.settings.labels && this.__internal.buttons) {
var labels = this.settings.labels;
if(labels.ok && this.__internal.buttons[0] && this.__internal.buttons[0].element) {
this.__internal.buttons[0].element.innerHTML = labels.ok;
this.__internal.buttons[0].text = labels.ok;
}
if(labels.cancel && this.__internal.buttons[1] && this.__internal.buttons[1].element) {
this.__internal.buttons[1].element.innerHTML = labels.cancel;
this.__internal.buttons[1].text = labels.cancel;
}
}
// If no labels are set, use default glossary
else if(this.__internal.buttons) {
if(this.__internal.buttons[0] && this.__internal.buttons[0].element) {
this.__internal.buttons[0].element.innerHTML = alertify.defaults.glossary.ok;
this.__internal.buttons[0].text = alertify.defaults.glossary.ok;
}
if(this.__internal.buttons[1] && this.__internal.buttons[1].element) {
this.__internal.buttons[1].element.innerHTML = alertify.defaults.glossary.cancel;
this.__internal.buttons[1].text = alertify.defaults.glossary.cancel;
}
}
bindEvents(this); bindEvents(this);
if(modal !== undefined){ if(modal !== undefined){
...@@ -2474,7 +2434,7 @@ ...@@ -2474,7 +2434,7 @@
} }
updateAbsPositionFix(this); updateAbsPositionFix(this);
this.elements.root.removeAttribute('style');
removeClass(this.elements.root, classes.animationOut); removeClass(this.elements.root, classes.animationOut);
addClass(this.elements.root, classes.animationIn); addClass(this.elements.root, classes.animationIn);
...@@ -2495,9 +2455,6 @@ ...@@ -2495,9 +2455,6 @@
// show dialog // show dialog
removeClass(this.elements.root, classes.hidden); removeClass(this.elements.root, classes.hidden);
//restore scroll to prevent document jump
restoreScrollPosition();
// internal on show event // internal on show event
if(typeof this.hooks.onshow === 'function'){ if(typeof this.hooks.onshow === 'function'){
this.hooks.onshow.call(this); this.hooks.onshow.call(this);
...@@ -2527,8 +2484,6 @@ ...@@ -2527,8 +2484,6 @@
*/ */
close: function () { close: function () {
if (this.__internal.isOpen ) { if (this.__internal.isOpen ) {
// custom `onclosing` event
if(dispatchEvent('onclosing', this) !== false){
unbindEvents(this); unbindEvents(this);
...@@ -2543,12 +2498,6 @@ ...@@ -2543,12 +2498,6 @@
//reflow //reflow
reflow = this.elements.modal.offsetWidth; 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 // remove custom dialog class on hide
if (typeof this.__internal.className !== 'undefined' && this.__internal.className !== '') { if (typeof this.__internal.className !== 'undefined' && this.__internal.className !== '') {
removeClass(this.elements.root, this.__internal.className); removeClass(this.elements.root, this.__internal.className);
...@@ -2567,13 +2516,8 @@ ...@@ -2567,13 +2516,8 @@
this.__internal.isOpen = false; this.__internal.isOpen = false;
ensureNoOverflow(); ensureNoOverflow();
}
} }
// last dialog and tab index was set by us, remove it.
if(!openDialogs.length && tabindex === '0'){
document.body.removeAttribute('tabindex');
}
return this; return this;
}, },
/** /**
...@@ -2591,7 +2535,6 @@ ...@@ -2591,7 +2535,6 @@
* @return {undefined} * @return {undefined}
*/ */
destroy:function(){ destroy:function(){
if(this.__internal) {
if (this.__internal.isOpen ) { if (this.__internal.isOpen ) {
//mark dialog for destruction, this will be called on tranistionOut event. //mark dialog for destruction, this will be called on tranistionOut event.
this.__internal.destroy = function(){ this.__internal.destroy = function(){
...@@ -2599,21 +2542,27 @@ ...@@ -2599,21 +2542,27 @@
}; };
//close the dialog to unbind all events. //close the dialog to unbind all events.
this.close(); this.close();
}else if(!this.__internal.destroy){ }else{
destruct(this, initialize); destruct(this, initialize);
} }
}
return this; return this;
}, },
}; };
} () ); } () );
var notifier = (function () { var notifier = (function () {
var reflow, var reflow,
element, element,
openInstances = [], openInstances = [],
classes = defaults.notifier.classes, classes = {
baseClass = classes.base; base: 'alertify-notifier',
message: 'ajs-message',
top: 'ajs-top',
right: 'ajs-right',
bottom: 'ajs-bottom',
left: 'ajs-left',
visible: 'ajs-visible',
hidden: 'ajs-hidden'
};
/** /**
* Helper: initializes the notifier instance * Helper: initializes the notifier instance
* *
...@@ -2627,10 +2576,7 @@ ...@@ -2627,10 +2576,7 @@
}; };
element = document.createElement('DIV'); 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); updatePosition(instance);
} }
...@@ -2653,7 +2599,7 @@ ...@@ -2653,7 +2599,7 @@
* *
*/ */
function updatePosition(instance) { function updatePosition(instance) {
element.className = baseClass; element.className = classes.base;
switch (instance.__internal.position) { switch (instance.__internal.position) {
case 'top-right': case 'top-right':
addClass(element, classes.top + ' ' + classes.right); addClass(element, classes.top + ' ' + classes.right);
...@@ -2661,15 +2607,9 @@ ...@@ -2661,15 +2607,9 @@
case 'top-left': case 'top-left':
addClass(element, classes.top + ' ' + classes.left); addClass(element, classes.top + ' ' + classes.left);
break; break;
case 'top-center':
addClass(element, classes.top + ' ' + classes.center);
break;
case 'bottom-left': case 'bottom-left':
addClass(element, classes.bottom + ' ' + classes.left); addClass(element, classes.bottom + ' ' + classes.left);
break; break;
case 'bottom-center':
addClass(element, classes.bottom + ' ' + classes.center);
break;
default: default:
case 'bottom-right': case 'bottom-right':
...@@ -2690,10 +2630,8 @@ ...@@ -2690,10 +2630,8 @@
function create(div, callback) { function create(div, callback) {
function clickDelegate(event, instance) { function clickDelegate(event, instance) {
if(!instance.__internal.closeButton || event.target.getAttribute('data-close') === 'true'){
instance.dismiss(true); instance.dismiss(true);
} }
}
function transitionDone(event, instance) { function transitionDone(event, instance) {
// unbind event // unbind event
...@@ -2754,7 +2692,6 @@ ...@@ -2754,7 +2692,6 @@
wait = _wait; wait = _wait;
break; break;
} }
this.__internal.closeButton = alertify.defaults.notifier.closeButton;
// set contents // set contents
if (typeof content !== 'undefined') { if (typeof content !== 'undefined') {
this.setContent(content); this.setContent(content);
...@@ -2831,19 +2768,13 @@ ...@@ -2831,19 +2768,13 @@
* *
*/ */
setContent: function (content) { setContent: function (content) {
if (isString(content)) { if (typeof content === 'string') {
clearContents(this.element); clearContents(this.element);
this.element.innerHTML = content; this.element.innerHTML = content;
} else if (content instanceof window.HTMLElement && this.element.firstChild !== content) { } else if (content instanceof window.HTMLElement && this.element.firstChild !== content) {
clearContents(this.element); clearContents(this.element);
this.element.appendChild(content); 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; return this;
}, },
/* /*
...@@ -2914,7 +2845,7 @@ ...@@ -2914,7 +2845,7 @@
initialize(this); initialize(this);
//create new notification message //create new notification message
var div = document.createElement('div'); var div = document.createElement('div');
div.className = classes.message + ((typeof type === 'string' && type !== '') ? ' ' + classes.prefix + type : ''); div.className = classes.message + ((typeof type === 'string' && type !== '') ? ' ajs-' + type : '');
return create(div, callback); return create(div, callback);
}, },
/** /**
...@@ -2934,7 +2865,6 @@ ...@@ -2934,7 +2865,6 @@
} }
}; };
})(); })();
/** /**
* Alertify public API * Alertify public API
* This contains everything that is exposed through the alertify object. * This contains everything that is exposed through the alertify object.
...@@ -3351,6 +3281,8 @@ ...@@ -3351,6 +3281,8 @@
return { return {
main: function (_title, _message, _onok, _oncancel) { main: function (_title, _message, _onok, _oncancel) {
// Reset labels to null for each new call
this.settings.labels = null;
var title, message, onok, oncancel; var title, message, onok, oncancel;
switch (arguments.length) { switch (arguments.length) {
case 1: case 1:
...@@ -3590,7 +3522,7 @@ ...@@ -3590,7 +3522,7 @@
//nothing //nothing
}, },
setMessage: function (message) { setMessage: function (message) {
if (isString(message)) { if (typeof message === 'string') {
clearContents(p); clearContents(p);
p.innerHTML = message; p.innerHTML = message;
} else if (message instanceof window.HTMLElement && p.firstChild !== message) { } else if (message instanceof window.HTMLElement && p.firstChild !== message) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment