/**
 * micromodal.js
 * @version 0.4.10
 * Lightweight modal library
 * @author Ghosh
 * @license MIT
 */

(function (global, factory) {
    typeof exports === 'object' && typeof module !== 'undefined'
      ? (module.exports = factory())
      : typeof define === 'function' && define.amd
      ? define(factory)
      : (global.MicroModal = factory());
  })(this, function () {
    'use strict';
  
    var version = '0.4.10';
  
    var MicroModal = (function () {
      var FOCUSABLE_ELEMENTS =
        'a[href], area[href], input:not([disabled]):not([type=hidden]), select:not([disabled]), textarea:not([disabled]), button:not([disabled]), iframe, object, embed, [tabindex="0"], [contenteditable]';
  
      function Modal(_ref) {
        var targetModal = _ref.targetModal,
          triggers = _ref.triggers,
          onShow = _ref.onShow,
          onClose = _ref.onClose,
          openTrigger = _ref.openTrigger,
          closeTrigger = _ref.closeTrigger,
          disableScroll = _ref.disableScroll,
          disableFocus = _ref.disableFocus,
          awaitCloseAnimation = _ref.awaitCloseAnimation,
          awaitOpenAnimation = _ref.awaitOpenAnimation,
          debugMode = _ref.debugMode;
  
        // Save a reference of the modal
        this.modal = document.getElementById(targetModal);
  
        // Save a reference to the passed config
        this.config = {
          debugMode: debugMode || false,
          disableScroll: disableScroll || false,
          openTrigger: openTrigger || 'data-micromodal-trigger',
          closeTrigger: closeTrigger || 'data-micromodal-close',
          onShow: onShow || function () {},
          onClose: onClose || function () {},
          awaitCloseAnimation: awaitCloseAnimation || false,
          awaitOpenAnimation: awaitOpenAnimation || false,
          disableFocus: disableFocus || false
        };
  
        // Register click events only if pre binding eventListeners
        if (triggers.length > 0) this.registerTriggers.apply(this, triggers);
  
        // pre bind functions for event listeners
        this.onClick = this.onClick.bind(this);
        this.onKeydown = this.onKeydown.bind(this);
      }
  
      /**
       * Loops through all openTriggers and binds click event
       * @param  {array} triggers [Array of node elements]
       * @return {void}
       */
      Modal.prototype.registerTriggers = function registerTriggers() {
        var _this = this;
  
        for (
          var _len = arguments.length, triggers = new Array(_len), _key = 0;
          _key < _len;
          _key++
        ) {
          triggers[_key] = arguments[_key];
        }
  
        triggers.forEach(function (trigger) {
          trigger.addEventListener('click', function (event) {
            return _this.showModal(event);
          });
        });
      };
  
      Modal.prototype.showModal = function showModal() {
        var _this2 = this;
  
        this.activeElement = document.activeElement;
        this.modal.setAttribute('aria-hidden', 'false');
        this.modal.classList.add('is-open');
        this.scrollBehaviour('disable');
        this.addEventListeners();
        if (this.config.awaitOpenAnimation) {
          var handler = function handler() {
            _this2.modal.removeEventListener('animationend', handler, false);
            _this2.setFocusToFirstNode();
          };
          this.modal.addEventListener('animationend', handler, false);
        } else {
          this.setFocusToFirstNode();
        }
        this.config.onShow(this.modal);
      };
  
      Modal.prototype.closeModal = function closeModal(event) {
        var modal = this.modal;
        this.modal.setAttribute('aria-hidden', 'true');
        this.removeEventListeners();
        this.scrollBehaviour('enable');
        if (this.activeElement && this.activeElement.focus) {
          this.activeElement.focus();
        }
        this.config.onClose(this.modal);
  
        if (this.config.awaitCloseAnimation) {
          this.modal.classList.remove('is-open');
          var openHandler = function openHandler() {
            modal.removeEventListener('animationend', openHandler, false);
            modal.classList.remove('is-open');
          };
          modal.addEventListener('animationend', openHandler, false);
        } else {
          this.modal.classList.remove('is-open');
        }
      };
  
      Modal.prototype.scrollBehaviour = function scrollBehaviour(toggle) {
        if (!this.config.disableScroll) return;
        if (toggle === 'enable') document.body.classList.remove('micromodal-open');
        else document.body.classList.add('micromodal-open');
      };
  
      Modal.prototype.addEventListeners = function addEventListeners() {
        this.modal.addEventListener('touchstart', this.onClick);
        this.modal.addEventListener('click', this.onClick);
        document.addEventListener('keydown', this.onKeydown);
      };
  
      Modal.prototype.removeEventListeners = function removeEventListeners() {
        this.modal.removeEventListener('touchstart', this.onClick);
        this.modal.removeEventListener('click', this.onClick);
        document.removeEventListener('keydown', this.onKeydown);
      };
  
      Modal.prototype.onClick = function onClick(event) {
        if (event.target.hasAttribute(this.config.closeTrigger)) {
          this.closeModal(event);
          event.preventDefault();
        }
      };
  
      Modal.prototype.onKeydown = function onKeydown(event) {
        if (event.keyCode === 27) this.closeModal(event);
        if (event.keyCode === 9) this.maintainFocus(event);
      };
  
      Modal.prototype.getFocusableNodes = function getFocusableNodes() {
        var nodes = this.modal.querySelectorAll(FOCUSABLE_ELEMENTS);
        return Array.apply(void 0, nodes);
      };
  
      Modal.prototype.setFocusToFirstNode = function setFocusToFirstNode() {
        if (this.config.disableFocus) return;
        var focusableNodes = this.getFocusableNodes();
        if (focusableNodes.length) focusableNodes[0].focus();
      };
  
      Modal.prototype.maintainFocus = function maintainFocus(event) {
        var focusableNodes = this.getFocusableNodes();
  
        // no focusable nodes
        if (focusableNodes.length === 0) {
          event.preventDefault();
          return;
        }
  
        // get the current focused item
        var focusedItem = document.activeElement;
  
        var totalNodes = focusableNodes.length;
        var focusedItemIndex = focusableNodes.indexOf(focusedItem);
  
        if (event.shiftKey && focusedItemIndex === 0) {
          focusableNodes[totalNodes - 1].focus();
          event.preventDefault();
        }
  
        if (!event.shiftKey && focusedItemIndex === totalNodes - 1) {
          focusableNodes[0].focus();
          event.preventDefault();
        }
      };
  
      return Modal;
    })();
  
    var modal = null;
  
    var MicroModal = {
      init: function init(config) {
        // We need to make sure there's a modal on the page before continuing
        var options = config || {};
        var triggers = document.querySelectorAll(
          "[" + (options.openTrigger || 'data-micromodal-trigger') + "]"
        );
        var triggerMap = Array.prototype.reduce.call(
          triggers,
          function (acc, trigger) {
            var targetModal = trigger.getAttribute(
              options.openTrigger || 'data-micromodal-trigger'
            );
            if (acc[targetModal] === undefined) acc[targetModal] = [];
            acc[targetModal].push(trigger);
            return acc;
          },
          {}
        );
  
        if (
          options.debugMode === true &&
          Object.keys(triggerMap).length === 0
        ) {
          console.warn(
            'MicroModal: ❗Please specify at least one modal trigger'
          );
        }
  
        for (var key in triggerMap) {
          var value = triggerMap[key];
          options.targetModal = key;
          options.triggers = [].concat(value);
          new MicroModal.modal(options);
        }
      },
  
      show: function show(targetModal, config) {
        config = config || {};
        config.targetModal = targetModal;
        if (!modal) modal = new MicroModal.modal(config);
        modal.showModal();
      },
  
      close: function close(targetModal) {
        modal.closeModal();
      },
  
      modal: MicroModal
    };
  
    MicroModal.modal = MicroModal;
  
    return MicroModal;
  });
  