File: /home/kbdhpghp/public_html/aqualander/wp-content/plugins/fluid-checkout/js/lib/flyout-block-406.js
/**
* Manage states and views for the flyout blocks.
*
* File flyout-block.js.
*/
(function (root, factory) {
if ( typeof define === 'function' && define.amd ) {
define([], factory(root));
} else if ( typeof exports === 'object' ) {
module.exports = factory(root);
} else {
root.FlyoutBlock = factory(root);
}
})(typeof global !== 'undefined' ? global : this.window || this.global, function (root) {
'use strict';
var _hasInitialized = false;
var _publicMethods = {
managers: [],
};
var _settings = { };
var _defaults = {
flyoutWrapperSelector: '[data-flyout]',
flyoutContentSelector: '[data-flyout-content]',
toggleButtonSelector: '[data-flyout-toggle]',
openButtonSelector: '[data-flyout-open]',
closeButtonSelector: '[data-flyout-close]',
overlaySelector: '[data-flyout-overlay]',
flyoutTogglePassActionSelector: '[data-flyout-pass-action], .js-flyout-pass-action',
autoFocusSelector: '[data-autofocus]',
flyoutToggleClassSelector: '.js-flyout-toggle',
flyoutClassTogglePrefix: 'js-flyout-target-',
idPrefix: 'flyout-block',
headingsSelector: 'h1, h2, h3, h4, h5, h6, [role="heading"]',
bodyHasFlyoutClass: 'has-flyout',
bodyHasFlyoutOpenClass: 'has-flyout--open',
isActivatedClass: 'is-activated',
isOpenClass: 'is-open',
openAnimationClass: 'fade-in-up',
closeAnimationClass: 'fade-out-down',
targetElementAttribute: 'data-flyout-target',
openAnimationClassAttribute: 'data-flyout-open-animation-class',
closeAnimationClassAttribute: 'data-flyout-close-animation-class',
manualFocusAttribute: 'data-flyout-manual-focus',
descriptionAttribute: 'data-flyout-description',
autoFocusAttribute: 'data-autofocus',
focusableElementsSelector: 'a[href], button:not([disabled]), input:not([disabled]):not([type="hidden"]), textarea:not([disabled]), select:not([disabled]), details, summary, iframe, object, embed, [contenteditable] [tabindex]:not([tabindex="-1"])',
flyoutRoleAttribute: 'data-flyout-role',
overlayTemplate: '<div class="flyout-overlay" data-flyout-overlay></div>',
};
var _states = {
OPEN: 'open',
CLOSED: 'closed',
}
var _key = {
TAB: 'Tab',
ENTER: 'Enter',
ESC: 'Escape',
SPACE: ' ',
}
/*!
* Merge two or more objects together.
* (c) 2017 Chris Ferdinandi, MIT License, https://gomakethings.com
* @param {Boolean} deep If true, do a deep (or recursive) merge [optional]
* @param {Object} objects The objects to merge together
* @returns {Object} Merged values of defaults and options
*/
var extend = function () {
// Variables
var extended = {};
var deep = false;
var i = 0;
// Check if a deep merge
if ( Object.prototype.toString.call( arguments[0] ) === '[object Boolean]' ) {
deep = arguments[0];
i++;
}
// Merge the object into the extended object
var merge = function (obj) {
for (var prop in obj) {
if (obj.hasOwnProperty(prop)) {
// If property is an object, merge properties
if (deep && Object.prototype.toString.call(obj[prop]) === '[object Object]') {
extended[prop] = extend(extended[prop], obj[prop]);
} else {
extended[prop] = obj[prop];
}
}
}
};
// Loop through each object and conduct a merge
for (; i < arguments.length; i++) {
var obj = arguments[i];
merge(obj);
}
return extended;
};
/**
* Gets keyboard-focusable elements within a specified element
*
* @param HTMLElement element The element to search within. Defaults to the `document` root element.
*
* @return NodeList All focusable elements withing the element passed in.
*/
var getFocusableElements = function( element ) {
// Set element to `document` root if not passed in
if ( ! element ) { element = document; }
// Get elements that are keyboard-focusable, but might be `disabled`
return element.querySelectorAll( _settings.focusableElementsSelector );
}
/**
* Get target element
*/
var getTargetElement = function( element ) {
// Bail if element not valid
if ( ! element ) return false;
// Try get target element from attributes
var targetSelector = element.getAttribute( _settings.targetElementAttribute );
if ( targetSelector && targetSelector != '' ) {
return document.querySelector( targetSelector );
}
// Return target element from parent nodes
return element.closest( _settings.flyoutWrapperSelector );
}
/**
* Get target element
*/
var getTargetElementFromClass = function( element ) {
if ( ! element ) { return false; }
// Iterate classes
for ( var i = 0; i < element.classList.length; i++ ) {
var cssClass = element.classList[i];
if ( cssClass.indexOf( _settings.flyoutClassTogglePrefix ) == 0 ) {
// Get target id from class name
var targetSelector = '#' + cssClass.replace( _settings.flyoutClassTogglePrefix, '' );
return document.querySelector( targetSelector );
}
}
return false;
}
/**
* Handle document clicks and route to the appropriate function.
*/
var handleClick = function ( e ) {
// TOGGLE
if ( e.target.closest( _settings.toggleButtonSelector ) ) {
e.preventDefault();
var button = e.target.closest( _settings.toggleButtonSelector );
var element = getTargetElement( button );
_publicMethods.toggle( element );
}
// TOGGLE (CSS CLASS)
else if ( e.target.closest( _settings.flyoutToggleClassSelector ) ) {
// Maybe prevent element's action
if ( ! e.target.closest( _settings.flyoutTogglePassActionSelector ) ) {
e.preventDefault();
}
var toggleElement = e.target.closest( _settings.flyoutToggleClassSelector );
var element = getTargetElementFromClass( toggleElement );
if ( element ) {
_publicMethods.toggle( element );
}
}
// OPEN
else if ( e.target.closest( _settings.openButtonSelector ) ) {
e.preventDefault();
var button = e.target.closest( _settings.openButtonSelector );
var element = getTargetElement( button );
_publicMethods.open( element );
}
// CLOSE
else if ( e.target.closest( _settings.closeButtonSelector ) ) {
e.preventDefault();
var button = e.target.closest( _settings.closeButtonSelector );
var element = getTargetElement( button );
_publicMethods.close( element );
}
// OVERLAY - Specific to a flyout block
else if ( e.target.matches( _settings.flyoutWrapperSelector ) ) {
var element = getTargetElement( e.target );
_publicMethods.close( element );
}
// OVERLAY - General
else if ( e.target.closest( _settings.overlaySelector ) ) {
_publicMethods.closeAll();
}
}
/**
* Handle keypress event.
*/
var handleKeyDown = function( e ) {
// Should do nothing if the default action has been cancelled
if ( e.defaultPrevented ) { return; }
// Close all flyout blocks if `ESC` was pressed
if ( e.key == _key.ESC ) {
_publicMethods.closeAll();
}
// ENTER on flyout trigger
if ( ( e.key == _key.ENTER || e.key == _key.SPACE ) && e.target.closest( _settings.triggerSelectors ) ) {
// Similate click
handleClick( e );
}
};
/**
* Set the `inert` property of the sibling elements.
*
* @param HTMLElement element The element which to maintain the focus in, all siblings will be marked with the value of the param `inert` except this one.
* @param bool inert Boolean value to set to the `inert` property, `true` will make siblings inert, `false` will release the inert state.
*/
var setSiblingsInert = function( element, inert ) {
// Bail if element does not have a parentNode
if ( ! element || ! element.parentNode ) { return; }
// Release all elements in case of an invalid value for the `inert` param.
if ( typeof inert !== 'boolean' ) { inert = false; }
// Make all other elements `inert`
var siblings = element.parentNode ? element.parentNode.childNodes : null;
if ( siblings ) {
Array.from( siblings ).forEach( function( child ) {
if ( child != element ) { child.inert = inert; }
} );
}
}
/**
* Set all sibling elements on the passed element's tree with `inert` property.
*
* @param HTMLElement element The element which to maintain the focus in, all siblings up the element's tree will be marked with the value of the param `inert` except this one.
* @param bool inert Boolean value to set to the `inert` property, `true` will make siblings inert, `false` will release the inert state.
*/
var setTreeSiblingsInert = function( element, inert ) {
// Bail if element does not have a parentNode
if ( ! element || ! element.parentNode ) { return; }
var targetElement = element;
while ( targetElement.parentNode ) {
setSiblingsInert( targetElement, inert );
targetElement = targetElement.parentNode;
}
}
/**
* Get current state of element
*/
_publicMethods.getState = function ( element ) {
var manager = _publicMethods.getInstance( element );
// Bail if manager invalid
if ( ! manager ) return false;
return manager.state;
}
/**
* Open element
*/
_publicMethods.open = function ( element ) {
var manager = _publicMethods.getInstance( element );
// Bail if manager invalid
if ( ! manager ) return false;
// Save element with focus
manager.previousActiveElement = document.activeElement;
// Set element open then play openning animation
AnimateHelper.doThenAnimate( element, manager.settings.openAnimationClass, function() {
// Set manager state
manager.state = _states.OPEN;
// Maybe save `hidden` attribute on the flyout element
manager.wasHidden = manager.element.hasAttribute( 'hidden' );
manager.element.removeAttribute( 'hidden' );
// Set classes
manager.element.classList.add( manager.settings.isOpenClass );
document.body.classList.add( manager.settings.bodyHasFlyoutOpenClass, manager.settings.bodyHasFlyoutOpenClass + '-' + manager.element.id );
// Set flyout content `role` attribute from data attributes
var roleAttrValue = manager.element.getAttribute( manager.settings.flyoutRoleAttribute ) == 'alert' || manager.element.getAttribute( manager.settings.flyoutRoleAttribute ) == 'alertdialog' ? 'alertdialog' : 'dialog';
manager.contentElement.setAttribute( 'role', roleAttrValue );
// Set content element as focusable
manager.contentElement.setAttribute( 'tabindex', 0 );
// Maybe skip setting focus
if ( ! manager.element.hasAttribute( manager.settings.manualFocusAttribute ) ) {
// Set focus element as the dialog itself
var focusElement = manager.contentElement;
// Maybe set focus to child element marked as auto-focus
var autofocusChild = manager.element.querySelector( manager.settings.autoFocusSelector );
if ( autofocusChild ) {
focusElement = autofocusChild;
}
// Maybe set focus to first focusable element
else if ( manager.element.matches( manager.settings.autoFocusSelector ) ) {
var focusableElements = Array.from( getFocusableElements( manager.element ) );
focusableElements = focusableElements.filter( function( maybeFocusable ) { return ! maybeFocusable.matches( manager.settings.closeButtonSelector ); } );
if ( focusableElements.length > 0 ) {
focusElement = focusableElements[0];
}
}
// Set focus
focusElement.focus();
}
// Make all other elements `inert`
setTreeSiblingsInert( manager.element, true );
} );
}
/**
* Close element
*/
_publicMethods.close = function ( element ) {
var manager = _publicMethods.getInstance( element );
// Bail if manager invalid
if ( ! manager ) return false;
// Play closing animation then set element closed
AnimateHelper.animateThenDo( element, manager.settings.closeAnimationClass, function() {
// Set manager state
manager.state = _states.CLOSED;
// Remove classes
manager.element.classList.remove( manager.settings.isOpenClass );
document.body.classList.remove( manager.settings.bodyHasFlyoutOpenClass + '-' + manager.element.id );
// Remove flyout content `role` attribute
manager.contentElement.removeAttribute( 'role' );
// Set content element as not-focusable
manager.contentElement.removeAttribute( 'tabindex' );
// Maybe set `hidden` attribute again
if ( manager.wasHidden ) {
manager.element.setAttribute( 'hidden', '' );
}
manager.element.wasHidden = undefined;
// Maybe remove body class for open elements
if ( ! _publicMethods.hasAnyElementOpen() ) {
document.body.classList.remove( manager.settings.bodyHasFlyoutOpenClass );
}
// Release all other elements, set `inert` to false
setTreeSiblingsInert( manager.element, false );
// Set focus back to the element previously with focus
if ( manager.previousActiveElement ) {
manager.previousActiveElement.focus();
}
} );
}
/**
* Close all instances
*/
_publicMethods.closeAll = function () {
for ( var i = 0; i < _publicMethods.managers.length; i++ ) {
var manager = _publicMethods.managers[i];
var currentState = _publicMethods.getState( manager.element );
if ( currentState != _states.CLOSED ) {
_publicMethods.close( manager.element );
}
}
}
/**
* Toggle element state
*/
_publicMethods.toggle = function ( element ) {
var currentState = _publicMethods.getState( element );
if ( currentState == _states.CLOSED ) {
_publicMethods.open( element );
}
else {
_publicMethods.close( element );
}
}
/**
* Get manager instance for element
*/
_publicMethods.getInstance = function ( element ) {
var instance;
for ( var i = 0; i < _publicMethods.managers.length; i++ ) {
var manager = _publicMethods.managers[i];
if ( manager.element == element ) { instance = manager; break; }
}
return instance;
}
/**
* Get manager instance for element
*/
_publicMethods.hasAnyElementOpen = function () {
for ( var i = 0; i < _publicMethods.managers.length; i++ ) {
var manager = _publicMethods.managers[i];
if ( manager.state == _states.OPEN ) { return true; }
}
return false;
}
/**
* Initialize a trigger element.
*/
_publicMethods.initializeTrigger = function( trigger ) {
// Enable the trigger element
trigger.removeAttribute( 'disabled' );
trigger.removeAttribute( 'aria-hidden' );
// Add the element to the natural tab order
trigger.setAttribute( 'tabindex', '0' );
// Set trigger role to `button`
if ( trigger.tagName.toUpperCase() != 'BUTTON' ) {
trigger.setAttribute( 'role', 'button' );
}
// Maybe move selector to the target attribute
var triggerHref = trigger.getAttribute( 'href' );
if ( triggerHref != undefined && triggerHref != '' && triggerHref != '#' && triggerHref.indexOf( '#' ) == 0 ) {
// Move selector to the target attribute
var targetElement = document.querySelector( triggerHref );
if ( targetElement ) {
trigger.setAttribute( _settings.targetElementAttribute, triggerHref );
}
}
// Remove the `href` attribute if the element has a flyout target
if ( trigger.getAttribute( _settings.targetElementAttribute ) ) {
trigger.removeAttribute( 'href' );
}
}
/**
* Initialize Script.
*/
_publicMethods.initTriggers = function() {
// Iterate trigger elements
var triggers = document.querySelectorAll( _settings.triggerSelectors );
for ( var i = 0; i < triggers.length; i++ ) {
_publicMethods.initializeTrigger( triggers[ i ] );
}
}
/**
* Initialize an element
*/
_publicMethods.initializeElement = function( element ) {
var manager = {};
manager.element = element;
manager.settings = extend( _settings );
manager.state = _states.CLOSED;
// Maybe create element ID
if ( ! manager.element.id || manager.element.id == '' ) {
manager.element.id = manager.settings.idPrefix + '-' + _publicMethods.managers.length;
}
// Get the content element
manager.contentElement = manager.element.querySelector( manager.settings.flyoutContentSelector );
// Try get open/close animation classes from attributes
var openAnimationAttrValue = manager.element.getAttribute( manager.settings.openAnimationClassAttribute );
var closeAnimationAttrValue = manager.element.getAttribute( manager.settings.closeAnimationClassAttribute );
manager.settings.openAnimationClass = openAnimationAttrValue && openAnimationAttrValue != '' ? openAnimationAttrValue : _settings.openAnimationClass;
manager.settings.closeAnimationClass = closeAnimationAttrValue && closeAnimationAttrValue != '' ? closeAnimationAttrValue : _settings.closeAnimationClass;
// Set flyout accessible name
var ariaLabelValue = manager.element.getAttribute( 'aria-label' );
var ariaLabelledbyValue = manager.element.getAttribute( 'aria-labelledby' );
if ( ( ! ariaLabelValue || ariaLabelValue == '' ) && ( ! ariaLabelledbyValue || ariaLabelledbyValue == '' ) ) {
var firstHeading = manager.contentElement.querySelector( manager.settings.headingsSelector );
// Set `aria-labelled` If a heading element exists inside the flyout content element
if ( firstHeading ) {
var headingId = firstHeading.id != undefined && firstHeading.id != '' ? firstHeading.id : manager.element.id + '-heading';
firstHeading.id = headingId;
manager.contentElement.setAttribute( 'aria-labelledby', headingId );
}
}
// Set flyout accessible description
var ariaDescribedbyValue = manager.element.getAttribute( 'aria-describedby' );
if ( ! ariaDescribedbyValue || ariaDescribedbyValue == '' ) {
var descriptionElement = manager.contentElement.querySelector( '[' + manager.settings.descriptionAttribute + ']' );
// If a description element exists inside the flyout content element
if ( descriptionElement ) {
var descriptionId = descriptionElement.id != undefined && descriptionElement.id != '' ? descriptionElement.id : manager.element.id + '-description';
descriptionElement.id = descriptionId;
manager.contentElement.setAttribute( 'aria-describedby', descriptionId );
}
}
// Set element as activated
manager.isActivated = true;
manager.element.classList.add( manager.settings.isActivatedClass );
// Add manager to public methods
_publicMethods.managers.push( manager );
}
/**
* Finish Initialize
*/
var finishInit = function( options ) {
// Merge with general settings with options
_settings = extend( _defaults, options );
// Set dynamic settings value
_settings.triggerSelectors = _settings.toggleButtonSelector + ', ' + _settings.openButtonSelector + ', ' + _settings.closeButtonSelector;
// Iterate elements
var elements = document.querySelectorAll( _settings.flyoutWrapperSelector );
for ( var i = 0; i < elements.length; i++ ) {
_publicMethods.initializeElement( elements[ i ] );
}
// Iterate trigger elements
_publicMethods.initTriggers();
// Add flyout overlay
var overlayElement = document.createElement('div');
overlayElement.innerHTML = _settings.overlayTemplate.trim();
document.body.appendChild( overlayElement.childNodes[0] );
// Add event listeners
document.addEventListener( 'click', handleClick );
document.addEventListener( 'keydown', handleKeyDown, true );
// Add body class
document.body.classList.add( _settings.bodyHasFlyoutClass );
_hasInitialized = true;
}
/**
* Initialize Script.
*/
_publicMethods.init = function( options ) {
if ( _hasInitialized ) return;
// Maybe finish initialization
if ( window.AnimateHelper && ( HTMLElement.prototype.hasOwnProperty('inert') || Element.prototype.hasOwnProperty( 'inert' ) ) ) {
finishInit( options );
}
else {
console.log( 'FlyoutBlock could not be initialized.' );
console.log( 'AnimateHelper loaded: ' + !! window.AnimateHelper );
console.log( 'HTMLElement has `inert` property: ' + !! HTMLElement.prototype.hasOwnProperty('inert') );
console.log( 'Element has `inert` property: ' + !! Element.prototype.hasOwnProperty('inert') );
}
};
//
// Public APIs
//
return _publicMethods;
});