/*! * Bootstrap offcanvas.js v5.0.0-beta3 (https://getbootstrap.com/) * Copyright 2011-2021 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors) * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) */ (function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('./dom/selector-engine.js'), require('./dom/manipulator.js'), require('./dom/data.js'), require('./dom/event-handler.js'), require('./base-component.js')) : typeof define === 'function' && define.amd ? define(['./dom/selector-engine', './dom/manipulator', './dom/data', './dom/event-handler', './base-component'], factory) : (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.Offcanvas = factory(global.SelectorEngine, global.Manipulator, global.Data, global.EventHandler, global.Base)); }(this, (function (SelectorEngine, Manipulator, Data, EventHandler, BaseComponent) { 'use strict'; function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; } var SelectorEngine__default = /*#__PURE__*/_interopDefaultLegacy(SelectorEngine); var Manipulator__default = /*#__PURE__*/_interopDefaultLegacy(Manipulator); var Data__default = /*#__PURE__*/_interopDefaultLegacy(Data); var EventHandler__default = /*#__PURE__*/_interopDefaultLegacy(EventHandler); var BaseComponent__default = /*#__PURE__*/_interopDefaultLegacy(BaseComponent); /** * -------------------------------------------------------------------------- * Bootstrap (v5.0.0-beta3): util/index.js * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) * -------------------------------------------------------------------------- */ const MILLISECONDS_MULTIPLIER = 1000; const toType = obj => { if (obj === null || obj === undefined) { return `${obj}`; } return {}.toString.call(obj).match(/\s([a-z]+)/i)[1].toLowerCase(); }; const getSelector = element => { let selector = element.getAttribute('data-bs-target'); if (!selector || selector === '#') { let hrefAttr = element.getAttribute('href'); // The only valid content that could double as a selector are IDs or classes, // so everything starting with `#` or `.`. If a "real" URL is used as the selector, // `document.querySelector` will rightfully complain it is invalid. // See https://github.com/twbs/bootstrap/issues/32273 if (!hrefAttr || !hrefAttr.includes('#') && !hrefAttr.startsWith('.')) { return null; } // Just in case some CMS puts out a full URL with the anchor appended if (hrefAttr.includes('#') && !hrefAttr.startsWith('#')) { hrefAttr = '#' + hrefAttr.split('#')[1]; } selector = hrefAttr && hrefAttr !== '#' ? hrefAttr.trim() : null; } return selector; }; const getSelectorFromElement = element => { const selector = getSelector(element); if (selector) { return document.querySelector(selector) ? selector : null; } return null; }; const getElementFromSelector = element => { const selector = getSelector(element); return selector ? document.querySelector(selector) : null; }; const getTransitionDurationFromElement = element => { if (!element) { return 0; } // Get transition-duration of the element let { transitionDuration, transitionDelay } = window.getComputedStyle(element); const floatTransitionDuration = Number.parseFloat(transitionDuration); const floatTransitionDelay = Number.parseFloat(transitionDelay); // Return 0 if element or transition duration is not found if (!floatTransitionDuration && !floatTransitionDelay) { return 0; } // If multiple durations are defined, take the first transitionDuration = transitionDuration.split(',')[0]; transitionDelay = transitionDelay.split(',')[0]; return (Number.parseFloat(transitionDuration) + Number.parseFloat(transitionDelay)) * MILLISECONDS_MULTIPLIER; }; const isElement = obj => (obj[0] || obj).nodeType; const typeCheckConfig = (componentName, config, configTypes) => { Object.keys(configTypes).forEach(property => { const expectedTypes = configTypes[property]; const value = config[property]; const valueType = value && isElement(value) ? 'element' : toType(value); if (!new RegExp(expectedTypes).test(valueType)) { throw new TypeError(`${componentName.toUpperCase()}: ` + `Option "${property}" provided type "${valueType}" ` + `but expected type "${expectedTypes}".`); } }); }; const isVisible = element => { if (!element) { return false; } if (element.style && element.parentNode && element.parentNode.style) { const elementStyle = getComputedStyle(element); const parentNodeStyle = getComputedStyle(element.parentNode); return elementStyle.display !== 'none' && parentNodeStyle.display !== 'none' && elementStyle.visibility !== 'hidden'; } return false; }; const isDisabled = element => { if (!element || element.nodeType !== Node.ELEMENT_NODE) { return true; } if (element.classList.contains('disabled')) { return true; } if (typeof element.disabled !== 'undefined') { return element.disabled; } return element.hasAttribute('disabled') && element.getAttribute('disabled') !== 'false'; }; const getjQuery = () => { const { jQuery } = window; if (jQuery && !document.body.hasAttribute('data-bs-no-jquery')) { return jQuery; } return null; }; const onDOMContentLoaded = callback => { if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', callback); } else { callback(); } }; const defineJQueryPlugin = (name, plugin) => { onDOMContentLoaded(() => { const $ = getjQuery(); /* istanbul ignore if */ if ($) { const JQUERY_NO_CONFLICT = $.fn[name]; $.fn[name] = plugin.jQueryInterface; $.fn[name].Constructor = plugin; $.fn[name].noConflict = () => { $.fn[name] = JQUERY_NO_CONFLICT; return plugin.jQueryInterface; }; } }); }; /** * -------------------------------------------------------------------------- * Bootstrap (v5.0.0-beta3): util/scrollBar.js * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) * -------------------------------------------------------------------------- */ const SELECTOR_FIXED_CONTENT = '.fixed-top, .fixed-bottom, .is-fixed'; const SELECTOR_STICKY_CONTENT = '.sticky-top'; const getWidth = () => { // https://developer.mozilla.org/en-US/docs/Web/API/Window/innerWidth#usage_notes const documentWidth = document.documentElement.clientWidth; return Math.abs(window.innerWidth - documentWidth); }; const hide = (width = getWidth()) => { document.body.style.overflow = 'hidden'; _setElementAttributes(SELECTOR_FIXED_CONTENT, 'paddingRight', calculatedValue => calculatedValue + width); _setElementAttributes(SELECTOR_STICKY_CONTENT, 'marginRight', calculatedValue => calculatedValue - width); _setElementAttributes('body', 'paddingRight', calculatedValue => calculatedValue + width); }; const _setElementAttributes = (selector, styleProp, callback) => { const scrollbarWidth = getWidth(); SelectorEngine__default['default'].find(selector).forEach(element => { if (element !== document.body && window.innerWidth > element.clientWidth + scrollbarWidth) { return; } const actualValue = element.style[styleProp]; const calculatedValue = window.getComputedStyle(element)[styleProp]; Manipulator__default['default'].setDataAttribute(element, styleProp, actualValue); element.style[styleProp] = callback(Number.parseFloat(calculatedValue)) + 'px'; }); }; const reset = () => { document.body.style.overflow = 'auto'; _resetElementAttributes(SELECTOR_FIXED_CONTENT, 'paddingRight'); _resetElementAttributes(SELECTOR_STICKY_CONTENT, 'marginRight'); _resetElementAttributes('body', 'paddingRight'); }; const _resetElementAttributes = (selector, styleProp) => { SelectorEngine__default['default'].find(selector).forEach(element => { const value = Manipulator__default['default'].getDataAttribute(element, styleProp); if (typeof value === 'undefined' && element === document.body) { element.style.removeProperty(styleProp); } else { Manipulator__default['default'].removeDataAttribute(element, styleProp); element.style[styleProp] = value; } }); }; /** * -------------------------------------------------------------------------- * Bootstrap (v5.0.0-beta3): offcanvas.js * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) * -------------------------------------------------------------------------- */ /** * ------------------------------------------------------------------------ * Constants * ------------------------------------------------------------------------ */ const NAME = 'offcanvas'; const DATA_KEY = 'bs.offcanvas'; const EVENT_KEY = `.${DATA_KEY}`; const DATA_API_KEY = '.data-api'; const EVENT_LOAD_DATA_API = `load${EVENT_KEY}${DATA_API_KEY}`; const ESCAPE_KEY = 'Escape'; const Default = { backdrop: true, keyboard: true, scroll: false }; const DefaultType = { backdrop: 'boolean', keyboard: 'boolean', scroll: 'boolean' }; const CLASS_NAME_BACKDROP_BODY = 'offcanvas-backdrop'; const CLASS_NAME_SHOW = 'show'; const CLASS_NAME_TOGGLING = 'offcanvas-toggling'; const OPEN_SELECTOR = '.offcanvas.show'; const ACTIVE_SELECTOR = `${OPEN_SELECTOR}, .${CLASS_NAME_TOGGLING}`; const EVENT_SHOW = `show${EVENT_KEY}`; const EVENT_SHOWN = `shown${EVENT_KEY}`; const EVENT_HIDE = `hide${EVENT_KEY}`; const EVENT_HIDDEN = `hidden${EVENT_KEY}`; const EVENT_FOCUSIN = `focusin${EVENT_KEY}`; const EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}`; const EVENT_CLICK_DISMISS = `click.dismiss${EVENT_KEY}`; const SELECTOR_DATA_DISMISS = '[data-bs-dismiss="offcanvas"]'; const SELECTOR_DATA_TOGGLE = '[data-bs-toggle="offcanvas"]'; /** * ------------------------------------------------------------------------ * Class Definition * ------------------------------------------------------------------------ */ class Offcanvas extends BaseComponent__default['default'] { constructor(element, config) { super(element); this._config = this._getConfig(config); this._isShown = false; this._addEventListeners(); } // Getters static get Default() { return Default; } static get DATA_KEY() { return DATA_KEY; } // Public toggle(relatedTarget) { return this._isShown ? this.hide() : this.show(relatedTarget); } show(relatedTarget) { if (this._isShown) { return; } const showEvent = EventHandler__default['default'].trigger(this._element, EVENT_SHOW, { relatedTarget }); if (showEvent.defaultPrevented) { return; } this._isShown = true; this._element.style.visibility = 'visible'; if (this._config.backdrop) { document.body.classList.add(CLASS_NAME_BACKDROP_BODY); } if (!this._config.scroll) { hide(); } this._element.classList.add(CLASS_NAME_TOGGLING); this._element.removeAttribute('aria-hidden'); this._element.setAttribute('aria-modal', true); this._element.setAttribute('role', 'dialog'); this._element.classList.add(CLASS_NAME_SHOW); const completeCallBack = () => { this._element.classList.remove(CLASS_NAME_TOGGLING); EventHandler__default['default'].trigger(this._element, EVENT_SHOWN, { relatedTarget }); this._enforceFocusOnElement(this._element); }; setTimeout(completeCallBack, getTransitionDurationFromElement(this._element)); } hide() { if (!this._isShown) { return; } const hideEvent = EventHandler__default['default'].trigger(this._element, EVENT_HIDE); if (hideEvent.defaultPrevented) { return; } this._element.classList.add(CLASS_NAME_TOGGLING); EventHandler__default['default'].off(document, EVENT_FOCUSIN); this._element.blur(); this._isShown = false; this._element.classList.remove(CLASS_NAME_SHOW); const completeCallback = () => { this._element.setAttribute('aria-hidden', true); this._element.removeAttribute('aria-modal'); this._element.removeAttribute('role'); this._element.style.visibility = 'hidden'; if (this._config.backdrop) { document.body.classList.remove(CLASS_NAME_BACKDROP_BODY); } if (!this._config.scroll) { reset(); } EventHandler__default['default'].trigger(this._element, EVENT_HIDDEN); this._element.classList.remove(CLASS_NAME_TOGGLING); }; setTimeout(completeCallback, getTransitionDurationFromElement(this._element)); } // Private _getConfig(config) { config = { ...Default, ...Manipulator__default['default'].getDataAttributes(this._element), ...(typeof config === 'object' ? config : {}) }; typeCheckConfig(NAME, config, DefaultType); return config; } _enforceFocusOnElement(element) { EventHandler__default['default'].off(document, EVENT_FOCUSIN); // guard against infinite focus loop EventHandler__default['default'].on(document, EVENT_FOCUSIN, event => { if (document !== event.target && element !== event.target && !element.contains(event.target)) { element.focus(); } }); element.focus(); } _addEventListeners() { EventHandler__default['default'].on(this._element, EVENT_CLICK_DISMISS, SELECTOR_DATA_DISMISS, () => this.hide()); EventHandler__default['default'].on(document, 'keydown', event => { if (this._config.keyboard && event.key === ESCAPE_KEY) { this.hide(); } }); EventHandler__default['default'].on(document, EVENT_CLICK_DATA_API, event => { const target = SelectorEngine__default['default'].findOne(getSelectorFromElement(event.target)); if (!this._element.contains(event.target) && target !== this._element) { this.hide(); } }); } // Static static jQueryInterface(config) { return this.each(function () { const data = Data__default['default'].get(this, DATA_KEY) || new Offcanvas(this, typeof config === 'object' ? config : {}); if (typeof config !== 'string') { return; } if (data[config] === undefined || config.startsWith('_') || config === 'constructor') { throw new TypeError(`No method named "${config}"`); } data[config](this); }); } } /** * ------------------------------------------------------------------------ * Data Api implementation * ------------------------------------------------------------------------ */ EventHandler__default['default'].on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (event) { const target = getElementFromSelector(this); if (['A', 'AREA'].includes(this.tagName)) { event.preventDefault(); } if (isDisabled(this)) { return; } EventHandler__default['default'].one(target, EVENT_HIDDEN, () => { // focus on trigger when it is closed if (isVisible(this)) { this.focus(); } }); // avoid conflict when clicking a toggler of an offcanvas, while another is open const allReadyOpen = SelectorEngine__default['default'].findOne(ACTIVE_SELECTOR); if (allReadyOpen && allReadyOpen !== target) { return; } const data = Data__default['default'].get(target, DATA_KEY) || new Offcanvas(target); data.toggle(this); }); EventHandler__default['default'].on(window, EVENT_LOAD_DATA_API, () => { SelectorEngine__default['default'].find(OPEN_SELECTOR).forEach(el => (Data__default['default'].get(el, DATA_KEY) || new Offcanvas(el)).show()); }); /** * ------------------------------------------------------------------------ * jQuery * ------------------------------------------------------------------------ */ defineJQueryPlugin(NAME, Offcanvas); return Offcanvas; }))); //# sourceMappingURL=offcanvas.js.map