/*! * Bootstrap tooltip.js v5.2.0-beta1 (https://getbootstrap.com/) * Copyright 2011-2022 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('@popperjs/core'), require('./util/index'), require('./util/sanitizer'), require('./dom/event-handler'), require('./dom/manipulator'), require('./base-component'), require('./util/template-factory')) : typeof define === 'function' && define.amd ? define(['@popperjs/core', './util/index', './util/sanitizer', './dom/event-handler', './dom/manipulator', './base-component', './util/template-factory'], factory) : (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.Tooltip = factory(global["@popperjs/core"], global.Index, global.Sanitizer, global.EventHandler, global.Manipulator, global.BaseComponent, global.TemplateFactory)); })(this, (function (Popper, index, sanitizer, EventHandler, Manipulator, BaseComponent, TemplateFactory) { 'use strict'; const _interopDefaultLegacy = e => e && typeof e === 'object' && 'default' in e ? e : { default: e }; function _interopNamespace(e) { if (e && e.__esModule) return e; const n = Object.create(null, { [Symbol.toStringTag]: { value: 'Module' } }); if (e) { for (const k in e) { if (k !== 'default') { const d = Object.getOwnPropertyDescriptor(e, k); Object.defineProperty(n, k, d.get ? d : { enumerable: true, get: () => e[k] }); } } } n.default = e; return Object.freeze(n); } const Popper__namespace = /*#__PURE__*/_interopNamespace(Popper); const EventHandler__default = /*#__PURE__*/_interopDefaultLegacy(EventHandler); const Manipulator__default = /*#__PURE__*/_interopDefaultLegacy(Manipulator); const BaseComponent__default = /*#__PURE__*/_interopDefaultLegacy(BaseComponent); const TemplateFactory__default = /*#__PURE__*/_interopDefaultLegacy(TemplateFactory); /** * -------------------------------------------------------------------------- * Bootstrap (v5.2.0-beta1): tooltip.js * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) * -------------------------------------------------------------------------- */ /** * Constants */ const NAME = 'tooltip'; const DISALLOWED_ATTRIBUTES = new Set(['sanitize', 'allowList', 'sanitizeFn']); const CLASS_NAME_FADE = 'fade'; const CLASS_NAME_MODAL = 'modal'; const CLASS_NAME_SHOW = 'show'; const SELECTOR_TOOLTIP_INNER = '.tooltip-inner'; const SELECTOR_MODAL = `.${CLASS_NAME_MODAL}`; const EVENT_MODAL_HIDE = 'hide.bs.modal'; const TRIGGER_HOVER = 'hover'; const TRIGGER_FOCUS = 'focus'; const TRIGGER_CLICK = 'click'; const TRIGGER_MANUAL = 'manual'; const EVENT_HIDE = 'hide'; const EVENT_HIDDEN = 'hidden'; const EVENT_SHOW = 'show'; const EVENT_SHOWN = 'shown'; const EVENT_INSERTED = 'inserted'; const EVENT_CLICK = 'click'; const EVENT_FOCUSIN = 'focusin'; const EVENT_FOCUSOUT = 'focusout'; const EVENT_MOUSEENTER = 'mouseenter'; const EVENT_MOUSELEAVE = 'mouseleave'; const AttachmentMap = { AUTO: 'auto', TOP: 'top', RIGHT: index.isRTL() ? 'left' : 'right', BOTTOM: 'bottom', LEFT: index.isRTL() ? 'right' : 'left' }; const Default = { animation: true, template: '', trigger: 'hover focus', title: '', delay: 0, html: false, selector: false, placement: 'top', offset: [0, 0], container: false, fallbackPlacements: ['top', 'right', 'bottom', 'left'], boundary: 'clippingParents', customClass: '', sanitize: true, sanitizeFn: null, allowList: sanitizer.DefaultAllowlist, popperConfig: null }; const DefaultType = { animation: 'boolean', template: 'string', title: '(string|element|function)', trigger: 'string', delay: '(number|object)', html: 'boolean', selector: '(string|boolean)', placement: '(string|function)', offset: '(array|string|function)', container: '(string|element|boolean)', fallbackPlacements: 'array', boundary: '(string|element)', customClass: '(string|function)', sanitize: 'boolean', sanitizeFn: '(null|function)', allowList: 'object', popperConfig: '(null|object|function)' }; /** * Class definition */ class Tooltip extends BaseComponent__default.default { constructor(element, config) { if (typeof Popper__namespace === 'undefined') { throw new TypeError('Bootstrap\'s tooltips require Popper (https://popper.js.org)'); } super(element, config); // Private this._isEnabled = true; this._timeout = 0; this._isHovered = false; this._activeTrigger = {}; this._popper = null; this._templateFactory = null; // Protected this.tip = null; this._setListeners(); } // Getters static get Default() { return Default; } static get DefaultType() { return DefaultType; } static get NAME() { return NAME; } // Public enable() { this._isEnabled = true; } disable() { this._isEnabled = false; } toggleEnabled() { this._isEnabled = !this._isEnabled; } toggle(event) { if (!this._isEnabled) { return; } if (event) { const context = this._initializeOnDelegatedTarget(event); context._activeTrigger.click = !context._activeTrigger.click; if (context._isWithActiveTrigger()) { context._enter(); } else { context._leave(); } return; } if (this._isShown()) { this._leave(); return; } this._enter(); } dispose() { clearTimeout(this._timeout); EventHandler__default.default.off(this._element.closest(SELECTOR_MODAL), EVENT_MODAL_HIDE, this._hideModalHandler); if (this.tip) { this.tip.remove(); } this._disposePopper(); super.dispose(); } show() { if (this._element.style.display === 'none') { throw new Error('Please use show on visible elements'); } if (!(this._isWithContent() && this._isEnabled)) { return; } const showEvent = EventHandler__default.default.trigger(this._element, this.constructor.eventName(EVENT_SHOW)); const shadowRoot = index.findShadowRoot(this._element); const isInTheDom = (shadowRoot || this._element.ownerDocument.documentElement).contains(this._element); if (showEvent.defaultPrevented || !isInTheDom) { return; } const tip = this._getTipElement(); this._element.setAttribute('aria-describedby', tip.getAttribute('id')); const { container } = this._config; if (!this._element.ownerDocument.documentElement.contains(this.tip)) { container.append(tip); EventHandler__default.default.trigger(this._element, this.constructor.eventName(EVENT_INSERTED)); } if (this._popper) { this._popper.update(); } else { this._createPopper(tip); } tip.classList.add(CLASS_NAME_SHOW); // If this is a touch-enabled device we add extra // empty mouseover listeners to the body's immediate children; // only needed because of broken event delegation on iOS // https://www.quirksmode.org/blog/archives/2014/02/mouse_event_bub.html if ('ontouchstart' in document.documentElement) { for (const element of [].concat(...document.body.children)) { EventHandler__default.default.on(element, 'mouseover', index.noop); } } const complete = () => { const previousHoverState = this._isHovered; this._isHovered = false; EventHandler__default.default.trigger(this._element, this.constructor.eventName(EVENT_SHOWN)); if (previousHoverState) { this._leave(); } }; this._queueCallback(complete, this.tip, this._isAnimated()); } hide() { if (!this._isShown()) { return; } const hideEvent = EventHandler__default.default.trigger(this._element, this.constructor.eventName(EVENT_HIDE)); if (hideEvent.defaultPrevented) { return; } const tip = this._getTipElement(); tip.classList.remove(CLASS_NAME_SHOW); // If this is a touch-enabled device we remove the extra // empty mouseover listeners we added for iOS support if ('ontouchstart' in document.documentElement) { for (const element of [].concat(...document.body.children)) { EventHandler__default.default.off(element, 'mouseover', index.noop); } } this._activeTrigger[TRIGGER_CLICK] = false; this._activeTrigger[TRIGGER_FOCUS] = false; this._activeTrigger[TRIGGER_HOVER] = false; this._isHovered = false; const complete = () => { if (this._isWithActiveTrigger()) { return; } if (!this._isHovered) { tip.remove(); } this._element.removeAttribute('aria-describedby'); EventHandler__default.default.trigger(this._element, this.constructor.eventName(EVENT_HIDDEN)); this._disposePopper(); }; this._queueCallback(complete, this.tip, this._isAnimated()); } update() { if (this._popper) { this._popper.update(); } } // Protected _isWithContent() { return Boolean(this._getTitle()); } _getTipElement() { if (!this.tip) { this.tip = this._createTipElement(this._getContentForTemplate()); } return this.tip; } _createTipElement(content) { const tip = this._getTemplateFactory(content).toHtml(); // todo: remove this check on v6 if (!tip) { return null; } tip.classList.remove(CLASS_NAME_FADE, CLASS_NAME_SHOW); // todo: on v6 the following can be achieved with CSS only tip.classList.add(`bs-${this.constructor.NAME}-auto`); const tipId = index.getUID(this.constructor.NAME).toString(); tip.setAttribute('id', tipId); if (this._isAnimated()) { tip.classList.add(CLASS_NAME_FADE); } return tip; } setContent(content) { let isShown = false; if (this.tip) { isShown = this._isShown(); this.tip.remove(); this.tip = null; } this._disposePopper(); this.tip = this._createTipElement(content); if (isShown) { this.show(); } } _getTemplateFactory(content) { if (this._templateFactory) { this._templateFactory.changeContent(content); } else { this._templateFactory = new TemplateFactory__default.default({ ...this._config, // the `content` var has to be after `this._config` // to override config.content in case of popover content, extraClass: this._resolvePossibleFunction(this._config.customClass) }); } return this._templateFactory; } _getContentForTemplate() { return { [SELECTOR_TOOLTIP_INNER]: this._getTitle() }; } _getTitle() { return this._config.title; } // Private _initializeOnDelegatedTarget(event) { return this.constructor.getOrCreateInstance(event.delegateTarget, this._getDelegateConfig()); } _isAnimated() { return this._config.animation || this.tip && this.tip.classList.contains(CLASS_NAME_FADE); } _isShown() { return this.tip && this.tip.classList.contains(CLASS_NAME_SHOW); } _createPopper(tip) { const placement = typeof this._config.placement === 'function' ? this._config.placement.call(this, tip, this._element) : this._config.placement; const attachment = AttachmentMap[placement.toUpperCase()]; this._popper = Popper__namespace.createPopper(this._element, tip, this._getPopperConfig(attachment)); } _getOffset() { const { offset } = this._config; if (typeof offset === 'string') { return offset.split(',').map(value => Number.parseInt(value, 10)); } if (typeof offset === 'function') { return popperData => offset(popperData, this._element); } return offset; } _resolvePossibleFunction(arg) { return typeof arg === 'function' ? arg.call(this._element) : arg; } _getPopperConfig(attachment) { const defaultBsPopperConfig = { placement: attachment, modifiers: [{ name: 'flip', options: { fallbackPlacements: this._config.fallbackPlacements } }, { name: 'offset', options: { offset: this._getOffset() } }, { name: 'preventOverflow', options: { boundary: this._config.boundary } }, { name: 'arrow', options: { element: `.${this.constructor.NAME}-arrow` } }, { name: 'preSetPlacement', enabled: true, phase: 'beforeMain', fn: data => { // Pre-set Popper's placement attribute in order to read the arrow sizes properly. // Otherwise, Popper mixes up the width and height dimensions since the initial arrow style is for top placement this._getTipElement().setAttribute('data-popper-placement', data.state.placement); } }] }; return { ...defaultBsPopperConfig, ...(typeof this._config.popperConfig === 'function' ? this._config.popperConfig(defaultBsPopperConfig) : this._config.popperConfig) }; } _setListeners() { const triggers = this._config.trigger.split(' '); for (const trigger of triggers) { if (trigger === 'click') { EventHandler__default.default.on(this._element, this.constructor.eventName(EVENT_CLICK), this._config.selector, event => this.toggle(event)); } else if (trigger !== TRIGGER_MANUAL) { const eventIn = trigger === TRIGGER_HOVER ? this.constructor.eventName(EVENT_MOUSEENTER) : this.constructor.eventName(EVENT_FOCUSIN); const eventOut = trigger === TRIGGER_HOVER ? this.constructor.eventName(EVENT_MOUSELEAVE) : this.constructor.eventName(EVENT_FOCUSOUT); EventHandler__default.default.on(this._element, eventIn, this._config.selector, event => { const context = this._initializeOnDelegatedTarget(event); context._activeTrigger[event.type === 'focusin' ? TRIGGER_FOCUS : TRIGGER_HOVER] = true; context._enter(); }); EventHandler__default.default.on(this._element, eventOut, this._config.selector, event => { const context = this._initializeOnDelegatedTarget(event); context._activeTrigger[event.type === 'focusout' ? TRIGGER_FOCUS : TRIGGER_HOVER] = context._element.contains(event.relatedTarget); context._leave(); }); } } this._hideModalHandler = () => { if (this._element) { this.hide(); } }; EventHandler__default.default.on(this._element.closest(SELECTOR_MODAL), EVENT_MODAL_HIDE, this._hideModalHandler); if (this._config.selector) { this._config = { ...this._config, trigger: 'manual', selector: '' }; } else { this._fixTitle(); } } _fixTitle() { const title = this._config.originalTitle; if (!title) { return; } if (!this._element.getAttribute('aria-label') && !this._element.textContent) { this._element.setAttribute('aria-label', title); } this._element.removeAttribute('title'); } _enter() { if (this._isShown() || this._isHovered) { this._isHovered = true; return; } this._isHovered = true; this._setTimeout(() => { if (this._isHovered) { this.show(); } }, this._config.delay.show); } _leave() { if (this._isWithActiveTrigger()) { return; } this._isHovered = false; this._setTimeout(() => { if (!this._isHovered) { this.hide(); } }, this._config.delay.hide); } _setTimeout(handler, timeout) { clearTimeout(this._timeout); this._timeout = setTimeout(handler, timeout); } _isWithActiveTrigger() { return Object.values(this._activeTrigger).includes(true); } _getConfig(config) { const dataAttributes = Manipulator__default.default.getDataAttributes(this._element); for (const dataAttribute of Object.keys(dataAttributes)) { if (DISALLOWED_ATTRIBUTES.has(dataAttribute)) { delete dataAttributes[dataAttribute]; } } config = { ...dataAttributes, ...(typeof config === 'object' && config ? config : {}) }; config = this._mergeConfigObj(config); config = this._configAfterMerge(config); this._typeCheckConfig(config); return config; } _configAfterMerge(config) { config.container = config.container === false ? document.body : index.getElement(config.container); if (typeof config.delay === 'number') { config.delay = { show: config.delay, hide: config.delay }; } config.originalTitle = this._element.getAttribute('title') || ''; config.title = this._resolvePossibleFunction(config.title) || config.originalTitle; if (typeof config.title === 'number') { config.title = config.title.toString(); } if (typeof config.content === 'number') { config.content = config.content.toString(); } return config; } _getDelegateConfig() { const config = {}; for (const key in this._config) { if (this.constructor.Default[key] !== this._config[key]) { config[key] = this._config[key]; } } // In the future can be replaced with: // const keysWithDifferentValues = Object.entries(this._config).filter(entry => this.constructor.Default[entry[0]] !== this._config[entry[0]]) // `Object.fromEntries(keysWithDifferentValues)` return config; } _disposePopper() { if (this._popper) { this._popper.destroy(); this._popper = null; } } // Static static jQueryInterface(config) { return this.each(function () { const data = Tooltip.getOrCreateInstance(this, config); if (typeof config !== 'string') { return; } if (typeof data[config] === 'undefined') { throw new TypeError(`No method named "${config}"`); } data[config](); }); } } /** * jQuery */ index.defineJQueryPlugin(Tooltip); return Tooltip; })); //# sourceMappingURL=tooltip.js.map