Superfish-Reloaded (v10)

Revision 10 of this benchmark created on


Description

Superfish initialisation code was missing from test case #2. This revision corrects this and deletes the reference to $.browser.msie from test case #1 to avoid a jQuery 1.9 error. Results are much closer now (although event delegation is, of course, a better idea).

Preparation HTML

<script src="https://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js">
</script>
                <ul class="sf-menu">
                        <li class="current">
                                <a href="#a">menu level1</a>
                                <ul>
                                        <li>
                                                <a href="#aa">menu item that is quite long</a>
                                        </li>
                                        <li class="current">
                                                <a href="#ab">menu level2</a>
                                                <ul>
                                                        <li><a href="#3">menu level3</a>
                                                                <ul>
                                                                        <li><a href="#">Menu level4</a></li>
                                                                </ul>
                                                        </li>
                                                        <li><a href="#aba">menu item</a></li>
                                                        <li><a href="#abb">menu item</a></li>
                                                        <li><a href="#abc">menu item</a></li>
                                                        <li><a href="#abd">menu item</a></li>
                                                </ul>
                                        </li>
                                        <li>
                                                <a href="#">menu item</a>
                                                <ul>
                                                        <li><a href="#">menu item</a></li>
                                                        <li><a href="#">menu item</a></li>
                                                        <li><a href="#">menu item</a></li>
                                                        <li><a href="#">menu item</a></li>
                                                        <li><a href="#">menu item</a></li>
                                                </ul>
                                        </li>
                                        <li>
                                                <a href="#">menu item</a>
                                                <ul>
                                                        <li><a href="#">menu item</a></li>
                                                        <li><a href="#">menu item</a></li>
                                                        <li><a href="#">menu item</a></li>
                                                        <li><a href="#">menu item</a></li>
                                                        <li><a href="#">menu item</a></li>
                                                </ul>
                                        </li>
                                </ul>
                        </li>
                        <li>
                                <a href="#">menu item</a>
                                <ul>
                                        <li>
                                                <a href="#">level one</a>
                                                <ul>
                                                        <li><a href="#">lvel 2</a></li>
                                                </ul>
                                        </li>
                                </ul>
                        </li>
                        <li>
                                <a href="#">menu item</a>
                                <ul>
                                        <li>
                                                <a href="#">menu item</a>
                                                <ul>
                                                        <li><a href="#">short</a></li>
                                                        <li><a href="#">short</a></li>
                                                        <li><a href="#">short</a></li>
                                                        <li><a href="#">short</a></li>
                                                        <li><a href="#">short</a></li>
                                                </ul>
                                        </li>
                                        <li>
                                                <a href="#">menu item</a>
                                                <ul>
                                                        <li><a href="#">menu item</a></li>
                                                        <li><a href="#">menu item</a></li>
                                                        <li><a href="#">menu item</a></li>
                                                        <li><a href="#">menu item</a></li>
                                                        <li><a href="#">menu item</a></li>
                                                </ul>
                                        </li>
                                        <li>
                                                <a href="#">menu item</a>
                                                <ul>
                                                        <li><a href="#">menu item</a></li>
                                                        <li><a href="#">menu item</a></li>
                                                        <li><a href="#">menu item</a></li>
                                                        <li><a href="#">menu item</a></li>
                                                        <li><a href="#">menu item</a></li>
                                                </ul>
                                        </li>
                                        <li>
                                                <a href="#">menu item</a>
                                                <ul>
                                                        <li><a href="#">menu item</a></li>
                                                        <li><a href="#">menu item</a></li>
                                                        <li><a href="#">menu item</a></li>
                                                        <li><a href="#">menu item</a></li>
                                                        <li><a href="#">menu item</a></li>
                                                </ul>
                                        </li>
                                        <li>
                                                <a href="#">menu item</a>
                                                <ul>
                                                        <li><a href="#">menu item</a></li>
                                                        <li><a href="#">menu item</a></li>
                                                        <li><a href="#">menu item</a></li>
                                                        <li><a href="#">menu item</a></li>
                                                        <li><a href="#">menu item</a></li>
                                                </ul>
                                        </li>
                                </ul>
                        </li>
                        <li>
                                <a href="#">menu item</a>
                        </li>   
                </ul>

Test runner

Ready to run.

Testing in
TestOps/sec
superfish1.4.8
/*
 * Superfish v1.4.8 - jQuery menu widget
 * Copyright (c) 2008 Joel Birch
 *
 * Dual licensed under the MIT and GPL licenses:
 *      http://www.opensource.org/licenses/mit-license.php
 *      http://www.gnu.org/licenses/gpl.html
 *
 * CHANGELOG: http://users.tpg.com.au/j_birch/plugins/superfish/changelog.txt
 */

