UNPKG

bootstrap-vue

Version:

BootstrapVue provides one of the most comprehensive implementations of Bootstrap 4 components and grid system for Vue.js and with extensive and automated WAI-ARIA accessibility markup.

1,109 lines (1,000 loc) 32.9 kB
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; 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; }; }(); function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } import Popper from 'popper.js'; import BvEvent from './bv-event.class'; import { assign } from './object'; import { from as arrayFrom } from './array'; import { closest, select, isVisible, isDisabled, getCS, addClass, removeClass, hasClass, setAttr, removeAttr, getAttr, eventOn, eventOff } from './dom'; var NAME = 'tooltip'; var CLASS_PREFIX = 'bs-tooltip'; var BSCLS_PREFIX_REGEX = new RegExp('\\b' + CLASS_PREFIX + '\\S+', 'g'); var TRANSITION_DURATION = 150; // Modal $root hidden event var MODAL_CLOSE_EVENT = 'bv::modal::hidden'; // Modal container for appending tip/popover var MODAL_CLASS = '.modal-content'; var AttachmentMap = { AUTO: 'auto', TOP: 'top', RIGHT: 'right', BOTTOM: 'bottom', LEFT: 'left', TOPLEFT: 'top', TOPRIGHT: 'top', RIGHTTOP: 'right', RIGHTBOTTOM: 'right', BOTTOMLEFT: 'bottom', BOTTOMRIGHT: 'bottom', LEFTTOP: 'left', LEFTBOTTOM: 'left' }; var OffsetMap = { AUTO: 0, TOPLEFT: -1, TOP: 0, TOPRIGHT: +1, RIGHTTOP: -1, RIGHT: 0, RIGHTBOTTOM: +1, BOTTOMLEFT: -1, BOTTOM: 0, BOTTOMRIGHT: +1, LEFTTOP: -1, LEFT: 0, LEFTBOTTOM: +1 }; var HoverState = { SHOW: 'show', OUT: 'out' }; var ClassName = { FADE: 'fade', SHOW: 'show' }; var Selector = { TOOLTIP: '.tooltip', TOOLTIP_INNER: '.tooltip-inner', ARROW: '.arrow' // ESLINT: Not used // const Trigger = { // HOVER: 'hover', // FOCUS: 'focus', // CLICK: 'click', // BLUR: 'blur', // MANUAL: 'manual' // } };var Defaults = { animation: true, template: '<div class="tooltip" role="tooltip">' + '<div class="arrow"></div>' + '<div class="tooltip-inner"></div>' + '</div>', trigger: 'hover focus', title: '', delay: 0, html: false, placement: 'top', offset: 0, arrowPadding: 6, container: false, fallbackPlacement: 'flip', callbacks: {}, boundary: 'scrollParent' // Transition Event names };var TransitionEndEvents = { WebkitTransition: ['webkitTransitionEnd'], MozTransition: ['transitionend'], OTransition: ['otransitionend', 'oTransitionEnd'], transition: ['transitionend'] // Client Side Tip ID counter for aria-describedby attribute // Could use Alex's uid generator util // Each tooltip requires a unique client side ID };var NEXTID = 1; /* istanbul ignore next */ function generateId(name) { return '__BV_' + name + '_' + NEXTID++ + '__'; } /* * ToolTip Class definition */ /* istanbul ignore next: difficult to test in Jest/JSDOM environment */ var ToolTip = function () { // Main constructor function ToolTip(element, config, $root) { _classCallCheck(this, ToolTip); // New tooltip object this.$isEnabled = true; this.$fadeTimeout = null; this.$hoverTimeout = null; this.$visibleInterval = null; this.$hoverState = ''; this.$activeTrigger = {}; this.$popper = null; this.$element = element; this.$tip = null; this.$id = generateId(this.constructor.NAME); this.$root = $root || null; this.$routeWatcher = null; // We use a bound version of the following handlers for root/modal listeners to maintain the 'this' context this.$forceHide = this.forceHide.bind(this); this.$doHide = this.doHide.bind(this); this.$doShow = this.doShow.bind(this); this.$doDisable = this.doDisable.bind(this); this.$doEnable = this.doEnable.bind(this); // Set the configuration this.updateConfig(config); } // NOTE: Overridden by PopOver class _createClass(ToolTip, [{ key: 'updateConfig', // Update config value: function updateConfig(config) { // Merge config into defaults. We use "this" here because PopOver overrides Default var updatedConfig = assign({}, this.constructor.Default, config); // Sanitize delay if (config.delay && typeof config.delay === 'number') { updatedConfig.delay = { show: config.delay, hide: config.delay }; } // Title for tooltip and popover if (config.title && typeof config.title === 'number') { updatedConfig.title = config.title.toString(); } // Content only for popover if (config.content && typeof config.content === 'number') { updatedConfig.content = config.content.toString(); } // Hide element original title if needed this.fixTitle(); // Update the config this.$config = updatedConfig; // Stop/Restart listening this.unListen(); this.listen(); } // Destroy this instance }, { key: 'destroy', value: function destroy() { // Stop listening to trigger events this.unListen(); // Disable while open listeners/watchers this.setWhileOpenListeners(false); // Clear any timouts clearTimeout(this.$hoverTimeout); this.$hoverTimeout = null; clearTimeout(this.$fadeTimeout); this.$fadeTimeout = null; // Remove popper if (this.$popper) { this.$popper.destroy(); } this.$popper = null; // Remove tip from document if (this.$tip && this.$tip.parentElement) { this.$tip.parentElement.removeChild(this.$tip); } this.$tip = null; // Null out other properties this.$id = null; this.$isEnabled = null; this.$root = null; this.$element = null; this.$config = null; this.$hoverState = null; this.$activeTrigger = null; this.$forceHide = null; this.$doHide = null; this.$doShow = null; this.$doDisable = null; this.$doEnable = null; } }, { key: 'enable', value: function enable() { // Create a non-cancelable BvEvent var enabledEvt = new BvEvent('enabled', { cancelable: false, target: this.$element, relatedTarget: null }); this.$isEnabled = true; this.emitEvent(enabledEvt); } }, { key: 'disable', value: function disable() { // Create a non-cancelable BvEvent var disabledEvt = new BvEvent('disabled', { cancelable: false, target: this.$element, relatedTarget: null }); this.$isEnabled = false; this.emitEvent(disabledEvt); } // Click toggler }, { key: 'toggle', value: function toggle(event) { if (!this.$isEnabled) { return; } if (event) { this.$activeTrigger.click = !this.$activeTrigger.click; if (this.isWithActiveTrigger()) { this.enter(null); } else { this.leave(null); } } else { if (hasClass(this.getTipElement(), ClassName.SHOW)) { this.leave(null); } else { this.enter(null); } } } // Show tooltip }, { key: 'show', value: function show() { var _this = this; if (!document.body.contains(this.$element) || !isVisible(this.$element)) { // If trigger element isn't in the DOM or is not visible return; } // Build tooltip element (also sets this.$tip) var tip = this.getTipElement(); this.fixTitle(); this.setContent(tip); if (!this.isWithContent(tip)) { // if No content, don't bother showing this.$tip = null; return; } // Set ID on tip and aria-describedby on element setAttr(tip, 'id', this.$id); this.addAriaDescribedby(); // Set animation on or off if (this.$config.animation) { addClass(tip, ClassName.FADE); } else { removeClass(tip, ClassName.FADE); } var placement = this.getPlacement(); var attachment = this.constructor.getAttachment(placement); this.addAttachmentClass(attachment); // Create a cancelable BvEvent var showEvt = new BvEvent('show', { cancelable: true, target: this.$element, relatedTarget: tip }); this.emitEvent(showEvt); if (showEvt.defaultPrevented) { // Don't show if event cancelled this.$tip = null; return; } // Insert tooltip if needed var container = this.getContainer(); if (!document.body.contains(tip)) { container.appendChild(tip); } // Refresh popper this.removePopper(); this.$popper = new Popper(this.$element, tip, this.getPopperConfig(placement, tip)); // Transitionend Callback var complete = function complete() { if (_this.$config.animation) { _this.fixTransition(tip); } var prevHoverState = _this.$hoverState; _this.$hoverState = null; if (prevHoverState === HoverState.OUT) { _this.leave(null); } // Create a non-cancelable BvEvent var shownEvt = new BvEvent('shown', { cancelable: false, target: _this.$element, relatedTarget: tip }); _this.emitEvent(shownEvt); }; // Enable while open listeners/watchers this.setWhileOpenListeners(true); // Show tip addClass(tip, ClassName.SHOW); // Start the transition/animation this.transitionOnce(tip, complete); } // handler for periodic visibility check }, { key: 'visibleCheck', value: function visibleCheck(on) { var _this2 = this; clearInterval(this.$visibleInterval); this.$visibleInterval = null; if (on) { this.$visibleInterval = setInterval(function () { var tip = _this2.getTipElement(); if (tip && !isVisible(_this2.$element) && hasClass(tip, ClassName.SHOW)) { // Element is no longer visible, so force-hide the tooltip _this2.forceHide(); } }, 100); } } }, { key: 'setWhileOpenListeners', value: function setWhileOpenListeners(on) { // Modal close events this.setModalListener(on); // Periodic $element visibility check // For handling when tip is in <keepalive>, tabs, carousel, etc this.visibleCheck(on); // Route change events this.setRouteWatcher(on); // Ontouch start listeners this.setOnTouchStartListener(on); if (on && /(focus|blur)/.test(this.$config.trigger)) { // If focus moves between trigger element and tip container, dont close eventOn(this.$tip, 'focusout', this); } else { eventOff(this.$tip, 'focusout', this); } } // force hide of tip (internal method) }, { key: 'forceHide', value: function forceHide() { if (!this.$tip || !hasClass(this.$tip, ClassName.SHOW)) { return; } // Disable while open listeners/watchers this.setWhileOpenListeners(false); // Clear any hover enter/leave event clearTimeout(this.$hoverTimeout); this.$hoverTimeout = null; this.$hoverState = ''; // Hide the tip this.hide(null, true); } // Hide tooltip }, { key: 'hide', value: function hide(callback, force) { var _this3 = this; var tip = this.$tip; if (!tip) { return; } // Create a canelable BvEvent var hideEvt = new BvEvent('hide', { // We disable cancelling if force is true cancelable: !force, target: this.$element, relatedTarget: tip }); this.emitEvent(hideEvt); if (hideEvt.defaultPrevented) { // Don't hide if event cancelled return; } // Transitionend Callback /* istanbul ignore next */ var complete = function complete() { if (_this3.$hoverState !== HoverState.SHOW && tip.parentNode) { // Remove tip from dom, and force recompile on next show tip.parentNode.removeChild(tip); _this3.removeAriaDescribedby(); _this3.removePopper(); _this3.$tip = null; } if (callback) { callback(); } // Create a non-cancelable BvEvent var hiddenEvt = new BvEvent('hidden', { cancelable: false, target: _this3.$element, relatedTarget: null }); _this3.emitEvent(hiddenEvt); }; // Disable while open listeners/watchers this.setWhileOpenListeners(false); // If forced close, disable animation if (force) { removeClass(tip, ClassName.FADE); } // Hide tip removeClass(tip, ClassName.SHOW); this.$activeTrigger.click = false; this.$activeTrigger.focus = false; this.$activeTrigger.hover = false; // Start the hide transition this.transitionOnce(tip, complete); this.$hoverState = ''; } }, { key: 'emitEvent', value: function emitEvent(evt) { var evtName = evt.type; if (this.$root && this.$root.$emit) { // Emit an event on $root this.$root.$emit('bv::' + this.constructor.NAME + '::' + evtName, evt); } var callbacks = this.$config.callbacks || {}; if (typeof callbacks[evtName] === 'function') { callbacks[evtName](evt); } } }, { key: 'getContainer', value: function getContainer() { var container = this.$config.container; var body = document.body; // If we are in a modal, we append to the modal instead of body, unless a container is specified return container === false ? closest(MODAL_CLASS, this.$element) || body : select(container, body) || body; } // Will be overritten by popover if needed }, { key: 'addAriaDescribedby', value: function addAriaDescribedby() { // Add aria-describedby on trigger element, without removing any other IDs var desc = getAttr(this.$element, 'aria-describedby') || ''; desc = desc.split(/\s+/).concat(this.$id).join(' ').trim(); setAttr(this.$element, 'aria-describedby', desc); } // Will be overritten by popover if needed }, { key: 'removeAriaDescribedby', value: function removeAriaDescribedby() { var _this4 = this; var desc = getAttr(this.$element, 'aria-describedby') || ''; desc = desc.split(/\s+/).filter(function (d) { return d !== _this4.$id; }).join(' ').trim(); if (desc) { setAttr(this.$element, 'aria-describedby', desc); } else { removeAttr(this.$element, 'aria-describedby'); } } }, { key: 'removePopper', value: function removePopper() { if (this.$popper) { this.$popper.destroy(); } this.$popper = null; } /* istanbul ignore next */ }, { key: 'transitionOnce', value: function transitionOnce(tip, complete) { var _this5 = this; var transEvents = this.getTransitionEndEvents(); var called = false; clearTimeout(this.$fadeTimeout); this.$fadeTimeout = null; var fnOnce = function fnOnce() { if (called) { return; } called = true; clearTimeout(_this5.$fadeTimeout); _this5.$fadeTimeout = null; transEvents.forEach(function (evtName) { eventOff(tip, evtName, fnOnce); }); // Call complete callback complete(); }; if (hasClass(tip, ClassName.FADE)) { transEvents.forEach(function (evtName) { eventOn(tip, evtName, fnOnce); }); // Fallback to setTimeout this.$fadeTimeout = setTimeout(fnOnce, TRANSITION_DURATION); } else { fnOnce(); } } // What transitionend event(s) to use? (returns array of event names) }, { key: 'getTransitionEndEvents', value: function getTransitionEndEvents() { for (var name in TransitionEndEvents) { if (this.$element.style[name] !== undefined) { return TransitionEndEvents[name]; } } // fallback return []; } }, { key: 'update', value: function update() { if (this.$popper !== null) { this.$popper.scheduleUpdate(); } } // NOTE: Overridden by PopOver class }, { key: 'isWithContent', value: function isWithContent(tip) { tip = tip || this.$tip; if (!tip) { return false; } return Boolean((select(Selector.TOOLTIP_INNER, tip) || {}).innerHTML); } // NOTE: Overridden by PopOver class }, { key: 'addAttachmentClass', value: function addAttachmentClass(attachment) { addClass(this.getTipElement(), CLASS_PREFIX + '-' + attachment); } }, { key: 'getTipElement', value: function getTipElement() { if (!this.$tip) { // Try and compile user supplied template, or fallback to default template this.$tip = this.compileTemplate(this.$config.template) || this.compileTemplate(this.constructor.Default.template); } // Add tab index so tip can be focused, and to allow it to be set as relatedTargt in focusin/out events this.$tip.tabIndex = -1; return this.$tip; } }, { key: 'compileTemplate', value: function compileTemplate(html) { if (!html || typeof html !== 'string') { return null; } var div = document.createElement('div'); div.innerHTML = html.trim(); var node = div.firstElementChild ? div.removeChild(div.firstElementChild) : null; div = null; return node; } // NOTE: Overridden by PopOver class }, { key: 'setContent', value: function setContent(tip) { this.setElementContent(select(Selector.TOOLTIP_INNER, tip), this.getTitle()); removeClass(tip, ClassName.FADE); removeClass(tip, ClassName.SHOW); } }, { key: 'setElementContent', value: function setElementContent(container, content) { if (!container) { // If container element doesn't exist, just return return; } var allowHtml = this.$config.html; if ((typeof content === 'undefined' ? 'undefined' : _typeof(content)) === 'object' && content.nodeType) { // content is a DOM node if (allowHtml) { if (content.parentElement !== container) { container.innerHtml = ''; container.appendChild(content); } } else { container.innerText = content.innerText; } } else { // We have a plain HTML string or Text container[allowHtml ? 'innerHTML' : 'innerText'] = content; } } // NOTE: Overridden by PopOver class }, { key: 'getTitle', value: function getTitle() { var title = this.$config.title || ''; if (typeof title === 'function') { // Call the function to get the title value title = title(this.$element); } if ((typeof title === 'undefined' ? 'undefined' : _typeof(title)) === 'object' && title.nodeType && !title.innerHTML.trim()) { // We have a DOM node, but without inner content, so just return empty string title = ''; } if (typeof title === 'string') { title = title.trim(); } if (!title) { // If an explicit title is not given, try element's title atributes title = getAttr(this.$element, 'title') || getAttr(this.$element, 'data-original-title') || ''; title = title.trim(); } return title; } }, { key: 'listen', value: function listen() { var _this6 = this; var triggers = this.$config.trigger.trim().split(/\s+/); var el = this.$element; // Listen for global show/hide events this.setRootListener(true); // Using 'this' as the handler will get automagically directed to this.handleEvent // And maintain our binding to 'this' triggers.forEach(function (trigger) { if (trigger === 'click') { eventOn(el, 'click', _this6); } else if (trigger === 'focus') { eventOn(el, 'focusin', _this6); eventOn(el, 'focusout', _this6); } else if (trigger === 'blur') { // Used to close $tip when element looses focus eventOn(el, 'focusout', _this6); } else if (trigger === 'hover') { eventOn(el, 'mouseenter', _this6); eventOn(el, 'mouseleave', _this6); } }, this); } }, { key: 'unListen', value: function unListen() { var _this7 = this; var events = ['click', 'focusin', 'focusout', 'mouseenter', 'mouseleave']; // Using "this" as the handler will get automagically directed to this.handleEvent events.forEach(function (evt) { eventOff(_this7.$element, evt, _this7); }, this); // Stop listening for global show/hide/enable/disable events this.setRootListener(false); } }, { key: 'handleEvent', value: function handleEvent(e) { // This special method allows us to use "this" as the event handlers if (isDisabled(this.$element)) { // If disabled, don't do anything. Note: if tip is shown before element gets // disabled, then tip not close until no longer disabled or forcefully closed. return; } if (!this.$isEnabled) { // If not enable return; } var type = e.type; var target = e.target; var relatedTarget = e.relatedTarget; var $element = this.$element; var $tip = this.$tip; if (type === 'click') { this.toggle(e); } else if (type === 'focusin' || type === 'mouseenter') { this.enter(e); } else if (type === 'focusout') { // target is the element which is loosing focus // And relatedTarget is the element gaining focus if ($tip && $element && $element.contains(target) && $tip.contains(relatedTarget)) { // If focus moves from $element to $tip, don't trigger a leave return; } if ($tip && $element && $tip.contains(target) && $element.contains(relatedTarget)) { // If focus moves from $tip to $element, don't trigger a leave return; } if ($tip && $tip.contains(target) && $tip.contains(relatedTarget)) { // If focus moves within $tip, don't trigger a leave return; } if ($element && $element.contains(target) && $element.contains(relatedTarget)) { // If focus moves within $element, don't trigger a leave return; } // Otherwise trigger a leave this.leave(e); } else if (type === 'mouseleave') { this.leave(e); } } /* istanbul ignore next */ }, { key: 'setRouteWatcher', value: function setRouteWatcher(on) { var _this8 = this; if (on) { this.setRouteWatcher(false); if (this.$root && Boolean(this.$root.$route)) { this.$routeWatcher = this.$root.$watch('$route', function (newVal, oldVal) { if (newVal === oldVal) { return; } // If route has changed, we force hide the tooltip/popover _this8.forceHide(); }); } } else { if (this.$routeWatcher) { // cancel the route watcher by calling hte stored reference this.$routeWatcher(); this.$routeWatcher = null; } } } /* istanbul ignore next */ }, { key: 'setModalListener', value: function setModalListener(on) { var modal = closest(MODAL_CLASS, this.$element); if (!modal) { // If we are not in a modal, don't worry. be happy return; } // We can listen for modal hidden events on $root if (this.$root) { this.$root[on ? '$on' : '$off'](MODAL_CLOSE_EVENT, this.$forceHide); } } /* istanbul ignore next */ }, { key: 'setRootListener', value: function setRootListener(on) { // Listen for global 'bv::{hide|show}::{tooltip|popover}' hide request event if (this.$root) { this.$root[on ? '$on' : '$off']('bv::hide::' + this.constructor.NAME, this.$doHide); this.$root[on ? '$on' : '$off']('bv::show::' + this.constructor.NAME, this.$doShow); this.$root[on ? '$on' : '$off']('bv::disable::' + this.constructor.NAME, this.$doDisable); this.$root[on ? '$on' : '$off']('bv::enable::' + this.constructor.NAME, this.$doEnable); } } }, { key: 'doHide', value: function doHide(id) { // Programmatically hide tooltip or popover if (!id) { // Close all tooltips or popovers this.forceHide(); } else if (this.$element && this.$element.id && this.$element.id === id) { // Close this specific tooltip or popover this.hide(); } } }, { key: 'doShow', value: function doShow(id) { // Programmatically show tooltip or popover if (!id) { // Open all tooltips or popovers this.show(); } else if (id && this.$element && this.$element.id && this.$element.id === id) { // Show this specific tooltip or popover this.show(); } } }, { key: 'doDisable', value: function doDisable(id) { // Programmatically disable tooltip or popover if (!id) { // Disable all tooltips or popovers this.disable(); } else if (this.$element && this.$element.id && this.$element.id === id) { // Disable this specific tooltip or popover this.disable(); } } }, { key: 'doEnable', value: function doEnable(id) { // Programmatically enable tooltip or popover if (!id) { // Enable all tooltips or popovers this.enable(); } else if (this.$element && this.$element.id && this.$element.id === id) { // Enable this specific tooltip or popover this.enable(); } } /* istanbul ignore next */ }, { key: 'setOnTouchStartListener', value: function setOnTouchStartListener(on) { var _this9 = this; // 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) { arrayFrom(document.body.children).forEach(function (el) { if (on) { eventOn(el, 'mouseover', _this9._noop); } else { eventOff(el, 'mouseover', _this9._noop); } }); } } /* istanbul ignore next */ }, { key: '_noop', value: function _noop() { // Empty noop handler for ontouchstart devices } }, { key: 'fixTitle', value: function fixTitle() { var el = this.$element; var titleType = _typeof(getAttr(el, 'data-original-title')); if (getAttr(el, 'title') || titleType !== 'string') { setAttr(el, 'data-original-title', getAttr(el, 'title') || ''); setAttr(el, 'title', ''); } } // Enter handler /* istanbul ignore next */ }, { key: 'enter', value: function enter(e) { var _this10 = this; if (e) { this.$activeTrigger[e.type === 'focusin' ? 'focus' : 'hover'] = true; } if (hasClass(this.getTipElement(), ClassName.SHOW) || this.$hoverState === HoverState.SHOW) { this.$hoverState = HoverState.SHOW; return; } clearTimeout(this.$hoverTimeout); this.$hoverState = HoverState.SHOW; if (!this.$config.delay || !this.$config.delay.show) { this.show(); return; } this.$hoverTimeout = setTimeout(function () { if (_this10.$hoverState === HoverState.SHOW) { _this10.show(); } }, this.$config.delay.show); } // Leave handler /* istanbul ignore next */ }, { key: 'leave', value: function leave(e) { var _this11 = this; if (e) { this.$activeTrigger[e.type === 'focusout' ? 'focus' : 'hover'] = false; if (e.type === 'focusout' && /blur/.test(this.$config.trigger)) { // Special case for `blur`: we clear out the other triggers this.$activeTrigger.click = false; this.$activeTrigger.hover = false; } } if (this.isWithActiveTrigger()) { return; } clearTimeout(this.$hoverTimeout); this.$hoverState = HoverState.OUT; if (!this.$config.delay || !this.$config.delay.hide) { this.hide(); return; } this.$hoverTimeout = setTimeout(function () { if (_this11.$hoverState === HoverState.OUT) { _this11.hide(); } }, this.$config.delay.hide); } }, { key: 'getPopperConfig', value: function getPopperConfig(placement, tip) { var _this12 = this; return { placement: this.constructor.getAttachment(placement), modifiers: { offset: { offset: this.getOffset(placement, tip) }, flip: { behavior: this.$config.fallbackPlacement }, arrow: { element: '.arrow' }, preventOverflow: { boundariesElement: this.$config.boundary } }, onCreate: function onCreate(data) { // Handle flipping arrow classes if (data.originalPlacement !== data.placement) { _this12.handlePopperPlacementChange(data); } }, onUpdate: function onUpdate(data) { // Handle flipping arrow classes _this12.handlePopperPlacementChange(data); } }; } }, { key: 'getOffset', value: function getOffset(placement, tip) { if (!this.$config.offset) { var arrow = select(Selector.ARROW, tip); var arrowOffset = parseFloat(getCS(arrow).width) + parseFloat(this.$config.arrowPadding); switch (OffsetMap[placement.toUpperCase()]) { case +1: return '+50%p - ' + arrowOffset + 'px'; case -1: return '-50%p + ' + arrowOffset + 'px'; default: return 0; } } return parseFloat(this.$config.offset); } }, { key: 'getPlacement', value: function getPlacement() { var placement = this.$config.placement; if (typeof placement === 'function') { return placement.call(this, this.$tip, this.$element); } return placement; } }, { key: 'isWithActiveTrigger', value: function isWithActiveTrigger() { for (var trigger in this.$activeTrigger) { if (this.$activeTrigger[trigger]) { return true; } } return false; } // NOTE: Overridden by PopOver class }, { key: 'cleanTipClass', value: function cleanTipClass() { var tip = this.getTipElement(); var tabClass = tip.className.match(BSCLS_PREFIX_REGEX); if (tabClass !== null && tabClass.length > 0) { tabClass.forEach(function (cls) { removeClass(tip, cls); }); } } }, { key: 'handlePopperPlacementChange', value: function handlePopperPlacementChange(data) { this.cleanTipClass(); this.addAttachmentClass(this.constructor.getAttachment(data.placement)); } }, { key: 'fixTransition', value: function fixTransition(tip) { var initConfigAnimation = this.$config.animation || false; if (getAttr(tip, 'x-placement') !== null) { return; } removeClass(tip, ClassName.FADE); this.$config.animation = false; this.hide(); this.show(); this.$config.animation = initConfigAnimation; } }], [{ key: 'getAttachment', value: function getAttachment(placement) { return AttachmentMap[placement.toUpperCase()]; } }, { key: 'Default', get: function get() { return Defaults; } // NOTE: Overridden by PopOver class }, { key: 'NAME', get: function get() { return NAME; } }]); return ToolTip; }(); export default ToolTip;