You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

867 lines
25 KiB

  1. /*!
  2. * Bootstrap offcanvas.js v5.1.3 (https://getbootstrap.com/)
  3. * Copyright 2011-2021 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors)
  4. * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
  5. */
  6. (function (global, factory) {
  7. typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('./dom/selector-engine.js'), require('./dom/manipulator.js'), require('./dom/event-handler.js'), require('./base-component.js')) :
  8. typeof define === 'function' && define.amd ? define(['./dom/selector-engine', './dom/manipulator', './dom/event-handler', './base-component'], factory) :
  9. (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.Offcanvas = factory(global.SelectorEngine, global.Manipulator, global.EventHandler, global.Base));
  10. })(this, (function (SelectorEngine, Manipulator, EventHandler, BaseComponent) { 'use strict';
  11. const _interopDefaultLegacy = e => e && typeof e === 'object' && 'default' in e ? e : { default: e };
  12. const SelectorEngine__default = /*#__PURE__*/_interopDefaultLegacy(SelectorEngine);
  13. const Manipulator__default = /*#__PURE__*/_interopDefaultLegacy(Manipulator);
  14. const EventHandler__default = /*#__PURE__*/_interopDefaultLegacy(EventHandler);
  15. const BaseComponent__default = /*#__PURE__*/_interopDefaultLegacy(BaseComponent);
  16. /**
  17. * --------------------------------------------------------------------------
  18. * Bootstrap (v5.1.3): util/index.js
  19. * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
  20. * --------------------------------------------------------------------------
  21. */
  22. const MILLISECONDS_MULTIPLIER = 1000;
  23. const TRANSITION_END = 'transitionend'; // Shoutout AngusCroll (https://goo.gl/pxwQGp)
  24. const toType = obj => {
  25. if (obj === null || obj === undefined) {
  26. return `${obj}`;
  27. }
  28. return {}.toString.call(obj).match(/\s([a-z]+)/i)[1].toLowerCase();
  29. };
  30. const getSelector = element => {
  31. let selector = element.getAttribute('data-bs-target');
  32. if (!selector || selector === '#') {
  33. let hrefAttr = element.getAttribute('href'); // The only valid content that could double as a selector are IDs or classes,
  34. // so everything starting with `#` or `.`. If a "real" URL is used as the selector,
  35. // `document.querySelector` will rightfully complain it is invalid.
  36. // See https://github.com/twbs/bootstrap/issues/32273
  37. if (!hrefAttr || !hrefAttr.includes('#') && !hrefAttr.startsWith('.')) {
  38. return null;
  39. } // Just in case some CMS puts out a full URL with the anchor appended
  40. if (hrefAttr.includes('#') && !hrefAttr.startsWith('#')) {
  41. hrefAttr = `#${hrefAttr.split('#')[1]}`;
  42. }
  43. selector = hrefAttr && hrefAttr !== '#' ? hrefAttr.trim() : null;
  44. }
  45. return selector;
  46. };
  47. const getElementFromSelector = element => {
  48. const selector = getSelector(element);
  49. return selector ? document.querySelector(selector) : null;
  50. };
  51. const getTransitionDurationFromElement = element => {
  52. if (!element) {
  53. return 0;
  54. } // Get transition-duration of the element
  55. let {
  56. transitionDuration,
  57. transitionDelay
  58. } = window.getComputedStyle(element);
  59. const floatTransitionDuration = Number.parseFloat(transitionDuration);
  60. const floatTransitionDelay = Number.parseFloat(transitionDelay); // Return 0 if element or transition duration is not found
  61. if (!floatTransitionDuration && !floatTransitionDelay) {
  62. return 0;
  63. } // If multiple durations are defined, take the first
  64. transitionDuration = transitionDuration.split(',')[0];
  65. transitionDelay = transitionDelay.split(',')[0];
  66. return (Number.parseFloat(transitionDuration) + Number.parseFloat(transitionDelay)) * MILLISECONDS_MULTIPLIER;
  67. };
  68. const triggerTransitionEnd = element => {
  69. element.dispatchEvent(new Event(TRANSITION_END));
  70. };
  71. const isElement = obj => {
  72. if (!obj || typeof obj !== 'object') {
  73. return false;
  74. }
  75. if (typeof obj.jquery !== 'undefined') {
  76. obj = obj[0];
  77. }
  78. return typeof obj.nodeType !== 'undefined';
  79. };
  80. const getElement = obj => {
  81. if (isElement(obj)) {
  82. // it's a jQuery object or a node element
  83. return obj.jquery ? obj[0] : obj;
  84. }
  85. if (typeof obj === 'string' && obj.length > 0) {
  86. return document.querySelector(obj);
  87. }
  88. return null;
  89. };
  90. const typeCheckConfig = (componentName, config, configTypes) => {
  91. Object.keys(configTypes).forEach(property => {
  92. const expectedTypes = configTypes[property];
  93. const value = config[property];
  94. const valueType = value && isElement(value) ? 'element' : toType(value);
  95. if (!new RegExp(expectedTypes).test(valueType)) {
  96. throw new TypeError(`${componentName.toUpperCase()}: Option "${property}" provided type "${valueType}" but expected type "${expectedTypes}".`);
  97. }
  98. });
  99. };
  100. const isVisible = element => {
  101. if (!isElement(element) || element.getClientRects().length === 0) {
  102. return false;
  103. }
  104. return getComputedStyle(element).getPropertyValue('visibility') === 'visible';
  105. };
  106. const isDisabled = element => {
  107. if (!element || element.nodeType !== Node.ELEMENT_NODE) {
  108. return true;
  109. }
  110. if (element.classList.contains('disabled')) {
  111. return true;
  112. }
  113. if (typeof element.disabled !== 'undefined') {
  114. return element.disabled;
  115. }
  116. return element.hasAttribute('disabled') && element.getAttribute('disabled') !== 'false';
  117. };
  118. /**
  119. * Trick to restart an element's animation
  120. *
  121. * @param {HTMLElement} element
  122. * @return void
  123. *
  124. * @see https://www.charistheo.io/blog/2021/02/restart-a-css-animation-with-javascript/#restarting-a-css-animation
  125. */
  126. const reflow = element => {
  127. // eslint-disable-next-line no-unused-expressions
  128. element.offsetHeight;
  129. };
  130. const getjQuery = () => {
  131. const {
  132. jQuery
  133. } = window;
  134. if (jQuery && !document.body.hasAttribute('data-bs-no-jquery')) {
  135. return jQuery;
  136. }
  137. return null;
  138. };
  139. const DOMContentLoadedCallbacks = [];
  140. const onDOMContentLoaded = callback => {
  141. if (document.readyState === 'loading') {
  142. // add listener on the first call when the document is in loading state
  143. if (!DOMContentLoadedCallbacks.length) {
  144. document.addEventListener('DOMContentLoaded', () => {
  145. DOMContentLoadedCallbacks.forEach(callback => callback());
  146. });
  147. }
  148. DOMContentLoadedCallbacks.push(callback);
  149. } else {
  150. callback();
  151. }
  152. };
  153. const defineJQueryPlugin = plugin => {
  154. onDOMContentLoaded(() => {
  155. const $ = getjQuery();
  156. /* istanbul ignore if */
  157. if ($) {
  158. const name = plugin.NAME;
  159. const JQUERY_NO_CONFLICT = $.fn[name];
  160. $.fn[name] = plugin.jQueryInterface;
  161. $.fn[name].Constructor = plugin;
  162. $.fn[name].noConflict = () => {
  163. $.fn[name] = JQUERY_NO_CONFLICT;
  164. return plugin.jQueryInterface;
  165. };
  166. }
  167. });
  168. };
  169. const execute = callback => {
  170. if (typeof callback === 'function') {
  171. callback();
  172. }
  173. };
  174. const executeAfterTransition = (callback, transitionElement, waitForTransition = true) => {
  175. if (!waitForTransition) {
  176. execute(callback);
  177. return;
  178. }
  179. const durationPadding = 5;
  180. const emulatedDuration = getTransitionDurationFromElement(transitionElement) + durationPadding;
  181. let called = false;
  182. const handler = ({
  183. target
  184. }) => {
  185. if (target !== transitionElement) {
  186. return;
  187. }
  188. called = true;
  189. transitionElement.removeEventListener(TRANSITION_END, handler);
  190. execute(callback);
  191. };
  192. transitionElement.addEventListener(TRANSITION_END, handler);
  193. setTimeout(() => {
  194. if (!called) {
  195. triggerTransitionEnd(transitionElement);
  196. }
  197. }, emulatedDuration);
  198. };
  199. /**
  200. * --------------------------------------------------------------------------
  201. * Bootstrap (v5.1.3): util/scrollBar.js
  202. * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
  203. * --------------------------------------------------------------------------
  204. */
  205. const SELECTOR_FIXED_CONTENT = '.fixed-top, .fixed-bottom, .is-fixed, .sticky-top';
  206. const SELECTOR_STICKY_CONTENT = '.sticky-top';
  207. class ScrollBarHelper {
  208. constructor() {
  209. this._element = document.body;
  210. }
  211. getWidth() {
  212. // https://developer.mozilla.org/en-US/docs/Web/API/Window/innerWidth#usage_notes
  213. const documentWidth = document.documentElement.clientWidth;
  214. return Math.abs(window.innerWidth - documentWidth);
  215. }
  216. hide() {
  217. const width = this.getWidth();
  218. this._disableOverFlow(); // give padding to element to balance the hidden scrollbar width
  219. this._setElementAttributes(this._element, 'paddingRight', calculatedValue => calculatedValue + width); // trick: We adjust positive paddingRight and negative marginRight to sticky-top elements to keep showing fullwidth
  220. this._setElementAttributes(SELECTOR_FIXED_CONTENT, 'paddingRight', calculatedValue => calculatedValue + width);
  221. this._setElementAttributes(SELECTOR_STICKY_CONTENT, 'marginRight', calculatedValue => calculatedValue - width);
  222. }
  223. _disableOverFlow() {
  224. this._saveInitialAttribute(this._element, 'overflow');
  225. this._element.style.overflow = 'hidden';
  226. }
  227. _setElementAttributes(selector, styleProp, callback) {
  228. const scrollbarWidth = this.getWidth();
  229. const manipulationCallBack = element => {
  230. if (element !== this._element && window.innerWidth > element.clientWidth + scrollbarWidth) {
  231. return;
  232. }
  233. this._saveInitialAttribute(element, styleProp);
  234. const calculatedValue = window.getComputedStyle(element)[styleProp];
  235. element.style[styleProp] = `${callback(Number.parseFloat(calculatedValue))}px`;
  236. };
  237. this._applyManipulationCallback(selector, manipulationCallBack);
  238. }
  239. reset() {
  240. this._resetElementAttributes(this._element, 'overflow');
  241. this._resetElementAttributes(this._element, 'paddingRight');
  242. this._resetElementAttributes(SELECTOR_FIXED_CONTENT, 'paddingRight');
  243. this._resetElementAttributes(SELECTOR_STICKY_CONTENT, 'marginRight');
  244. }
  245. _saveInitialAttribute(element, styleProp) {
  246. const actualValue = element.style[styleProp];
  247. if (actualValue) {
  248. Manipulator__default.default.setDataAttribute(element, styleProp, actualValue);
  249. }
  250. }
  251. _resetElementAttributes(selector, styleProp) {
  252. const manipulationCallBack = element => {
  253. const value = Manipulator__default.default.getDataAttribute(element, styleProp);
  254. if (typeof value === 'undefined') {
  255. element.style.removeProperty(styleProp);
  256. } else {
  257. Manipulator__default.default.removeDataAttribute(element, styleProp);
  258. element.style[styleProp] = value;
  259. }
  260. };
  261. this._applyManipulationCallback(selector, manipulationCallBack);
  262. }
  263. _applyManipulationCallback(selector, callBack) {
  264. if (isElement(selector)) {
  265. callBack(selector);
  266. } else {
  267. SelectorEngine__default.default.find(selector, this._element).forEach(callBack);
  268. }
  269. }
  270. isOverflowing() {
  271. return this.getWidth() > 0;
  272. }
  273. }
  274. /**
  275. * --------------------------------------------------------------------------
  276. * Bootstrap (v5.1.3): util/backdrop.js
  277. * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
  278. * --------------------------------------------------------------------------
  279. */
  280. const Default$2 = {
  281. className: 'modal-backdrop',
  282. isVisible: true,
  283. // if false, we use the backdrop helper without adding any element to the dom
  284. isAnimated: false,
  285. rootElement: 'body',
  286. // give the choice to place backdrop under different elements
  287. clickCallback: null
  288. };
  289. const DefaultType$2 = {
  290. className: 'string',
  291. isVisible: 'boolean',
  292. isAnimated: 'boolean',
  293. rootElement: '(element|string)',
  294. clickCallback: '(function|null)'
  295. };
  296. const NAME$2 = 'backdrop';
  297. const CLASS_NAME_FADE = 'fade';
  298. const CLASS_NAME_SHOW$1 = 'show';
  299. const EVENT_MOUSEDOWN = `mousedown.bs.${NAME$2}`;
  300. class Backdrop {
  301. constructor(config) {
  302. this._config = this._getConfig(config);
  303. this._isAppended = false;
  304. this._element = null;
  305. }
  306. show(callback) {
  307. if (!this._config.isVisible) {
  308. execute(callback);
  309. return;
  310. }
  311. this._append();
  312. if (this._config.isAnimated) {
  313. reflow(this._getElement());
  314. }
  315. this._getElement().classList.add(CLASS_NAME_SHOW$1);
  316. this._emulateAnimation(() => {
  317. execute(callback);
  318. });
  319. }
  320. hide(callback) {
  321. if (!this._config.isVisible) {
  322. execute(callback);
  323. return;
  324. }
  325. this._getElement().classList.remove(CLASS_NAME_SHOW$1);
  326. this._emulateAnimation(() => {
  327. this.dispose();
  328. execute(callback);
  329. });
  330. } // Private
  331. _getElement() {
  332. if (!this._element) {
  333. const backdrop = document.createElement('div');
  334. backdrop.className = this._config.className;
  335. if (this._config.isAnimated) {
  336. backdrop.classList.add(CLASS_NAME_FADE);
  337. }
  338. this._element = backdrop;
  339. }
  340. return this._element;
  341. }
  342. _getConfig(config) {
  343. config = { ...Default$2,
  344. ...(typeof config === 'object' ? config : {})
  345. }; // use getElement() with the default "body" to get a fresh Element on each instantiation
  346. config.rootElement = getElement(config.rootElement);
  347. typeCheckConfig(NAME$2, config, DefaultType$2);
  348. return config;
  349. }
  350. _append() {
  351. if (this._isAppended) {
  352. return;
  353. }
  354. this._config.rootElement.append(this._getElement());
  355. EventHandler__default.default.on(this._getElement(), EVENT_MOUSEDOWN, () => {
  356. execute(this._config.clickCallback);
  357. });
  358. this._isAppended = true;
  359. }
  360. dispose() {
  361. if (!this._isAppended) {
  362. return;
  363. }
  364. EventHandler__default.default.off(this._element, EVENT_MOUSEDOWN);
  365. this._element.remove();
  366. this._isAppended = false;
  367. }
  368. _emulateAnimation(callback) {
  369. executeAfterTransition(callback, this._getElement(), this._config.isAnimated);
  370. }
  371. }
  372. /**
  373. * --------------------------------------------------------------------------
  374. * Bootstrap (v5.1.3): util/focustrap.js
  375. * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
  376. * --------------------------------------------------------------------------
  377. */
  378. const Default$1 = {
  379. trapElement: null,
  380. // The element to trap focus inside of
  381. autofocus: true
  382. };
  383. const DefaultType$1 = {
  384. trapElement: 'element',
  385. autofocus: 'boolean'
  386. };
  387. const NAME$1 = 'focustrap';
  388. const DATA_KEY$1 = 'bs.focustrap';
  389. const EVENT_KEY$1 = `.${DATA_KEY$1}`;
  390. const EVENT_FOCUSIN = `focusin${EVENT_KEY$1}`;
  391. const EVENT_KEYDOWN_TAB = `keydown.tab${EVENT_KEY$1}`;
  392. const TAB_KEY = 'Tab';
  393. const TAB_NAV_FORWARD = 'forward';
  394. const TAB_NAV_BACKWARD = 'backward';
  395. class FocusTrap {
  396. constructor(config) {
  397. this._config = this._getConfig(config);
  398. this._isActive = false;
  399. this._lastTabNavDirection = null;
  400. }
  401. activate() {
  402. const {
  403. trapElement,
  404. autofocus
  405. } = this._config;
  406. if (this._isActive) {
  407. return;
  408. }
  409. if (autofocus) {
  410. trapElement.focus();
  411. }
  412. EventHandler__default.default.off(document, EVENT_KEY$1); // guard against infinite focus loop
  413. EventHandler__default.default.on(document, EVENT_FOCUSIN, event => this._handleFocusin(event));
  414. EventHandler__default.default.on(document, EVENT_KEYDOWN_TAB, event => this._handleKeydown(event));
  415. this._isActive = true;
  416. }
  417. deactivate() {
  418. if (!this._isActive) {
  419. return;
  420. }
  421. this._isActive = false;
  422. EventHandler__default.default.off(document, EVENT_KEY$1);
  423. } // Private
  424. _handleFocusin(event) {
  425. const {
  426. target
  427. } = event;
  428. const {
  429. trapElement
  430. } = this._config;
  431. if (target === document || target === trapElement || trapElement.contains(target)) {
  432. return;
  433. }
  434. const elements = SelectorEngine__default.default.focusableChildren(trapElement);
  435. if (elements.length === 0) {
  436. trapElement.focus();
  437. } else if (this._lastTabNavDirection === TAB_NAV_BACKWARD) {
  438. elements[elements.length - 1].focus();
  439. } else {
  440. elements[0].focus();
  441. }
  442. }
  443. _handleKeydown(event) {
  444. if (event.key !== TAB_KEY) {
  445. return;
  446. }
  447. this._lastTabNavDirection = event.shiftKey ? TAB_NAV_BACKWARD : TAB_NAV_FORWARD;
  448. }
  449. _getConfig(config) {
  450. config = { ...Default$1,
  451. ...(typeof config === 'object' ? config : {})
  452. };
  453. typeCheckConfig(NAME$1, config, DefaultType$1);
  454. return config;
  455. }
  456. }
  457. /**
  458. * --------------------------------------------------------------------------
  459. * Bootstrap (v5.1.3): util/component-functions.js
  460. * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
  461. * --------------------------------------------------------------------------
  462. */
  463. const enableDismissTrigger = (component, method = 'hide') => {
  464. const clickEvent = `click.dismiss${component.EVENT_KEY}`;
  465. const name = component.NAME;
  466. EventHandler__default.default.on(document, clickEvent, `[data-bs-dismiss="${name}"]`, function (event) {
  467. if (['A', 'AREA'].includes(this.tagName)) {
  468. event.preventDefault();
  469. }
  470. if (isDisabled(this)) {
  471. return;
  472. }
  473. const target = getElementFromSelector(this) || this.closest(`.${name}`);
  474. const instance = component.getOrCreateInstance(target); // Method argument is left, for Alert and only, as it doesn't implement the 'hide' method
  475. instance[method]();
  476. });
  477. };
  478. /**
  479. * --------------------------------------------------------------------------
  480. * Bootstrap (v5.1.3): offcanvas.js
  481. * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
  482. * --------------------------------------------------------------------------
  483. */
  484. /**
  485. * ------------------------------------------------------------------------
  486. * Constants
  487. * ------------------------------------------------------------------------
  488. */
  489. const NAME = 'offcanvas';
  490. const DATA_KEY = 'bs.offcanvas';
  491. const EVENT_KEY = `.${DATA_KEY}`;
  492. const DATA_API_KEY = '.data-api';
  493. const EVENT_LOAD_DATA_API = `load${EVENT_KEY}${DATA_API_KEY}`;
  494. const ESCAPE_KEY = 'Escape';
  495. const Default = {
  496. backdrop: true,
  497. keyboard: true,
  498. scroll: false
  499. };
  500. const DefaultType = {
  501. backdrop: 'boolean',
  502. keyboard: 'boolean',
  503. scroll: 'boolean'
  504. };
  505. const CLASS_NAME_SHOW = 'show';
  506. const CLASS_NAME_BACKDROP = 'offcanvas-backdrop';
  507. const OPEN_SELECTOR = '.offcanvas.show';
  508. const EVENT_SHOW = `show${EVENT_KEY}`;
  509. const EVENT_SHOWN = `shown${EVENT_KEY}`;
  510. const EVENT_HIDE = `hide${EVENT_KEY}`;
  511. const EVENT_HIDDEN = `hidden${EVENT_KEY}`;
  512. const EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}`;
  513. const EVENT_KEYDOWN_DISMISS = `keydown.dismiss${EVENT_KEY}`;
  514. const SELECTOR_DATA_TOGGLE = '[data-bs-toggle="offcanvas"]';
  515. /**
  516. * ------------------------------------------------------------------------
  517. * Class Definition
  518. * ------------------------------------------------------------------------
  519. */
  520. class Offcanvas extends BaseComponent__default.default {
  521. constructor(element, config) {
  522. super(element);
  523. this._config = this._getConfig(config);
  524. this._isShown = false;
  525. this._backdrop = this._initializeBackDrop();
  526. this._focustrap = this._initializeFocusTrap();
  527. this._addEventListeners();
  528. } // Getters
  529. static get NAME() {
  530. return NAME;
  531. }
  532. static get Default() {
  533. return Default;
  534. } // Public
  535. toggle(relatedTarget) {
  536. return this._isShown ? this.hide() : this.show(relatedTarget);
  537. }
  538. show(relatedTarget) {
  539. if (this._isShown) {
  540. return;
  541. }
  542. const showEvent = EventHandler__default.default.trigger(this._element, EVENT_SHOW, {
  543. relatedTarget
  544. });
  545. if (showEvent.defaultPrevented) {
  546. return;
  547. }
  548. this._isShown = true;
  549. this._element.style.visibility = 'visible';
  550. this._backdrop.show();
  551. if (!this._config.scroll) {
  552. new ScrollBarHelper().hide();
  553. }
  554. this._element.removeAttribute('aria-hidden');
  555. this._element.setAttribute('aria-modal', true);
  556. this._element.setAttribute('role', 'dialog');
  557. this._element.classList.add(CLASS_NAME_SHOW);
  558. const completeCallBack = () => {
  559. if (!this._config.scroll) {
  560. this._focustrap.activate();
  561. }
  562. EventHandler__default.default.trigger(this._element, EVENT_SHOWN, {
  563. relatedTarget
  564. });
  565. };
  566. this._queueCallback(completeCallBack, this._element, true);
  567. }
  568. hide() {
  569. if (!this._isShown) {
  570. return;
  571. }
  572. const hideEvent = EventHandler__default.default.trigger(this._element, EVENT_HIDE);
  573. if (hideEvent.defaultPrevented) {
  574. return;
  575. }
  576. this._focustrap.deactivate();
  577. this._element.blur();
  578. this._isShown = false;
  579. this._element.classList.remove(CLASS_NAME_SHOW);
  580. this._backdrop.hide();
  581. const completeCallback = () => {
  582. this._element.setAttribute('aria-hidden', true);
  583. this._element.removeAttribute('aria-modal');
  584. this._element.removeAttribute('role');
  585. this._element.style.visibility = 'hidden';
  586. if (!this._config.scroll) {
  587. new ScrollBarHelper().reset();
  588. }
  589. EventHandler__default.default.trigger(this._element, EVENT_HIDDEN);
  590. };
  591. this._queueCallback(completeCallback, this._element, true);
  592. }
  593. dispose() {
  594. this._backdrop.dispose();
  595. this._focustrap.deactivate();
  596. super.dispose();
  597. } // Private
  598. _getConfig(config) {
  599. config = { ...Default,
  600. ...Manipulator__default.default.getDataAttributes(this._element),
  601. ...(typeof config === 'object' ? config : {})
  602. };
  603. typeCheckConfig(NAME, config, DefaultType);
  604. return config;
  605. }
  606. _initializeBackDrop() {
  607. return new Backdrop({
  608. className: CLASS_NAME_BACKDROP,
  609. isVisible: this._config.backdrop,
  610. isAnimated: true,
  611. rootElement: this._element.parentNode,
  612. clickCallback: () => this.hide()
  613. });
  614. }
  615. _initializeFocusTrap() {
  616. return new FocusTrap({
  617. trapElement: this._element
  618. });
  619. }
  620. _addEventListeners() {
  621. EventHandler__default.default.on(this._element, EVENT_KEYDOWN_DISMISS, event => {
  622. if (this._config.keyboard && event.key === ESCAPE_KEY) {
  623. this.hide();
  624. }
  625. });
  626. } // Static
  627. static jQueryInterface(config) {
  628. return this.each(function () {
  629. const data = Offcanvas.getOrCreateInstance(this, config);
  630. if (typeof config !== 'string') {
  631. return;
  632. }
  633. if (data[config] === undefined || config.startsWith('_') || config === 'constructor') {
  634. throw new TypeError(`No method named "${config}"`);
  635. }
  636. data[config](this);
  637. });
  638. }
  639. }
  640. /**
  641. * ------------------------------------------------------------------------
  642. * Data Api implementation
  643. * ------------------------------------------------------------------------
  644. */
  645. EventHandler__default.default.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (event) {
  646. const target = getElementFromSelector(this);
  647. if (['A', 'AREA'].includes(this.tagName)) {
  648. event.preventDefault();
  649. }
  650. if (isDisabled(this)) {
  651. return;
  652. }
  653. EventHandler__default.default.one(target, EVENT_HIDDEN, () => {
  654. // focus on trigger when it is closed
  655. if (isVisible(this)) {
  656. this.focus();
  657. }
  658. }); // avoid conflict when clicking a toggler of an offcanvas, while another is open
  659. const allReadyOpen = SelectorEngine__default.default.findOne(OPEN_SELECTOR);
  660. if (allReadyOpen && allReadyOpen !== target) {
  661. Offcanvas.getInstance(allReadyOpen).hide();
  662. }
  663. const data = Offcanvas.getOrCreateInstance(target);
  664. data.toggle(this);
  665. });
  666. EventHandler__default.default.on(window, EVENT_LOAD_DATA_API, () => SelectorEngine__default.default.find(OPEN_SELECTOR).forEach(el => Offcanvas.getOrCreateInstance(el).show()));
  667. enableDismissTrigger(Offcanvas);
  668. /**
  669. * ------------------------------------------------------------------------
  670. * jQuery
  671. * ------------------------------------------------------------------------
  672. */
  673. defineJQueryPlugin(Offcanvas);
  674. return Offcanvas;
  675. }));
  676. //# sourceMappingURL=offcanvas.js.map