Search code examples
jqueryresponsive-designhovertooltipclickable

Responsive Tooltip with Tooltip Hover


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/


Solution

  • 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.