/*

* ES2015 simple and accessible hide-show system (collapsible regions), using ARIA
* Website: https://van11y.net/accessible-hide-show/
* License MIT: https://github.com/nico3333fr/van11y-accessible-hide-show-aria/blob/master/LICENSE
*/

const loadConfig = () => {

const CACHE = {};

const set = (id, config) => {

    CACHE[id] = config;

};
const get = (id) => CACHE[id];
const remove = (id) => CACHE[id];

return {
    set,
    get,
    remove
}

};

const DATA_HASH_ID = 'data-hash-id';

const pluginConfig = loadConfig();

const findById = (id, hash) => document.querySelector(`#$id`);

const addClass = (el, className) => {

if (el.classList) {
    el.classList.add(className); // IE 10+
} else {
    el.className += ' ' + className; // IE 8+
}

}

const removeClass = (el, className) => {

if (el.classList) {
    el.classList.remove(className); // IE 10+
} else {
    el.className = el.className.replace(new RegExp('(^|\\b)' + className.split(' ').join('|') + '(\\b|$)', 'gi'), ' '); // IE 8+
}

}

const hasClass = (el, className) => {

if (el.classList) {
    return el.classList.contains(className); // IE 10+
} else {
    return new RegExp('(^| )' + className + '( |$)', 'gi').test(el.className); // IE 8+ ?
}

}

const setAttributes = (node, attrs) => {

Object
    .keys(attrs)
    .forEach((attribute) => {
        node.setAttribute(attribute, attrs[attribute]);
    });

};

const triggerEvent = (el, event_type) => {

if (el.fireEvent) {
    el.fireEvent('on' + event_type);
} else {
    let evObj = document.createEvent('Events');
    evObj.initEvent(event_type, true, false);
    el.dispatchEvent(evObj);
}

}

/* gets an element el, search if it is element with class or child of parent class, returns id of the element founded */ const searchParentHashId = (el, hashId) => {

let found = false;

let parentElement = el;
while (parentElement.nodeType === 1 && parentElement && found === false) {

    if (parentElement.hasAttribute(hashId) === true) {
        found = true;
    } else {
        parentElement = parentElement.parentNode;
    }
}
if (found === true) {
    return parentElement.getAttribute(hashId);
} else {
    return '';
}

} const searchParent = (el, parentClass, hashId) => {

let found = false;

let parentElement = el;
while (parentElement && found === false) {
    if (hasClass(parentElement, parentClass) === true && parentElement.getAttribute(DATA_HASH_ID) === hashId) {
        found = true;
    } else {
        parentElement = parentElement.parentNode;
    }
}
if (found === true) {
    return parentElement.getAttribute('id');
} else {
    return '';
}

}