;
(function($) {
  $.fn.superfish = function(op) {

    var sf = $.fn.superfish,
        c = sf.c,
        $arrow = $(['<span class="', c.arrowClass, '"> &#187;</span>'].join('')),
        over = function() {
        var $$ = $(this),
            menu = getMenu($$);
        clearTimeout(menu.sfTimer);
        $$.showSuperfishUl().siblings().hideSuperfishUl();
        },
        out = function() {
        var $$ = $(this),
            menu = getMenu($$),
            o = sf.op;
        clearTimeout(menu.sfTimer);
        menu.sfTimer = setTimeout(function() {
          o.retainPath = ($.inArray($$[0], o.$path) > -1);
          $$.hideSuperfishUl();
          if (o.$path.length && $$.parents(['li.', o.hoverClass].join('')).length < 1) {
            over.call(o.$path);
          }
        }, o.delay);
        },
        getMenu = function($menu) {
        var menu = $menu.parents(['ul.', c.menuClass, ':first'].join(''))[0];
        sf.op = sf.o[menu.serial];
        return menu;
        },
        addArrow = function($a) {
        $a.addClass(c.anchorClass).append($arrow.clone());
        };

    return this.each(function() {
      var s = this.serial = sf.o.length;
      var o = $.extend({}, sf.defaults, op);
      o.$path = $('li.' + o.pathClass, this).slice(0, o.pathLevels).each(function() {
        $(this).addClass([o.hoverClass, c.bcClass].join(' ')).filter('li:has(ul)').removeClass(o.pathClass);
      });
      sf.o[s] = sf.op = o;

      $('li:has(ul)', this)[($.fn.hoverIntent && !o.disableHI) ? 'hoverIntent' : 'hover'](over, out).each(function() {
        if (o.autoArrows) addArrow($('>a:first-child', this));
      }).not('.' + c.bcClass).hideSuperfishUl();

      var $a = $('a', this);
      $a.each(function(i) {
        var $li = $a.eq(i).parents('li');
        $a.eq(i).focus(function() {
          over.call($li);
        }).blur(function() {
          out.call($li);
        });
      });
      o.onInit.call(this);

    }).each(function() {
      var menuClasses = [c.menuClass];
      $(this).addClass(menuClasses.join(' '));
    });
  };

  var sf = $.fn.superfish;
  sf.o = [];
  sf.op = {};
  sf.IE7fix = function() {
    var o = sf.op;
    if ($.browser.msie && $.browser.version > 6 && o.dropShadows && o.animation.opacity != undefined) this.toggleClass(sf.c.shadowClass + '-off');
  };
  sf.c = {
    bcClass: 'sf-breadcrumb',
    menuClass: 'sf-js-enabled',
    anchorClass: 'sf-with-ul',
    arrowClass: 'sf-sub-indicator',
    shadowClass: 'sf-shadow'
  };
  sf.defaults = {
    hoverClass: 'sfHover',
    pathClass: 'overideThisToUse',
    pathLevels: 1,
    delay: 800,
    animation: {
      opacity: 'show'
    },
    speed: 'normal',
    autoArrows: true,
    dropShadows: true,
    disableHI: false,
    // true disables hoverIntent detection
    onInit: function() {},
    // callback functions
    onBeforeShow: function() {},
    onShow: function() {},
    onHide: function() {}
  };
  $.fn.extend({
    hideSuperfishUl: function() {
      var o = sf.op,
          not = (o.retainPath === true) ? o.$path : '';
      o.retainPath = false;
      var $ul = $(['li.', o.hoverClass].join(''), this).add(this).not(not).removeClass(o.hoverClass).find('>ul').hide().css('visibility', 'hidden');
      o.onHide.call($ul);
      return this;
    },
    showSuperfishUl: function() {
      var o = sf.op,
          sh = sf.c.shadowClass + '-off',
          $ul = this.addClass(o.hoverClass).find('>ul:hidden').css('visibility', 'visible');
      sf.IE7fix.call($ul);
      o.onBeforeShow.call($ul);
      $ul.animate(o.animation, o.speed, function() {
        sf.IE7fix.call($ul);
        o.onShow.call($ul);
      });
      return this;
    }
  });

})(jQuery);
jQuery('ul.sf-menu').superfish();
ready
Superfish-reloaded
/*
 * Superfish v1.5 - jQuery menu widget
 * Copyright (c) 2012 Bob Gregor
 * Copyright (c) 2008 Joel Birch
 *
 * Dual licensed under the MIT and GPL licenses:
 *      http://www.opensource.org/licenses/mit-license.php
 *      http://www.gnu.org/licenses/gpl.html
 *
 * CHANGELOG: https://github.com/bobbravo2/superfish/blob/master/changelog.txt
 */

