Cleaning up mouseenter by calling a function?

173 views Asked by At

I would like to clean up the mouseenter portion of my tooltip plugin by calling a new function called showKeyTip. (This would also enable me to use an if statement inside mouseenter to control the hover)

I got the idea from how setTimeout is handled in mouseleave, but for some reason, a similar call is not working in mouseenter...

I feel like I am missing something, or do not fully understand how $(this) is tied to things.

Any advice/suggestions are appreciated.


Current code (snippet):

  // [ hide ]
  function hideKeyTip(){
    timer = setTimeout(function(){
        keyTip.stop().fadeOut(faderate)}, timeout); 
  }

  // [ control ]
  return this.each(function(){

    $(this)

    .on("mouseenter", function(){

      clearTimeout(timer);

      // dimensions
      var targetH = $(this).height()/2,
          targetW = $(this).width();

      // position
      var top = $(this).offset().top - targetH + padtop,
          left = $(this).offset().left + targetW + padleft;

      // apply css & show
      keyTip.css({
        'top': top, 
        'left': left
      }).show(); 
    })// mouseenter

    .on("mouseleave", function(){

      hideKeyTip();

    });// mouseleave    
  });// return this

Cleaned up version (not working)

I moved the contents of mouseenter into a new function called showKeyTip and call it within mouseenter.

  // [ hide ]
  function hideKeyTip(){
    timer = setTimeout(function(){
        keyTip.stop().fadeOut(faderate)}, timeout); 
  }

  // [ show ]
  function showKeyTip(){

      clearTimeout(timer);

      // dimensions
      var targetH = $(this).height()/2,
          targetW = $(this).width();

      // position
      var top = $(this).offset().top - targetH + padtop,
          left = $(this).offset().left + targetW + padleft;

      // apply css settings & show
      keyTip.css({
        'top': top, 
        'left': left
      }).show(); 
  }

  // [ control ]

  return this.each(function(){

    $(this)

    .on("mouseenter", function(){

      showKeyTip();

    })// mouseenter

    .on("mouseleave", function(){

      hideKeyTip();

    });// mouseleave    
  });// return this

Update: Cleaned up version 2 (working)

Using adeneo's suggestion, there is one last piece to this puzzle...

What is the best way to roll in a test case for hover or mouseenter/over of the tooltip?

I'd like to keep showing the tooltip if being hovered over.

My current stance is to add an if statement to the hideKeyTip function, but the tooltips get hung up on being shown and never fade out when the mouse leaves.

  // [ hide ]
  function hideKeyTip(){
    if(!keyTip.hover()){
      timer = setTimeout(function(){
        keyTip.stop().fadeOut(faderate)}, timeout); 
    }
  }

  // [ show ]
  function showKeyTip(){

      clearTimeout(timer);

      // dimensions
      var targetH = $(this).height()/2,
          targetW = $(this).width();

      // position
      var top = $(this).offset().top - targetH + padtop,
          left = $(this).offset().left + targetW + padleft;

      // apply css settings & show
      keyTip.css({
        'top': top, 
        'left': left
      }).show(); 
  }

  // [ control ]
  return this.on({

    mouseenter: showKeyTip,
    mouseleave: hideKeyTip

  });// return this

Update: Hover control (help!)

Trying to reuse the hide and show functions to display the tooltip when the user is hovering over the actual tooltip. (useful for when a link is present in the tooltip.)

Any suggestions? What am I doing wrong? Thanks...

  // [ hide ]
  function hideKeyTip(){
      timer = setTimeout(function(){
        keyTip.stop().fadeOut(faderate)}, timeout); 
  }

  // [ show ]
  function showKeyTip(){

      clearTimeout(timer);

      // dimensions
      var targetH = $(this).height()/2,
          targetW = $(this).width();

      // position
      var top = $(this).offset().top - targetH + padtop,
          left = $(this).offset().left + targetW + padleft;

      // apply css settings & show
      keyTip.css({
        'top': top, 
        'left': left
      }).show(); 
  }

  // [ control ]
  return this.on({

    mouseenter: showKeyTip,
    mouseleave: hideKeyTip

  });

  return keyTip.on({  
    // note: keyTip = $(settings.tooltip);
    mouseenter: function(){
      clearTimout(timer);
    },
    mouseleave: hideKeyTip
  });

Final Update: Hover control (solved)

After some trial and error in codepen, I think I've found a good solution for showing the tooltip while the user's mouse cursor was over it. I was also approaching the problem from the wrong angle... is that return keyTip.on() statement even legal?

So here's what I've come up with. If you can point out any negatives to this method, please let me know.

I will post the codepen in a comment below when I have it cleaned up.

Thank you adeneo for pointing me in the right direction.

  // [ hide ]
  function hideKeyTip(){

     // note: keyTip = $(settings.tooltip);

     keyTip.on({
        mouseenter: function(){
           //you have arrived
        }, 
        mouseleave: function(){
           timer = setTimeout(function(){
              keyTip.stop().fadeOut(faderate)}, timeout); 
        };
     });
  }

  // [ show ]
  function showKeyTip(){

      clearTimeout(timer);

      // dimensions
      var targetH = $(this).height()/2,
          targetW = $(this).width();

      // position
      var top = $(this).offset().top - targetH + padtop,
          left = $(this).offset().left + targetW + padleft;

      // apply css settings & show
      keyTip.css({
        'top': top, 
        'left': left
      }).show(); 
  }

  // [ control ]
  return this.on({
    mouseenter: showKeyTip,
    mouseleave: hideKeyTip

  });
2

There are 2 answers

3
adeneo On BEST ANSWER

When calling the functions in the window scope, the window is obviously the value of this.
You need to reference the functions, not call them inside other anonymous functions, to keep the value of this as the element.

return this.on({
           mouseenter : showKeyTip,
           mouseleave : hideKeyTip,
});

note that you can drop the each call if all you're doing is calling on on the collection, as jQuery iterates iternally.

0
Yuriy.Bidasyuk On

The easiest solution to correct your code would be to pass this as an argument to your showKeyTip function.

The call would be

showKeyTip(this);

And the function declaration

function showKeyTip(t){
   .....
   var targetH = $(t).height()/2,
   .....
}