3
\$\begingroup\$

I've been getting into plugin development for jQuery and my first creation is a tooltip plugin. I've been reading a lot about plugin development especially with the use of JavaScript prototyping. I'm just looking for any tips to further improve my plugin development (only 144 lines of code).

Two questions in particular:

  1. The tooltip accepts "settings" options which I extend the standard jQuery way. Should I be passing only the necessary properties into the "Tip" object for each tooltip rather than the whole settings object, which right now I'm just doing out of convenience and simplicity?

  2. I also pass the event scheduler to the "Tip" object out of convenience, but should I be passing this into the function calls separately rather than keeping it as part of each tooltip object?

demo: http://websanova.com/plugins/tooltips/jquery#wtip

code (also at http://websanova.com/a/plugins/websanova/tooltip/wTip.1.0.js):

/******************************************
 * Websanova.com
 *
 * Resources for web entrepreneurs
 *
 * @author          Websanova
 * @copyright       Copyright (c) 2012 Websanova.
 * @license         This wTip jQuery plug-in is dual licensed under the MIT and GPL licenses.
 * @link            http://www.websanova.com
 * @docs            http://www.websanova.com/plugins/websanova/tooltip
 * @version         Version 1.0
 *
 ******************************************/
(function($)
{
  $.fn.wTip = function(settings)
  {
    var defaultSettings = {
      color    : 'cream',     // allow custom with #FFAACC
      opacity    : 0.8,      // opacity level
      title    : null,      // manually set title
      fadeIn    : 0,      // time before tooltip appears in milliseconds
      fadeOut    : 0,      // time before tooltip fades in milliseconds
      delayIn    : 0,      // time before tooltip displays in milliseconds
      delayOut  : 0,      // time before tooltip begins to dissapear in milliseconds
      offsetX    : 8,      // x offset of mouse position
      offsetY    : 15      // y offset of mouse position
    }

    var supportedColors = ['red','green','blue','white','black','cream','yellow','orange','plum'];

    settings = $.extend(defaultSettings,settings);

    return this.each(function()
    {
      var elem = $(this);

      settings.title = settings.title || elem.attr('title') || 'No title set';  

      var scheduleEvent = new eventScheduler();
      var tip = new Tip(settings, scheduleEvent);

      $('body').append(tip.generate());

      elem
      //hover on/off triggers
      .hover(function()
      {
        tip.hover = true;

        scheduleEvent.set(function(){ tip.show(); }, settings.delayIn);
      },function()
      {
        tip.hover = false;

        if(tip.shown) tip.hide();
      })
      //move tooltip with mouse poitner
      .mousemove(function(e)
      {
        tip.move(e);
      })
      //remove title attribute so that we don't have the browser title showing up
      .removeAttr('title');
    });
  }

  /**
   * Event scheduler class definition
   */
  function eventScheduler(){}

  eventScheduler.prototype =
  {
    set: function (func, timeout)
    {
      this.timer = setTimeout(func, timeout);
    },

    clear: function()
    {
      clearTimeout(this.timer);
    }
  }

  /**
   * Tip class definition
   */
  function Tip(settings, scheduleEvent)
  {
    this.hover = false;
    this.shown = false;

    this.settings = settings;
    this.scheduleEvent = scheduleEvent;
  }

  Tip.prototype = 
  {
    generate: function()
    {
      if(this.tip) return this.tip;

      this.tip =
      $('<div class="_wTip_holder"><div class="_wTip_outer"><div class="_wTip_bg"></div><div class="_wTip_inner">' + this.settings.title + '</div></div></div>')
      .css({display: 'none', position: 'absolute', opacity: this.settings.opacity})
      .addClass('_wTip_' + this.settings.color);

      return this.tip;
    },

    show: function()
    {
      var $this = this;

      this.tip.fadeIn(this.settings.fadeIn, function()
      {
        $this.shown = true;

        if(!$this.hover) $this.hide();
      });
    },

    move: function(e)
    {
      this.tip.css({left: e.pageX + this.settings.offsetX, top: e.pageY + this.settings.offsetY});
    },

    hide: function()
    {
      var $this = this;

      this.scheduleEvent.set(function()
      {
        $this.tip.fadeOut($this.settings.fadeOut, function()
        {
          $this.shown = false;
        });
      },
      this.settings.delayOut);
    }
  }
})(jQuery);

Any tips or pointers in the right direction appreciated.

\$\endgroup\$
2
  • 2
    \$\begingroup\$ for future reference: Please include the code in the question, not a link to it \$\endgroup\$
    – seand
    Commented Jan 18, 2012 at 19:56
  • \$\begingroup\$ I'm kind of curious why you picked a tooltip plugin, with so many of those (e.g. qTip) already in existence? \$\endgroup\$
    – Kato
    Commented Jan 26, 2012 at 15:40

1 Answer 1

1
\$\begingroup\$

You ask:

  1. The tooltip accepts "settings" options which I extend the standard jQuery way. Should I be passing only the necessary properties into the "Tip" object for each tooltip rather than the whole settings object, which right now I'm just doing out of convenience and simplicity?

A:

No. If you filter out any "extra" settings and someone comes along to extend your code they will have trouble if they want to add extra settings. There doesn't seem to be any reason to remove them.

Also on this point

settings = $.extend(defaultSettings,settings);

is normally

settings = $.extend({}, defaultSettings, settings || {});

This allows settings to be optional and defaultSettings won't be overridden.

I would also move var defaultSettings outside your $.fn.wTip function (but still in your closure (function($){) this will mean its not created every time.

While it is not necessary, I would return this in your eventScheduler class

function eventScheduler()
{
    return this;
}  

Its easier to understand that it is a class. (Also most class are Capitalized but thats just a style).

Overall I would say you have a nice clean coding style.

\$\endgroup\$
1
  • \$\begingroup\$ Thanks man, those are great tips. I also moved the $('body').append(tip.generate()); call into the generate function itself, which seemed to make more sense to me as well. \$\endgroup\$
    – Rob
    Commented Jan 23, 2012 at 0:48

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.