const plugin = (config = {}) => {

const CONFIG = {
    HIDESHOW_EXPAND: 'js-expandmore',
    HIDESHOW_BUTTON_EXPAND: 'js-expandmore-button',
    HIDESHOW_BUTTON_EXPAND_STYLE: 'expandmore__button',
    HIDESHOW_BUTTON_LABEL_ID: 'label_expand_',

    DATA_PREFIX_CLASS: 'data-hideshow-prefix-class',

    HIDESHOW_BUTTON_EMPTY_ELEMENT_SYMBOL: 'expandmore__symbol',
    HIDESHOW_BUTTON_EMPTY_ELEMENT_TAG: 'span',
    ATTR_HIDESHOW_BUTTON_EMPTY_ELEMENT: 'aria-hidden',

    HIDESHOW_TO_EXPAND_ID: 'expand_',
    HIDESHOW_TO_EXPAND_STYLE: 'expandmore__to_expand',

    /*
     recommended settings by a11y expert
    */
    ATTR_CONTROL: 'data-controls',
    ATTR_EXPANDED: 'aria-expanded',
    ATTR_LABELLEDBY: 'data-labelledby',
    ATTR_HIDDEN: 'data-hidden',

    IS_OPENED_CLASS: 'is-opened',

    DISPLAY_FIRST_LOAD: 'js-first_load',
    DISPLAY_FIRST_LOAD_DELAY: '1500',
    ...config
};

const HASH_ID = Math.random().toString(32).slice(2, 12);

pluginConfig.set(HASH_ID, CONFIG);

/** Find all expand inside a container
 * @param  {Node} node Default document
 * @return {Array}
 */
const $listHideShows = (node = document) => [].slice.call(node.querySelectorAll('.' + CONFIG.HIDESHOW_EXPAND)); //[...node.querySelectorAll('.' + CONFIG.HIDESHOW_EXPAND)]; // that does not work on IE when transpiled :-(

/**
 * Build expands for a container
 * @param  {Node} node
 */
const attach = (node) => {

    $listHideShows(node)
        .forEach((expand_node) => {

            let iLisible = Math.random().toString(32).slice(2, 12);
            // let prefixClassName = typeof expand_node.getAttribute(DATA_PREFIX_CLASS) !== 'undefined' ? expand_node.getAttribute(DATA_PREFIX_CLASS) + '-' : '' ; // IE11+
            let prefixClassName = expand_node.hasAttribute(CONFIG.DATA_PREFIX_CLASS) === true ? expand_node.getAttribute(CONFIG.DATA_PREFIX_CLASS) + '-' : '';
            let toExpand = expand_node.nextElementSibling;
            let expandmoreText = expand_node.innerHTML;
            let expandButton = document.createElement("BUTTON");
            let expandButtonEmptyElement = document.createElement(CONFIG.HIDESHOW_BUTTON_EMPTY_ELEMENT_TAG);

            expand_node.setAttribute(DATA_HASH_ID, HASH_ID);

            // empty element for symbol
            addClass(expandButtonEmptyElement, prefixClassName + CONFIG.HIDESHOW_BUTTON_EMPTY_ELEMENT_SYMBOL);
            setAttributes(expandButtonEmptyElement, {
                [CONFIG.ATTR_HIDESHOW_BUTTON_EMPTY_ELEMENT]: true,
                [DATA_HASH_ID]: HASH_ID
            });

            // clear element before adding button to it
            expand_node.innerHTML = '';

            // create a button with all attributes
            addClass(expandButton, prefixClassName + CONFIG.HIDESHOW_BUTTON_EXPAND_STYLE);
            addClass(expandButton, CONFIG.HIDESHOW_BUTTON_EXPAND);
            setAttributes(expandButton, {
                [CONFIG.ATTR_CONTROL]: CONFIG.HIDESHOW_TO_EXPAND_ID + iLisible,
                [CONFIG.ATTR_EXPANDED]: 'false',
                'id': CONFIG.HIDESHOW_BUTTON_LABEL_ID + iLisible,
                'type': 'button',
                [DATA_HASH_ID]: HASH_ID
            });
            expandButton.innerHTML = expandmoreText;

            // Button goes into node
            expand_node.appendChild(expandButton);
            expandButton.insertBefore(expandButtonEmptyElement, expandButton.firstChild);

            // to expand attributes
            setAttributes(toExpand, {
                [CONFIG.ATTR_LABELLEDBY]: CONFIG.HIDESHOW_BUTTON_LABEL_ID + iLisible,
                [CONFIG.ATTR_HIDDEN]: 'true',
                'id': CONFIG.HIDESHOW_TO_EXPAND_ID + iLisible,
                [DATA_HASH_ID]: HASH_ID
            });

            // add delay if DISPLAY_FIRST_LOAD
            addClass(toExpand, prefixClassName + CONFIG.HIDESHOW_TO_EXPAND_STYLE);
            if (hasClass(toExpand, CONFIG.DISPLAY_FIRST_LOAD) === true) {
                setTimeout(function() {
                    removeClass(toExpand, CONFIG.DISPLAY_FIRST_LOAD);
                }, CONFIG.DISPLAY_FIRST_LOAD_DELAY);
            }

            // quick tip to open
            if (hasClass(toExpand, CONFIG.IS_OPENED_CLASS) === true) {
                addClass(expandButton, CONFIG.IS_OPENED_CLASS);
                expandButton.setAttribute(CONFIG.ATTR_EXPANDED, 'true');

                removeClass(toExpand, CONFIG.IS_OPENED_CLASS);
                toExpand.removeAttribute(CONFIG.ATTR_HIDDEN);

            }

        });

};

/*const destroy = (node) => {
    $listHideShows(node)
    .forEach((expand_node) => {

    });
};*/

return {
    attach
    /*,
            destroy*/
}

};

const main = () => {

/* listeners for all configs */
['click', 'keydown']
.forEach(eventName => {

    document.body
        .addEventListener(eventName, e => {

            let hashId = searchParentHashId(e.target, DATA_HASH_ID); //e.target.dataset.hashId;
            // search if click on button or on element in a button contains data-hash-id (it is needed to load config and know which class to search)

            if (hashId !== '') {

                // loading config from element
                let CONFIG = pluginConfig.get(hashId);

                // search if click on button or on element in a button (fix for Chrome)
                let id_expand_button = searchParent(e.target, CONFIG.HIDESHOW_BUTTON_EXPAND, hashId);

                // click on button
                if (id_expand_button !== '' && eventName === 'click') {
                    let button_tag = findById(id_expand_button, hashId);
                    let destination = findById(button_tag.getAttribute(CONFIG.ATTR_CONTROL), hashId);
                    let etat_button = button_tag.getAttribute(CONFIG.ATTR_EXPANDED);

                    // if closed
                    if (etat_button === 'false') {
                        button_tag.setAttribute(CONFIG.ATTR_EXPANDED, true);
                        addClass(button_tag, CONFIG.IS_OPENED_CLASS);
                        destination.removeAttribute(CONFIG.ATTR_HIDDEN);
                    } else {
                        button_tag.setAttribute(CONFIG.ATTR_EXPANDED, false);
                        removeClass(button_tag, CONFIG.IS_OPENED_CLASS);
                        destination.setAttribute(CONFIG.ATTR_HIDDEN, true);
                    }

                }
                // click on hx (fix for voiceover = click or keydown on hx => click on button.
                // this makes no sense, but somebody has to do the job to make it fucking work
                if (hasClass(e.target, CONFIG.HIDESHOW_EXPAND) === true) {
                    let hx_tag = e.target;
                    let button_in = hx_tag.querySelector('.' + CONFIG.HIDESHOW_BUTTON_EXPAND)

                    if (hx_tag != button_in) {
                        if (eventName === 'click') {
                            triggerEvent(button_in, 'click');
                            return false;
                        }
                        if (eventName === 'keydown' && (13 === e.keyCode || 32 === e.keyCode)) {
                            triggerEvent(button_in, 'click');
                            return false;
                        }
                    }

                }

            }

        }, true);

});

return plugin;

};

window.van11yAccessibleHideShowAria = main();

const onLoad = () => {

const expand_default = window.van11yAccessibleHideShowAria();
expand_default.attach();

document.removeEventListener('DOMContentLoaded', onLoad);

}

document.addEventListener('DOMContentLoaded', onLoad);