UNPKG

@ithaka/bonsai

Version:
185 lines (163 loc) 6.73 kB
"use strict"; import $ from "jquery"; import { Keyboard } from "foundation-sites/js/foundation.util.keyboard"; import { Reveal } from "foundation-sites/js/foundation.reveal"; import { BonsaiBase } from "./bonsai.base"; /** Reveal Module * @class * @name BonsaiModal * @param {jQuery} elements - jQuery object to use for initializing the modal component. * @param {Object} options - Optional parameters. * * @example * var elem = new BonsaiModal($(".reveal")); * * @returns Returns Bonsai.Modals object that has initialized each modal with the incoming `options` * */ class BonsaiModal extends BonsaiBase { constructor(elements, options = {}) { super(elements, options); Bonsai.Modals = Bonsai.hasOwnProperty("Modals") ? Bonsai.Modals : {members: {}, reflow: this.reflow}; this._initializeModals(); } /** * Iterates through every element passed into BonsaiModal and initializes it. Store the initlalized Reveal Modal with its elementID into window object Bonsai.Modals * @private */ _initializeModals() { this.elements.each((index, element) => { let $element = $(element), elementID = $element.attr("id"), theModal = new Reveal($element, this.options); this._registerModalEvents(theModal); this._addCircleDesign($element); if (elementID) { Bonsai.Modals.members[elementID] = theModal; // Store theModal with elementID after initialized } }); } _registerModalEvents(theModal) { theModal.$anchor.on("click", (event) => { theModal.$anchor = $(event.target); this._onAnchorClick(event, theModal); }); theModal.$element.find("a.close-button").on("click", (event) => { this._onCloseButtonClick(event); }); // gather and combine events for the modal div let modalEvents = this._getModalEvents(theModal), additionalModalEvents = this._getAdditionalModalEvents(theModal); modalEvents = Object.assign(modalEvents, additionalModalEvents); // register events onto the modal div theModal.$element.on(modalEvents); } /** * events that are meant to be registered against the modal div * @param elementID - the ID of the modal div * @param theModal - the Foundation Reveal object returned from new Reveal() * @returns an object of functions that triggers custom bonsai events * @private */ _getModalEvents(theModal) { return { /** Trigger this to customize the modal as it just started the open call and not visible * @event bonsai-modal-open */ "closeme.zf.reveal": () => { theModal.$element.trigger("bonsai-modal-open"); }, /** Trigger this to customize the modal as it has successfully opened and is visible * @event bonsai-modal-opened */ "open.zf.reveal": () => { theModal.$element.trigger("bonsai-modal-opened"); }, /** Trigger this to customize the modal as it just finished closing and is closed * @event bonsai-modal-closed */ "closed.zf.reveal": () => { theModal.$element.trigger("bonsai-modal-closed"); }, /** Trigger this to reflow the modal and register focusable elements after modal html content change * @event revealReflow */ "revealReflow" : function() { theModal.focusableElements = Keyboard.findFocusable(theModal.$element); Keyboard.trapFocus(theModal.$element); // update focusable elements and trap focus in modal }, // Modal keydown event for tabbing order tweak "keydown" : function(e) { if(Keyboard.parseKey(e) === "SHIFT_TAB") { // special case: fix "Cite this Item" shift+tab to copy buttons if (theModal.focusableElements.eq(3).is(":focus")) { theModal.focusableElements.eq(2).focus(); e.preventDefault(); e.stopImmediatePropagation(); // stop other events on the element and stop bubbling up the DOM tree } } } }; } /** * Register additional events to be put onto the modal * @param $element - the jQuery selected div that is the modal * @param elementID - the ID of the modal * @param theModal - the Foundation Reveal object returned from new Reveal() * @returns an object */ _getAdditionalModalEvents(theModal) { return {}; } /** * Adds a bonsai specific design to the modal if data-icon and optionally * data-circle-color are on the modal div * data-color-circle must be a color in the palette * data-color-icon must be an icon in bonsai * @param $element - the jQuery selected modal * @private */ _addCircleDesign($element) { const elementData = $element.data(); if (elementData.icon) { let circleClass = elementData.circleColor ? `circle ${elementData.circleColor}-background` : "circle"; $element.prepend( `<div class="modal-circle"> <div class="${circleClass}"><i class="icon-${elementData.icon}"></i></div> </div>` ); } } /** * Runs when the user clicks on the anchor that is meant to launch the modal * @param event - the click event * @param theModal - the Bonsai modal object, passed in to be used when subclassing * @private */ _onAnchorClick(event, theModal) { // to prevent browser from following href event.preventDefault(); } /** * Runs when the user clicks on the anchor that is meant to close the modal * @param event - the click event * @private */ _onCloseButtonClick(event) { // to prevent the browser from following href event.preventDefault(); } /** * Reflow method to re-bind jQuery element to a Modal object, and store it back to Bonsai.Modals * * @public */ reflow() { $.each(Bonsai.Modals.members, (elementID, theModal) => { theModal._destroy(); // detroy previous Modal element let theNewModal = new Reveal($(`#${elementID}`)); BonsaiModal.prototype._registerModalEvents(theNewModal); Bonsai.Modals.members[elementID] = theNewModal; }); } } export { BonsaiModal };