alertifyjs
Version:
AlertifyJS is a javascript framework for developing pretty browser dialogs and notifications.
124 lines (118 loc) • 5.46 kB
JavaScript
/**
* 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();
}
}