(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.3.2"; var classCallCheck = function (instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }; var createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); var toConsumableArray = function (arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) arr2[i] = arr[i]; return arr2; } else { return Array.from(arr); } }; var MicroModal = function () { var FOCUSABLE_ELEMENTS = ['a[href]', 'area[href]', 'input:not([disabled]):not([type="hidden"]):not([aria-hidden])', 'select:not([disabled]):not([aria-hidden])', 'textarea:not([disabled]):not([aria-hidden])', 'button:not([disabled]):not([aria-hidden])', 'iframe', 'object', 'embed', '[contenteditable]', '[tabindex]:not([tabindex^="-"])']; var Modal = function () { function Modal(_ref) { var targetModal = _ref.targetModal, _ref$triggers = _ref.triggers, triggers = _ref$triggers === undefined ? [] : _ref$triggers, _ref$onShow = _ref.onShow, onShow = _ref$onShow === undefined ? function () {} : _ref$onShow, _ref$onClose = _ref.onClose, onClose = _ref$onClose === undefined ? function () {} : _ref$onClose, _ref$openTrigger = _ref.openTrigger, openTrigger = _ref$openTrigger === undefined ? 'data-micromodal-trigger' : _ref$openTrigger, _ref$closeTrigger = _ref.closeTrigger, closeTrigger = _ref$closeTrigger === undefined ? 'data-micromodal-close' : _ref$closeTrigger, _ref$disableScroll = _ref.disableScroll, disableScroll = _ref$disableScroll === undefined ? false : _ref$disableScroll, _ref$disableFocus = _ref.disableFocus, disableFocus = _ref$disableFocus === undefined ? false : _ref$disableFocus, _ref$awaitCloseAnimat = _ref.awaitCloseAnimation, awaitCloseAnimation = _ref$awaitCloseAnimat === undefined ? false : _ref$awaitCloseAnimat, _ref$debugMode = _ref.debugMode, debugMode = _ref$debugMode === undefined ? false : _ref$debugMode; classCallCheck(this, Modal); // Save a reference of the modal this.modal = document.getElementById(targetModal); // Save a reference to the passed config this.config = { debugMode: debugMode, disableScroll: disableScroll, openTrigger: openTrigger, closeTrigger: closeTrigger, onShow: onShow, onClose: onClose, awaitCloseAnimation: awaitCloseAnimation, disableFocus: disableFocus // Register click events only if prebinding eventListeners };if (triggers.length > 0) this.registerTriggers.apply(this, toConsumableArray(triggers)); // prebind 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} */ createClass(Modal, [{ key: 'registerTriggers', value: function registerTriggers() { var _this = this; for (var _len = arguments.length, triggers = Array(_len), _key = 0; _key < _len; _key++) { triggers[_key] = arguments[_key]; } triggers.filter(Boolean).forEach(function (trigger) { trigger.addEventListener('click', function () { return _this.showModal(); }); }); } }, { key: 'showModal', value: function showModal() { this.activeElement = document.activeElement; this.modal.setAttribute('aria-hidden', 'false'); this.modal.classList.add('is-open'); this.setFocusToFirstNode(); this.scrollBehaviour('disable'); this.addEventListeners(); this.config.onShow(this.modal); } }, { key: 'closeModal', value: function closeModal() { var modal = this.modal; this.modal.setAttribute('aria-hidden', 'true'); this.removeEventListeners(); this.scrollBehaviour('enable'); if (this.activeElement) { this.activeElement.focus(); } this.config.onClose(this.modal); if (this.config.awaitCloseAnimation) { this.modal.addEventListener('animationend', function handler() { modal.classList.remove('is-open'); modal.removeEventListener('animationend', handler, false); }, false); } else { modal.classList.remove('is-open'); } } }, { key: 'closeModalById', value: function closeModalById(targetModal) { this.modal = document.getElementById(targetModal); if (this.modal) this.closeModal(); } }, { key: 'scrollBehaviour', value: function scrollBehaviour(toggle) { // if (!this.config.disableScroll) return; var body = document.querySelector('body'); var html = document.querySelector('html'); var device_ratio = window.devicePixelRatio || 1; var device_width = screen.width * device_ratio; console.log("Device Width is "); console.log(device_width); switch (toggle) { case 'enable': // Object.assign(body.style, { overflow: '', position: 'relative' }); Object.assign(html.style, { overflow: '', position: 'relative' }); if(device_width < 768) { //Object.assign(body.style, { position: 'fixed',top: '0', bottom:'0', left:'0', right:'0' }); } break; case 'disable': //Object.assign(body.style, { position: 'fixed', overflow: 'hidden' }); Object.assign(html.style, { position: 'fixed', overflow: 'hidden', width:'100%' }); if(device_width < 768) { //Object.assign(body.style, { position: 'relative'}); // Object.assign(body.style, { position: 'fixed',top: '0', bottom:'0', left:'0', right:'0' }); } break; default: } } }, { key: 'addEventListeners', value: function addEventListeners() { this.modal.addEventListener('touchstart', this.onClick); this.modal.addEventListener('click', this.onClick); document.addEventListener('keydown', this.onKeydown); } }, { key: 'removeEventListeners', value: function removeEventListeners() { this.modal.removeEventListener('touchstart', this.onClick); this.modal.removeEventListener('click', this.onClick); document.removeEventListener('keydown', this.onKeydown); } }, { key: 'onClick', value: function onClick(event) { if (event.target.hasAttribute(this.config.closeTrigger)) { this.closeModal(); event.preventDefault(); } } }, { key: 'onKeydown', value: function onKeydown(event) { if (event.keyCode === 27) this.closeModal(event); if (event.keyCode === 9) this.maintainFocus(event); } }, { key: 'getFocusableNodes', value: function getFocusableNodes() { var nodes = this.modal.querySelectorAll(FOCUSABLE_ELEMENTS); return Array.apply(undefined, toConsumableArray(nodes)); } }, { key: 'setFocusToFirstNode', value: function setFocusToFirstNode() { if (this.config.disableFocus) return; var focusableNodes = this.getFocusableNodes(); if (focusableNodes.length) focusableNodes[0].focus(); } }, { key: 'maintainFocus', value: function maintainFocus(event) { var focusableNodes = this.getFocusableNodes(); // if disableFocus is true if (!this.modal.contains(document.activeElement)) { focusableNodes[0].focus(); } else { var focusedItemIndex = focusableNodes.indexOf(document.activeElement); if (event.shiftKey && focusedItemIndex === 0) { focusableNodes[focusableNodes.length - 1].focus(); event.preventDefault(); } if (!event.shiftKey && focusedItemIndex === focusableNodes.length - 1) { focusableNodes[0].focus(); event.preventDefault(); } } } }]); return Modal; }(); /** * Modal prototype ends. * Here on code is reposible for detecting and * autobinding event handlers on modal triggers */ // Keep a reference to the opened modal var activeModal = null; /** * Generates an associative array of modals and it's * respective triggers * @param {array} triggers An array of all triggers * @param {string} triggerAttr The data-attribute which triggers the module * @return {array} */ var generateTriggerMap = function generateTriggerMap(triggers, triggerAttr) { var triggerMap = []; triggers.forEach(function (trigger) { var targetModal = trigger.attributes[triggerAttr].value; if (triggerMap[targetModal] === undefined) triggerMap[targetModal] = []; triggerMap[targetModal].push(trigger); }); return triggerMap; }; /** * Validates whether a modal of the given id exists * in the DOM * @param {number} id The id of the modal * @return {boolean} */ var validateModalPresence = function validateModalPresence(id) { if (!document.getElementById(id)) { console.warn('MicroModal v' + version + ': \u2757Seems like you have missed %c\'' + id + '\'', 'background-color: #f8f9fa;color: #50596c;font-weight: bold;', 'ID somewhere in your code. Refer example below to resolve it.'); console.warn('%cExample:', 'background-color: #f8f9fa;color: #50596c;font-weight: bold;', ''); return false; } }; /** * Validates if there are modal triggers present * in the DOM * @param {array} triggers An array of data-triggers * @return {boolean} */ var validateTriggerPresence = function validateTriggerPresence(triggers) { if (triggers.length <= 0) { console.warn('MicroModal v' + version + ': \u2757Please specify at least one %c\'micromodal-trigger\'', 'background-color: #f8f9fa;color: #50596c;font-weight: bold;', 'data attribute.'); console.warn('%cExample:', 'background-color: #f8f9fa;color: #50596c;font-weight: bold;', ''); return false; } }; /** * Checks if triggers and their corresponding modals * are present in the DOM * @param {array} triggers Array of DOM nodes which have data-triggers * @param {array} triggerMap Associative array of modals and thier triggers * @return {boolean} */ var validateArgs = function validateArgs(triggers, triggerMap) { validateTriggerPresence(triggers); if (!triggerMap) return true; for (var id in triggerMap) { validateModalPresence(id); }return true; }; /** * Binds click handlers to all modal triggers * @param {object} config [description] * @return void */ var init = function init(config) { // Create an config object with default openTrigger var options = Object.assign({}, { openTrigger: 'data-micromodal-trigger' }, config); // Collects all the nodes with the trigger var triggers = [].concat(toConsumableArray(document.querySelectorAll('[' + options.openTrigger + ']'))); // Makes a mappings of modals with their trigger nodes var triggerMap = generateTriggerMap(triggers, options.openTrigger); // Checks if modals and triggers exist in dom if (options.debugMode === true && validateArgs(triggers, triggerMap) === false) return; // For every target modal creates a new instance for (var key in triggerMap) { var value = triggerMap[key]; options.targetModal = key; options.triggers = [].concat(toConsumableArray(value)); new Modal(options); // eslint-disable-line no-new } }; /** * Shows a particular modal * @param {string} targetModal [The id of the modal to display] * @param {object} config [The configuration object to pass] * @return {void} */ var show = function show(targetModal, config) { var options = config || {}; options.targetModal = targetModal; // Checks if modals and triggers exist in dom if (options.debugMode === true && validateModalPresence(targetModal) === false) return; // stores reference to active modal activeModal = new Modal(options); // eslint-disable-line no-new activeModal.showModal(); }; /** * Closes the active modal * @param {string} targetModal [The id of the modal to close] * @return {void} */ var close = function close(targetModal) { targetModal ? activeModal.closeModalById(targetModal) : activeModal.closeModal(); }; return { init: init, show: show, close: close }; }(); return MicroModal; })));