'use strict';
/**
* Lightweight modal designed to be easily ported to SPA frameworks et al.
* @namespace modal_light
* @memberof UCASDesignFramework
* @param {object} global - UCASDesignFramework object.
* @param {object} _u - UCASUtilities object.
*/
(function (global, _u) {
var focusTracker
var attributePrefix = 'data-'
/**
* Initialise plugin
* @function init
* @memberof! UCASDesignFramework.modal_light
* @public
*/
function init () {
var modalTriggers = document.querySelectorAll('[modal-light-trigger]')
if (modalTriggers.length > 0) {
attributePrefix = ''
} else {
modalTriggers = document.querySelectorAll('[' + attributePrefix + 'modal-light-trigger]')
}
_u.forEach(modalTriggers, function (i, el) {
el.addEventListener('click', function (event) {
event.preventDefault()
showModal(event)
}, false)
})
// Escape key should close modal for accessibility
document.onkeydown = function (ev) {
ev = ev || window.event
var activeModal = document.querySelector('[' + attributePrefix + 'modal-light-state="visible"] aside')
if (ev.keyCode === 27 && activeModal) {
hideModal()
}
}
// Trap the focus
focusTrapper()
}
/**
* Remove event listeners and close all open modals.
* @function destroy
* @memberof! UCASDesignFramework.modal_light
* @public
*/
function destroy () {
var modalTriggers = document.querySelectorAll('[' + attributePrefix + 'modal-light-trigger]')
_u.forEach(modalTriggers, function (i, el) {
el.removeEventListener('click', showModal)
})
var targets = document.querySelectorAll('[' + attributePrefix + 'modal-light-close]')
_u.forEach(targets, function (i, el) {
el.removeEventListener('click', hideModal)
})
var openModal = document.querySelector('[' + attributePrefix + 'modal-light-state="visible"]')
if (openModal) {
openModal.setAttribute(attributePrefix + 'modal-light-state', 'hidden')
}
}
/**
* Works out which modal is at the top.
* @returns {Node} - the topmost modal
*/
function topModal () {
return document.querySelectorAll('[' + attributePrefix + 'modal-light-state="visible"]')[document.querySelectorAll('[' + attributePrefix + 'modal-light-state="visible"]').length - 1]
}
/**
* Displays a modal
* @function showModal
* @memberof! UCASDesignFramework.modal_light
* @param {string|event} modalID ID of modal to show or click event who's target contains a data-modal-id attribute
*/
function showModal (modalID) {
focusTracker = modalID
if (typeof modalID === 'object') {
modalID = modalID.target.attributes[attributePrefix + 'modal-light-id'].value
} else if (typeof modalID !== 'string') {
console.error('Can\'t open modal!', modalID, 'should be a string or event!')
// @todo handle errors globally see DF-526
return
}
var targetModal = document.getElementById(modalID)
if (!targetModal) {
console.error('Modal with ID ' + modalID + ' does not exist.')
return
}
targetModal.setAttribute(attributePrefix + 'modal-light-state', 'visible')
targetModal.querySelector('aside').focus()
attachCloseListener(targetModal)
/**
* @event modalLightShow
* @memberof! UCASDesignFramework.modal_light
*/
var event = document.createEvent('Event')
event.initEvent('modalLightShow', true, true)
targetModal.dispatchEvent(event)
}
/**
* Attaches event listeners to close modal
* @param {Node} targetModal - the modal
*/
function attachCloseListener (targetModal) {
var targets = targetModal.querySelectorAll('[' + attributePrefix + 'modal-light-close]')
_u.forEach(targets, function (i, el) {
el.addEventListener('click', hideModalListener, false)
})
}
/**
* Hide modal listener.
* @param {object} event]
*/
function hideModalListener (event) {
event.preventDefault()
hideModal()
}
/**
* Hides all modals or specific modalID
* @function hideModal
* @memberof! UCASDesignFramework.modal_light
* @param {string} modalID] ID of modal to hide (optional)
*/
function hideModal (modalID) {
var targetModal
if (typeof modalID === 'string') {
targetModal = document.getElementById(modalID)
targetModal.setAttribute(attributePrefix + 'modal-light-state', 'hidden')
} else {
// As there is not a specific target, apply only to the top modal.
targetModal = topModal()
targetModal.setAttribute(attributePrefix + 'modal-light-state', 'hidden')
if (typeof focusTracker !== 'string') {
focusTracker.target.focus()
}
}
/**
* @event modalLightHide
* @memberof! UCASDesignFramework.modal_light
*/
var event = document.createEvent('Event')
event.initEvent('modalLightHide', true, true)
targetModal.dispatchEvent(event)
}
/**
* Traps focus inside an active modal for accessibility
*/
function focusTrapper () {
document.addEventListener('focus', function (ev) {
var activeModal = topModal()
if (activeModal && !activeModal.contains(ev.target)) {
ev.stopPropagation()
activeModal.focus()
}
}, true)
}
/**
* Provide a simple way to reference a modal and show/hide it.
* @class
* @memberof! UCASDesignFramework.modal_light
* @public
* @example
* myLovelyModal = new UCASDesignFramework.modal_light.Modal("modal-1")
* myLovelyModal.show()
* myLovelyModal.hide()
*/
var Modal = (function () {
/**
* @param {string} id - id of the modal
*/
function Modal (id) {
this.id = id
}
Modal.prototype.show = function () {
showModal(this.id)
}
Modal.prototype.hide = function () {
hideModal(this.id)
}
return Modal
})()
// Expose public methods
global.modal_light = {
init: init,
destroy: destroy,
showModal: showModal,
hideModal: hideModal,
Modal: Modal
}
})(UCASDesignFramework, UCASUtilities)