;
(function($) {
  //Set up global SF object
  var sf = {};
  sf.c = {
    menuClass: 'sf-js-enabled',
    anchorClass: 'sf-with-ul'
  };
  sf.defaults = {
    hoverClass: 'sfHover',
    pathClass: 'overideThisToUse',
    pathLevels: 1,
    delay: 800,
    animIn: {
      opacity: 'show'
    },
    //What animation object to use to show the submenus
    animOut: {
      opacity: 'hide'
    },
    //  "       "                  "    "  "  "  hide  "     "
    easeIn: "swing",
    easeOut: "swing",
    speedIn: 'normal',
    speedOut: 'normal',
    autoArrows: true,
    arrow: '<span class="sf-sub-indicator">&#187;</span>',
    //Markup to use for sub-menu indicators
    disableHI: false,
    // true disables hoverIntent detection
    //All Callbacks are passed the current superfish instance as an argument
    onInit: function() {},
    // Called on init, after plugin data initialized
    onAfterInit: function() {},
    // callback functions
    onBeforeShow: function() {},
    //Passed the UL to be animated
    onShow: function() {},
    //Passed the UL just animated
    onBeforeHide: function() {},
    onHide: function() {}
  };
  $.fn.superfish = function(method) {
    // Method calling logic
    if (methods[method]) {
      return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
    } else if (typeof method === 'object' || !method) {
      return methods.init.apply(this, arguments);
    } else {
      $.error('Method ' + method + ' does not exist on jQuery.superfish');
    }
  }; /*****************************END jQuery Plugin **********/
  var methods = {
    init: function(opts) {
      return this.each(function() {
        //Set up local variables
        var _ = $(this),
            o = $.extend({}, sf.defaults, opts),
            
            
            //Namespace instance data
            data = _.data('superfish')
             if (!data) {
            //Initialize data
            var lis = _.find('li'); //Get all instance LI's
            var uls = lis.find('ul'); //Get all instance UL's
            _.data('superfish', {
              //Set namaspaced instance data
              timer: null,
              uls: uls,
              //Save all child UL dom nodes
              lis: lis
            })
            data = _.data('superfish'); //make it easy for the rest of init()
            }
            
            //Sanity Checks
             //Check if jQuery.superfish has already been intitialized
            
        if (data.initialized) {
          //console.warn('superfish already initialized on',this);
          //return this;
        }
        //make sure passed in element actually has submenus
        if (data.uls.length == 0) {
          //console.log('no ul\'s found on parent menu item, exiting');
          return this;
        }
        //Add root menu CSS class
        _.addClass(sf.c.menuClass)
        //Call onInit Callback
        o.onInit.call(null, _);
        //Add Arrows
        if (o.autoArrows) {
          $('li:has(ul)', _).addClass(sf.c.anchorClass).append(o.arrow);
        }
        //Set all UL's to hidden
        data.uls.hide();
        data.lis.delegate('a', 'mouseenter mouseleave', function(e) {
          //this is the event target, <a href="#"/>
          var $this = $(this),
              $li = $this.parent('li')
               $next = $this.next('ul');
          if (e.type == 'mouseenter') {
            //Clear Timeout
            clearTimeout(data.timer);
            //Clean up adjacent hover classes, but not the current xpath
            data.lis.not($li).not($li.parents()).removeClass(o.hoverClass);
            //Add hover class to current LI
            $li.addClass(o.hoverClass);
            //Find next UL and animate it
            if ($next.is(':hidden')) {
              o.onBeforeShow.call(null, $next);
              $next.animate(o.animIn, o.speedIn, o.easeIn, function() {
                o.onShow.call(null, $next);
              })
            }
          } else if (e.type == "mouseleave") {
            data.timer = setTimeout(function() {
              o.onBeforeHide.call(null, _);
              data.uls.animate(o.animOut, o.speedOut, o.easeOut, function() {
                o.onHide.call(null, _);
              });
              //Second timeout to run after animation is complete
              var anon = setTimeout(function() {
                data.uls.hide();
                data.lis.removeClass(o.hoverClass);
              }, o.speedOut);
            }, o.delay);

          } else {
            console.warn(' $(this), event.type', $(this), e.type)
          }
          e.preventDefault();
          e.stopPropagation();
          return false;
        });
        //@TODO
        if (o.pathClass !== sf.defaults.pathClass) {
          console.warn('@TODO pathClass enabled')
          $('li.' + o.pathClass, _).slice(0, o.pathLevels)
        }
        o.onAfterInit.call(null, _);
        data.initialized = true;
      }) //End jQuery.each
    },
    //END INIT METHOD
  } //End Methods
})(jQuery);
jQuery('ul.sf-menu').superfish();
ready

Revisions

You can edit these tests or add more tests to this page by appending /edit to the URL.