Skip to content

Instantly share code, notes, and snippets.

@joeldbirch
Created April 12, 2013 12:22
Show Gist options
  • Star 8 You must be signed in to star a gist
  • Fork 5 You must be signed in to fork a gist
  • Save joeldbirch/5371649 to your computer and use it in GitHub Desktop.
Save joeldbirch/5371649 to your computer and use it in GitHub Desktop.
Updated version of Supposition. This version is compatible with Superfish 1.6+. See this ancient page for description, example and caveats: http://users.tpg.com.au/j_birch/plugins/superfish/supposition-test/
/*
* Supposition v0.3a - an optional enhancer for Superfish jQuery menu widget
*
* Copyright (c) 2013 Joel Birch - based on work by Jesse Klaasse - credit goes largely to him.
* Special thanks to Karl Swedberg for valuable input.
*
* Dual licensed under the MIT and GPL licenses:
* http://www.opensource.org/licenses/mit-license.php
* http://www.gnu.org/licenses/gpl.html
*/
;(function($){
$.fn.supposition = function(){
var $w = $(window), /*do this once instead of every onBeforeShow call*/
_offset = function(dir) {
return window[dir == 'y' ? 'pageYOffset' : 'pageXOffset']
|| document.documentElement && document.documentElement[dir=='y' ? 'scrollTop' : 'scrollLeft']
|| document.body[dir=='y' ? 'scrollTop' : 'scrollLeft'];
},
onInit = function(){
/* I haven't touched this bit - needs work as there are still z-index issues */
$topNav = $('li',this);
var cZ=parseInt($topNav.css('z-index')) + $topNav.length;
$topNav.each(function() {
$(this).css({zIndex:--cZ});
});
},
onHide = function(){
this.css({marginTop:'',marginLeft:''});
},
onBeforeShow = function(){
this.each(function(){
var $u = $(this);
$u.css('display','block');
var menuWidth = $u.width(),
parentWidth = $u.parents('ul').width(),
totalRight = $w.width() + _offset('x'),
menuRight = $u.offset().left + menuWidth;
if (menuRight > totalRight) {
$u.css('margin-left', ($u.parents('ul').length == 1 ? totalRight - menuRight : -(menuWidth + parentWidth)) + 'px');
}
var windowHeight = $w.height(),
offsetTop = $u.offset().top,
menuHeight = $u.height(),
baseline = windowHeight + _offset('y');
var expandUp = (offsetTop + menuHeight > baseline);
if (expandUp) {
$u.css('margin-top',baseline - (menuHeight + offsetTop));
}
$u.css('display','none');
});
};
return this.each(function() {
var $this = $(this),
o = $this.data('sf-options'); /* get this menu's options */
/* if callbacks already set, store them */
var _onInit = o.onInit,
_onBeforeShow = o.onBeforeShow,
_onHide = o.onHide;
$.extend($this.data('sf-options'),{
onInit: function() {
onInit.call(this); /* fire our Supposition callback */
_onInit.call(this); /* fire stored callbacks */
},
onBeforeShow: function() {
onBeforeShow.call(this); /* fire our Supposition callback */
_onBeforeShow.call(this); /* fire stored callbacks */
},
onHide: function() {
onHide.call(this); /* fire our Supposition callback */
_onHide.call(this); /* fire stored callbacks */
}
});
});
};
})(jQuery);
@matrym
Copy link

matrym commented Jun 5, 2013

The current version with the most recent superfish.js can create a flash when used with hoverintent. This issue doesn't exist on the demo site, which uses older versions of each. I believe the issue may be with the latest hoverintent.

@mcpmbstu
Copy link

Hello Matrym, i faced the same issue, then i got the solution. here is the code with latest script i used.

jQuery('ul.sf-menu').superfish({
animation : { opacity:'show' }, /also works with 'height' etc./
onInit : jQuery.fn.supposition.onInit,
onBeforeShow : jQuery.fn.supposition.onBeforeShow,
onHide : jQuery.fn.supposition.onHide
});

hope this will help you. important to use "fn"

thanks

@joefaron
Copy link

solid addition.

@Matticus289
Copy link

I have found that IE10+ has a problem maintaining the position of the re-positioned nav items when used with superfish (happening up to version 1.7.5 of superfish). For example, if the child nav item would normally appear outside the browser window when its parent is hovered over and is given a negative margin left of -200px by suppostion() to correct it, it will suddenly lose the -200px margin the moment a link inside the element is clicked and not navigate to the clicked link. It moves back to it's normal position. Surprisingly, IE9 doesn't seem to have this problem.

A Live example:
http://www.wileyrein.com - try clicking on a menu item under "diversity" when you make your browser window small enough that the dropdown menu has to be re-positioned and you will see what I mean.

https://www.taylorenglish.com/ Same thing on the "careers" drop down.

@cemelmaci
Copy link

i think solition for flashing problem
52 $u.css('display','none'); to //$u.css('display','none');

thanks

@carasmo
Copy link

carasmo commented Nov 25, 2015

This works in the sense that it moves the menu, but the hovered menus that have children have to be hovered twice since it doesn't open the link on the first click.

@carasmo
Copy link

carasmo commented Nov 25, 2015

Never mind. It was a wordpress issue. Works great!

@imfaisalkh
Copy link

@cemelmaci Commenting out this line $u.css('display','none'); solves the flickering issue, but it also disables any animaion on the menu.

@moorthidaniel
Copy link

this plugin helped me to display sub menu items in the left side, if there is not enough screen space on the right
check out this post https://stackoverflow.com/a/47286812/202503

@namkazt
Copy link

namkazt commented Jan 16, 2020

for anyone that have issue with flashing and animation, replace onBeforeShow this only check for sub-menu and no need to set display to block to check.

onBeforeShow = function () {
                this.each(function () {
                    var $u = $(this);
                    var menuWidth = $u.width(),
                        parentWidth = $u.parents('ul').width(),
                        totalRight = $w.width() + _offset('x'),
                        menuRight = $u.offset().left + menuWidth;
                    if ($u.parents('li').hasClass('menu-has-children')) {
                        menuRight = $u.parents('ul').offset().left + menuWidth + $u.parents('ul').width()
                    }
                    if (menuRight > totalRight) {
                        $u.css('margin-left', ($u.parents('ul').length == 1 ? totalRight - menuRight : -(menuWidth + parentWidth)) + 'px');
                    }

                    var windowHeight = $w.height(),
                        offsetTop = $u.offset().top,
                        menuHeight = $u.height(),
                        baseline = windowHeight + _offset('y');
                    var expandUp = (offsetTop + menuHeight > baseline);
                    if (expandUp) {
                        $u.css('margin-top', baseline - (menuHeight + offsetTop));
                    }
                });
            };

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment