'use strict';
/**
* Dynamic form help.
* @namespace form_help
* @memberof UCASDesignFramework
* @param {object} global - UCASDesignFramework object.
* @param {object} _u - UCASUtilities object.
*/
(function (global, _u) {
var breakpoint
var currentForm
var currentFormItem
var resizeEventHandlers = []
/**
* Initialise form_help.
* @function init
* @memberof! UCASDesignFramework.form_help
* @public
* @param {Node} [context=document] - DOM element we're limiting selection to
* @param {string} [selector='.form--dynamic-help'] - CSS selector
*/
function init (context, selector) {
context = context || document
selector = selector || '.form--dynamic-help'
breakpoint = global.size.cssBreakpoint
// Add event listeners.
var forms = context.querySelectorAll(selector)
if (forms.length > 0) {
addHelpEventListeners(forms, breakpoint)
// On window resize, recheck breakpoint and remove/add event listeners as necessary.
var resizeEventHandler = function dynamicHelpResizeHandler () {
breakpoint = global.size.cssBreakpoint
addHelpEventListeners(forms, breakpoint)
}
resizeEventHandlers.push(resizeEventHandler)
window.addEventListener('dfResize', resizeEventHandler)
}
// Set an attribute on .layout-scope for IE.
if (document.documentMode) {
var scopes = context.querySelectorAll('.layout-scope')
scopes.forEach(function (scope) {
scope.setAttribute('data-layout-scope-legacy', '')
})
}
}
/**
* Destroy plugin.
* Assumes the form has been removed from the DOM.
* @function destroy
* @memberof! UCASDesignFramework.form_help
* @public
*/
function destroy () {
document.removeEventListener('click', formHelpDocumentClickHandler) // In practice unnecessary as the click handler removes the listener.
_u.forEach(resizeEventHandlers, function (i, resizeEventHandler) {
document.removeEventListener('dfResize', resizeEventHandler)
})
breakpoint = currentForm = currentFormItem = undefined
}
/**
* Add help event listeners.
* @param {NodeList} forms - nodelist of forms
* @param {string} breakpoint - the breakpoint
*/
function addHelpEventListeners (forms, breakpoint) {
if (breakpoint === 'xsmall') {
addHelpButtons(forms)
} else {
addDynamicHelpEventListeners(forms)
}
}
/**
* Add dynamic help event listeners.
* @param {NodeList} forms - nodelist of forms
*/
function addDynamicHelpEventListeners (forms) {
_u.forEach(forms, function (i, form) {
if (form.getAttribute('data-initialised') !== 'true') {
form.addEventListener('focusin', formHelpFocusHandler)
form.addEventListener('mouseleave', formHelpMouseleaveHelper)
form.setAttribute('data-initialised', 'true')
}
var formItems = form.querySelectorAll('.form-item--text, .form-item__radio, legend')
_u.forEach(formItems, function (i, formItem) {
if (formItem.getAttribute('data-initialised') !== 'true') {
formItem.addEventListener('mouseover', formHelpMouseoverHelper)
formItem.setAttribute('data-initialised', 'true')
_u.log.log('form_help.addDynamicHelpEventListeners', formItem)
}
})
})
}
/**
* Add help buttons.
* @param {NodeList} forms - nodelist of forms
*/
function addHelpButtons (forms) {
_u.forEach(forms, function (i, form) {
form.setAttribute('data-initialised', 'true')
var formItems = form.querySelectorAll('[class^="form-item"].dynamic-help')
_u.forEach(formItems, function (i, formItem) {
var button = formItem.querySelector('.button--help')
if (button === null) {
var label = formItem.querySelector('label')
var input = formItem.querySelector('input')
// Create the button.
button = document.createElement('button')
button.setAttribute('class', 'button button--help hide-text')
button.appendChild(document.createTextNode(formItem.getAttribute('data-toggle-help-button-label') || 'Help'))
button.id = 'button-' + input.getAttribute('aria-describedby')
formItem.insertBefore(button, label.nextSibling)
addButtonEventListeners(button)
}
})
})
}
/**
* Add button event listeners.
* @param {node} button - the button
*/
function addButtonEventListeners (button) {
UCASUtilities.toggle.create(
button.id,
function open () {
var formItem = this.$element.parentNode
var description = formItem.querySelector('.form-item__description')
formItem.setAttribute('data-form-item-active', 'true')
formItem.removeAttribute('data-toggle-transition')
_u.position.resetBreakout(description)
description.style.maxHeight = description.scrollHeight + 20 + 'px'
clearTimeout(formItem.transitionTimeout)
UCASUtilities.toggle.hideOthers(this.id)
},
function close () {
var formItem = this.$element.parentNode
var description = formItem.querySelector('.form-item__description')
clearTimeout(formItem.transitionTimeout)
formItem.setAttribute('data-toggle-transition', '')
description.style.maxHeight = 0
formItem.transitionTimeout = setTimeout(function () {
formItem.removeAttribute('data-toggle-transition')
formItem.setAttribute('data-form-item-active', 'false')
}, 500)
},
false
)
}
/**
* Help mouseover handler.
* @param {Event} e - DOM event
*/
function formHelpMouseoverHelper (e) {
// Don't use mouseover if we're focused on a form item.
if (e.target.closest('.form--dynamic-help[data-form-item-has-focus="true"]')) {
return
}
// If we're not wrapped in .dynamic-help, then exit.
if (!e.target.closest('.dynamic-help')) {
return
}
if (document.activeElement !== e.target) {
if (currentFormItem) {
currentFormItem.setAttribute('data-form-item-mouseover', 'false')
}
this.setAttribute('data-form-item-mouseover', 'true')
currentFormItem = this
setBreakout(e)
}
}
/**
* Help mouseleave handler.
* @param {Event} e - DOM event
*/
function formHelpMouseleaveHelper (e) {
if (currentFormItem) {
currentFormItem.setAttribute('data-form-item-mouseover', 'false')
}
}
/**
* Help focus handler.
* @param {Event} e - DOM event
*/
function formHelpFocusHandler (e) {
if (document.activeElement === e.target) {
setBreakout(e)
currentForm = this
this.setAttribute('data-form-item-has-focus', 'true')
this.addEventListener('focusout', formHelpFocusOutHandler)
document.addEventListener('click', formHelpDocumentClickHandler)
}
}
/**
* Document click handler.
* @param {Event} e - DOM event
*/
function formHelpDocumentClickHandler (e) {
if (currentFormItem !== undefined && (e.target.form !== currentForm || document.activeElement !== e.target)) {
currentFormItem.setAttribute('data-form-item-mouseover', 'false')
currentForm.setAttribute('data-form-item-has-focus', 'false')
document.removeEventListener('click', formHelpDocumentClickHandler)
}
}
/**
* Help focus out handler.
* @param {Event} e - DOM event
*/
function formHelpFocusOutHandler (e) {
this.setAttribute('data-form-item-has-focus', 'false')
this.removeEventListener('focusout', formHelpFocusOutHandler)
}
/**
* Set breakout styles.
* @param {Event} e - DOM event
*/
function setBreakout (e) {
// If we're using .layout-scope, then set a breakout so items don't get cropped.
if (currentFormItem) {
var scope = currentFormItem.closest('.layout-scope')
}
if (_u.position.breakout && scope) {
// params: element, scope, origin, left, top
_u.position.breakout(
currentFormItem.querySelector('.form-item__description'),
scope,
currentFormItem.querySelector('.form-item__description'),
0,
0
)
}
}
// Expose public methods
global.form_help = {
addSubscriptions: true,
init: init,
destroy: destroy
}
})(UCASDesignFramework, UCASUtilities)