1

I have setup this code in order to work with a shortcode/plugin I'm building for WordPress...everything is finally working well with responsive (this is the third jQuery revision), but I'm having an issue with one thing: Hovering on the tooltip.

I need to be able to mouse into the tooltip and have it stay visible. I need the tooltip to go away if:

a. The tooltip is moused out of, or.. b. The target is moused out of

jQuery is not my strong suite and I can only get one or the other to happen.

HTML:

<div class="mbt-hover" style="width:100px; height:auto;">
    <p>Test Text</p>
    <div class="mbt-tooltip" style="width:200px; height:auto;">
        <p>Test pop-up <a title="About" href="http://www.mindblowingthings.dev/about/">content</a>
        <ul>
            <li>this</li>
            <li>is</li>
            <li>a list</li>
        </ul>
    </div>
</div>

CSS:

#tooltip {
text-align: center;
color: #fff;
background: #111;
position: absolute;
z-index: 100;
padding: 15px;
}

#tooltip:after {
    width: 0;
    height: 0;
    border-left: 10px solid transparent;
    border-right: 10px solid transparent;
    border-top: 10px solid #111;
    content: '';
    position: absolute;
    left: 50%;
    bottom: -10px;
    margin-left: -10px;
}

    #tooltip.top:after {
        border-top-color: transparent;
        border-bottom: 10px solid #111;
        top: -20px;
        bottom: auto;
    }

    #tooltip.left:after {
        left: 10px;
        margin: 0;
    }

    #tooltip.right:after {
        right: 10px;
        left: auto;
        margin: 0;
    }


.mbt-tooltip {
display: none;
width: auto;
max-width: 100% !important;
} 

JQUERY

$( function() {

    var targets = $('.mbt-hover'),
        target  = false,
        tooltip = $('.mbt-tooltip'),
        title   = false;

    targets.bind( 'mouseenter', function()
    {
        target  = $( this );
        tip     = target.children('.mbt-tooltip');
        tooltip = $( '<div id="tooltip"></div>' );

        if( !tip || tip == '' )
            return false;

        //target.remove('.mbt-tooltip');
        //target.removeAttr( 'title' );
        tooltip.css( 'opacity', 0 )

               .html( tip.clone().show() )

               .appendTo( 'body' );

        var init_tooltip = function()
        {
            if( $( window ).width() < tooltip.outerWidth() * 1.5 )
                tooltip.css( 'max-width', $( window ).width() / 2 );
            else
                tooltip.css( 'max-width', 340 );

            var pos_left = target.offset().left + ( target.outerWidth() / 2 ) - ( tooltip.outerWidth() / 2 ),
                pos_top  = target.offset().top - tooltip.outerHeight() - 20;

            if( pos_left < 0 )
            {
                pos_left = target.offset().left + target.outerWidth() / 2 - 20;
                tooltip.addClass( 'left' );
            }
            else
                tooltip.removeClass( 'left' );

            if( pos_left + tooltip.outerWidth() > $( window ).width() )
            {
                pos_left = target.offset().left - tooltip.outerWidth() + target.outerWidth() / 2 + 20;
                tooltip.addClass( 'right' );
            }
            else
                tooltip.removeClass( 'right' );

            if( pos_top < 0 )
            {
                var pos_top  = target.offset().top + target.outerHeight();
                tooltip.addClass( 'top' );
            }
            else
                tooltip.removeClass( 'top' );

            tooltip.css( { left: pos_left, top: pos_top } )
                   .animate( { top: '+=10', opacity: 1 }, 50 );
        };

        init_tooltip();
        $( window ).resize( init_tooltip );


       var remove_tooltip = function()
        {
            tooltip.animate( { top: '-=10', opacity: 0 }, 300, function()
            {
                $( this ).remove();
            });

            target.children('.mbt-tooltip', tip);

        };

        //**** ISSUE AREA ****//
        target.bind( 'mouseleave', remove_tooltip );
        tooltip.bind( 'click', remove_tooltip );
    });
});

FIDDLE: http://jsfiddle.net/RevConcept/L8bho8yu/

RevConcept
  • 253
  • 1
  • 6
  • 19

1 Answers1

1

that's because the tooltip that you create on mouseenter event of .mbt-hover

tooltip = $( '<div id="tooltip"></div>' );

is a new element that you append to the body. Because it's not a child of .mbt-hover, when you try to hover over the tooltip, it will trigger the mouseleave event of .mbt-hover, thus removing the tooltip.

What you need to do is to append the new tooltip that you create to the .mbt-hover, and not to the body, so when you hover over the tooltip, it still count as mouseenter on .mbt-hover and wouldn't remove the tooltip. (*Note: this will results the same only if your tooltip absolute position is relative to the body and not to the parent container, if your tooltip position is relative to it's parent, you need to change your code to calculate the top, left, or right)

You also have some redundant code, for example:

  1. var targets = $('.mbt-hover') with target = $( this );, this two variable is pointing / targetting to the same element which is .mbt-hover, so it's better for you to only use the targets for every usage inside the mouseenter event by replacing the target to targets.
  2. Because you already have a tooltip in your HTML with class .mbt-tooltip, it's better to use it for the tooltip, rather then creating a new tooltip element that clone the one that you have already (Because on document ready, you declare it with tooltip = $('.mbt-tooltip'), but then on the mouseenter you change it with tooltip = $( '<div id="tooltip"></div>' );

Here's the Updated Fiddle of yours which is removed from the redundant code on point number one.

Kyojimaru
  • 2,694
  • 1
  • 14
  • 22
  • Ahhhh! Genius :) I never even thought of that. Thank you SO much and thank you for the very detailed answer with explanation! – RevConcept Oct 31 '14 at 16:33
  • Actually, there was an issue because there can be more than one tooltip on the page and your code was combining the tooltip content into one tip. I updated it: http://jsfiddle.net/RevConcept/x8vz6kdy/1/ – RevConcept Oct 31 '14 at 16:40
  • @RevConcept, did you embed all your tooltip inside every `mbt-hover`, and every `tooltip` has the same template? If yes, I think it's better to embed it as `data` attribute in the `mbt-hover` (e.g.: `data-listcount="2" data-list1="one" data-list2="two"`), so it wouldn't take as much space, then when you append it, give it an `id`, so when you hover again, you just need to check if it exist already and show it, rather than updating the existing one or creating a new one everytime. – Kyojimaru Nov 03 '14 at 02:40
  • The issue is that these tooltips are tied to client created content in a WordPress shortcode...so I can't really use data attributes since they will be adding a variety of content including images and videos. Make sense? – RevConcept Nov 04 '14 at 20:50
  • @RevConcept, I think you can still use `data` attributes, but it will take quite a lot of time to change the code though, but I'm not sure which one perform better and if it's worth the time. If you don't have any performance issue, I think it's ok to keep what you do now. – Kyojimaru Nov 05 '14 at 04:53