@@ -145,6 +145,15 @@ export const BVTooltip = /*#__PURE__*/ Vue.extend({
145145 }
146146 }
147147 return false
148+ } ,
149+ computedTemplateData ( ) {
150+ return {
151+ title : this . title ,
152+ content : this . content ,
153+ variant : this . variant ,
154+ customClass : this . customClass ,
155+ noFade : this . noFade
156+ }
148157 }
149158 } ,
150159 watch : {
@@ -160,26 +169,14 @@ export const BVTooltip = /*#__PURE__*/ Vue.extend({
160169 } )
161170 }
162171 } ,
172+ computedTemplateData ( newVal , oldVal ) {
173+ // If any of the while open reactive "props" change,
174+ // ensure that the template updates accordingly
175+ this . handleTemplateUpdate ( )
176+ } ,
163177 disabled ( newVal , oldVal ) {
164178 newVal ? this . disable ( ) : this . enable ( )
165179 } ,
166- // The following wont be needed when these are moved to data() (possibly)
167- // and teh updated() hook supposedly runs when data is updated (but not props)
168- title ( newVal , oldVal ) {
169- this . $nextTick ( this . handleTemplateUpdate )
170- } ,
171- content ( newVal , oldVal ) {
172- this . $nextTick ( this . handleTemplateUpdate )
173- } ,
174- variant ( newVal , oldVal ) {
175- this . $nextTick ( this . handleTemplateUpdate )
176- } ,
177- customClass ( newVal , oldVal ) {
178- this . $nextTick ( this . handleTemplateUpdate )
179- } ,
180- noFade ( newVal , oldVal ) {
181- this . $nextTick ( this . handleTemplateUpdate )
182- }
183180 } ,
184181 created ( ) {
185182 // Create non-reactive properties
@@ -228,23 +225,21 @@ export const BVTooltip = /*#__PURE__*/ Vue.extend({
228225 } ,
229226 methods : {
230227 //
231- // Methd for updating popper/template data
228+ // Methods for creating and destroying the template
232229 //
230+ getTemplate ( ) {
231+ // Overridden by BVPopover
232+ return BVTooltipTemplate
233+ } ,
233234 updateData ( data = { } ) {
235+ // Method for updating popper/template data
234236 // We only update data if it exists, and has not changed
235237 keys ( templateData ) . forEach ( prop => {
236238 if ( ! isUndefined ( data [ prop ] ) && this [ prop ] !== data [ prop ] ) {
237239 this [ prop ] = data [ prop ]
238240 }
239241 } )
240242 } ,
241- //
242- // Methods for creating and destroying the template
243- //
244- getTemplate ( ) {
245- // Overridden by BVPopover
246- return BVTooltipTemplate
247- } ,
248243 createTemplateAndShow ( ) {
249244 // Creates the template instance and show it
250245 // this.destroyTemplate()
@@ -304,17 +299,17 @@ export const BVTooltip = /*#__PURE__*/ Vue.extend({
304299 this . $_hoverState = ''
305300 this . clearActiveTriggers ( )
306301 this . localPlacementTarget = null
307- this . localShow = false
308302 try {
309303 this . $_tip && this . $_tip . $destroy ( )
310304 } catch { }
311305 this . $_tip = null
306+ this . localShow = false
312307 } ,
313308 getTemplateElement ( ) {
314309 return this . $_tip ? this . $_tip . $el : null
315310 } ,
316311 handleTemplateUpdate ( ) {
317- // Update our observable title/content props
312+ // Update our template title/content " props"
318313 // So that the template updates accordingly
319314 const $tip = this . $_tip
320315 if ( $tip ) {
@@ -334,19 +329,28 @@ export const BVTooltip = /*#__PURE__*/ Vue.extend({
334329 // Show the tooltip
335330 const target = this . getTarget ( )
336331
337- // TODO:
338- // Test for existence of $_tip and exit if exists
339332 if ( ! target || ! document . body . contains ( target ) || ! isVisible ( target ) || this . dropdownOpen ( ) ) {
340333 // If trigger element isn't in the DOM or is not visible, or is on an open dropdown toggle
341334 return
342335 }
336+
337+ if ( this . $_tip || this . localShow ) {
338+ // If tip already exists, exit early
339+ return
340+ }
343341
342+ // In the process of showing
343+ this . localShow = true
344+
344345 // Create a cancelable BvEvent
345346 const showEvt = this . buildEvent ( 'show' , { cancelable : true } )
346347 this . emitEvent ( showEvt )
347348 if ( showEvt . defaultPrevented ) {
348349 // Don't show if event cancelled
350+ // Destroy the template (if for some reason it was created)
349351 this . destroyTemplate ( )
352+ // Clear the localShow flag
353+ this . localShow = false
350354 return
351355 }
352356
@@ -356,9 +360,7 @@ export const BVTooltip = /*#__PURE__*/ Vue.extend({
356360 // Set aria-describedby on target
357361 this . addAriaDescribedby ( )
358362
359- // Flag we are showing
360- this . localShow = true
361- // Create and how the tooltip
363+ // Create and show the tooltip
362364 this . createTemplateAndShow ( )
363365 } ,
364366 hide ( force = false ) {
@@ -382,7 +384,7 @@ export const BVTooltip = /*#__PURE__*/ Vue.extend({
382384 this . hideTemplate ( )
383385 // TODO:
384386 // The following could be added to hideTemplate()
385- // Clear out any active triggers
387+ // Clear out any stragging active triggers
386388 this . clearActiveTriggers ( )
387389 // Reset the hoverstate
388390 this . $_hoverState = ''
@@ -552,7 +554,7 @@ export const BVTooltip = /*#__PURE__*/ Vue.extend({
552554 // If the target has a title attribute, null it out and
553555 // store on data-title
554556 const target = this . getTarget ( )
555- if ( hasAttr ( target , 'title' ) ) {
557+ if ( target && hasAttr ( target , 'title' ) ) {
556558 setAttr ( target , 'data-original-title' , getAttr ( target , 'title' ) || '' )
557559 setAttr ( target , 'title' , '' )
558560 }
@@ -561,7 +563,7 @@ export const BVTooltip = /*#__PURE__*/ Vue.extend({
561563 // If target had a title, restore the title attribute
562564 // and remove the data-title attribute
563565 const target = this . getTarget ( )
564- if ( hasAttr ( target , 'data-original-title' ) ) {
566+ if ( target && hasAttr ( target , 'data-original-title' ) ) {
565567 setAttr ( target , 'title' , getAttr ( target , 'data-original-title' ) || '' )
566568 setAttr ( target , 'data-original-title' , '' )
567569 }
@@ -574,7 +576,7 @@ export const BVTooltip = /*#__PURE__*/ Vue.extend({
574576 return new BvEvent ( type , {
575577 cancelable : false ,
576578 target : this . getTarget ( ) ,
577- relatedTarget : this . getTemplateElement ( ) ,
579+ relatedTarget : this . getTemplateElement ( ) || null ,
578580 componentId : this . computedId ,
579581 vueTarget : this ,
580582 // Add in option overrides
@@ -625,12 +627,13 @@ export const BVTooltip = /*#__PURE__*/ Vue.extend({
625627 const events = [ 'click' , 'focusin' , 'focusout' , 'mouseenter' , 'mouseleave' ]
626628 const target = this . getTarget ( )
627629
630+ // Stop listening for global show/hide/enable/disable events
631+ this . setRootListener ( false )
632+
633+ // Clear out any active target listeners
628634 events . forEach ( evt => {
629635 target && eventOff ( target , evt , this . handleEvent , EvtOpts )
630636 } , this )
631-
632- // Stop listening for global show/hide/enable/disable events
633- this . setRootListener ( false )
634637 } ,
635638 setRootListener ( on ) {
636639 // Listen for global `bv::{hide|show}::{tooltip|popover}` hide request event
@@ -651,24 +654,21 @@ export const BVTooltip = /*#__PURE__*/ Vue.extend({
651654 // Dropdown open events (if we are attached to a dropdown)
652655 this . setDropdownListener ( on )
653656 // Periodic $element visibility check
654- // For handling when tip is in <keepalive>, tabs, carousel, etc
657+ // For handling when tip target is in <keepalive>, tabs, carousel, etc
655658 this . visibleCheck ( on )
656659 // On-touch start listeners
657660 this . setOnTouchStartListener ( on )
658661 } ,
659662 visibleCheck ( on ) {
660663 // Handler for periodic visibility check
661- // TODO:
662- // Could make this a MutationObserver or IntersectionObserver
663664 clearInterval ( this . $_visibleInterval )
664665 this . $_visibleInterval = null
666+ const target = this . getTarget ( )
667+ const tip = this . getTemplateElement ( )
665668 if ( on ) {
666669 this . visibleInterval = setInterval ( ( ) => {
667- const tip = this . getTemplateElement ( )
668- // TODO:
669- // Change the hasClass check to check localShow status instead
670- if ( tip && ! isVisible ( this . getTarget ( ) ) && this . localShow ) {
671- // Element is no longer visible, so force-hide the tooltip
670+ if ( tip && this . localShow && ( ! target . parentNode || ! isVisible ( target ) ) ) {
671+ // Target element is no longer visible or not in DOM, so force-hide the tooltip
672672 this . forceHide ( )
673673 }
674674 } , 100 )
@@ -703,8 +703,9 @@ export const BVTooltip = /*#__PURE__*/ Vue.extend({
703703 // TODO:
704704 // We could grab the ID from the dropdown, and listen for
705705 // $root events for that particular dropdown id
706- // Although dropdown doesn't emit $root events
706+ // Dropdown shown and hidden events will need to emit
707707 // Note: Dropdown auto-ID happens in a $nextTick after mount
708+ // So the ID lookup would need to be done in a nextTick
708709 if ( target . __vue__ ) {
709710 target . __vue__ [ on ? '$on' : '$off' ] ( 'shown' , this . forceHide )
710711 }
@@ -714,7 +715,6 @@ export const BVTooltip = /*#__PURE__*/ Vue.extend({
714715 //
715716 handleEvent ( evt ) {
716717 // General trigger event handler
717- // Will handle any native event when the event handler is just `this`
718718 // target is the trigger element
719719 const target = this . getTarget ( )
720720 if ( ! target || isDisabled ( target ) || ! this . $_enabled || this . dropdownOpen ( ) ) {
0 commit comments