2 * Superfish v1.4.8 - jQuery menu widget
3 * Copyright (c) 2008 Joel Birch
5 * Dual licensed under the MIT and GPL licenses:
6 * http://www.opensource.org/licenses/mit-license.php
7 * http://www.gnu.org/licenses/gpl.html
9 * CHANGELOG: http://users.tpg.com.au/j_birch/plugins/superfish/changelog.txt
13 $.fn.superfish = function(op) {
15 var sf = $.fn.superfish,
18 $arrow = $(['<span class="', c.arrowClass, '"> »</span>'].join('')),
19 click = function(evt) {
20 $(".subnav.ddopen").hide();
24 if (o.firstOnClick && !menuActive && $$.parent()[0] == menu)
27 clearTimeout(menu.sfTimer);
29 $$.showSuperfishUl().siblings().hideSuperfishUl();
30 // prevent redirect to anchor target href
39 if($$.parent().hasClass("hs-active")) {
40 //Bug#51993: deactive submenu while hoverscroll is activated
44 if (!o.firstOnClick || menuActive || $$.parent()[0] != menu)
46 clearTimeout(menu.sfTimer);
47 $$.showSuperfishUl().siblings().hideSuperfishUl();
48 if($$.parent().hasClass('megamenuSiblings')) {
49 $$.parent().siblings().children('li').hideSuperfishUl();
58 clearTimeout(menu.sfTimer);
59 menu.sfTimer = $menu.hasClass(sf.defaults['retainClass']) ? null : setTimeout(function() {
60 if($menu.hasClass(sf.defaults['retainClass']) === false) {
61 o.retainPath = ($.inArray($$[0], o.$path) > -1);
63 if (o.$path.length && $$.parents(['li.', o.hoverClass].join('')).length < 1)
76 getMenu = function($menu) {
77 var menu = $menu.hasClass(sf.menuClass) ? $menu[0] : $menu.parents(['ul.', c.menuClass, ':first'].join(''))[0];
80 sf.op = sf.o[menu.serial];
83 addArrow = function($a) {
84 $a.addClass(c.anchorClass).append($arrow.clone());
87 return this.each(function() {
88 var s = this.serial = sf.o.length;
92 $('li.' + o.pathClass, this).slice(0, o.pathLevels).each
95 $(this).addClass([o.hoverClass, c.bcClass].join(' '))
97 .filter('li:has(ul)').removeClass(o.pathClass);
102 $('li:has(ul)', this).not('li:has( > .' + sf.ignoreClass + ')')['click'](click);
104 $('li:has(ul)', this).not('li:has( > .' + sf.ignoreClass + ')')[($.fn.hoverIntent && !o.disableHI) ? 'hoverIntent' : 'hover'](over, out);
107 $('li:has(ul)', this)
110 if (o.autoArrows) addArrow(
111 $('>a:first-child', this));
113 .not('.' + c.bcClass)
116 var $a = $('a', this);
117 $a.each(function(i) {
118 var $li = $a.eq(i).parents('li');
120 $a.eq(i).attr("tabindex",-1).focus(function() {
129 $a.eq(i).click(function(event)
131 event.preventDefault();
132 if ( !$a.eq(i).hasClass("sf-with-ul") || $li.children('ul').size() == 0) {
133 SUGAR.ajaxUI.loadContent(this.href);
138 $a.eq(i).dblclick(function(event)
140 SUGAR.ajaxUI.loadContent(this.href);
148 var menuClasses = [c.menuClass];
149 if (sf.op.dropShadows && !($.browser.msie &&
151 7)) menuClasses.push(c.shadowClass);
152 $(this).addClass(menuClasses.join(' '));
156 var sf = $.fn.superfish;
160 sf.IE7fix = function() {
162 if ($.browser.msie && $.browser.version > 6 && o.dropShadows &&
163 o.animation.opacity != undefined)
164 this.toggleClass(sf.c.shadowClass + '-off');
167 sf.positionMenu = function($ul) {
169 if(this.offset() && this.parent().parent().hasClass('sf-menu') != true) {
170 var viewPortHeight = $(window).height(),
171 submenuHeight = this.outerHeight(),
172 submenuTop = this.offset().top - $(document).scrollTop();
174 if(submenuTop + submenuHeight > viewPortHeight) {
175 this.css('top','auto');
176 this.css('bottom','0px');
181 * Return css property variale which contains numerical data.
182 * i.e. width, border, padding-left, etc.
183 * @param this - element that is trying to retrive
184 * @param $css - css properity which contains numerical data
185 * @return int - value of the size
187 sf.cssValue = function($css) {
190 var _val = parseInt(this.css($css).replace("px", ""));
191 return (_val) ? _val : 0;
194 * To support IE fixed size rendering,
195 * parse out dom elements out of the fixed element
198 * <div style=position:fixed>
200 * <li jquery-attached>
201 * <ul style=position:absoulte>
208 * <div style=position:fixed>
209 * <li ul-child-id='auto-evaluted-id'>
214 * <ul id='auto-evaluted-id' style=position:fix;left/right/top-positioning:auto-calculated>
217 * @param this - element container which is inside the fixed box model
218 * @param $ul - dropdown box model which needs to render out of the fixed box range
219 * if $ul is not given, it will restore back to the original structure
221 sf.IEfix = function($ul) {
222 if ($.browser.msie && $.browser.version > 6) {
224 //Take out the element out of the fixed box model,
225 //and then append it into the end of body container
226 this.each(function(){
229 _id = $$.attr("ul-child-id") ? $$.attr("ul-child-id") : ($ul.attr('id')) ? $ul.attr('id') : o.megamenuID ? o.megamenuID + ++sf.counter : 'megamenu' + ++sf.counter,
230 _top = $$.position().top + $$.parent().position().top,
231 _left = $$.offset().left - sf.cssValue.call($ul, "border-left-width"),
232 $menu = $('ul.' + sf.c.menuClass + ':visible');
233 //handling sub-sliding menu
234 if($$.css('position') == 'static' || $$.parent().hasClass('megamenuSiblings')) {
235 _left += $$.outerWidth() + sf.cssValue.call($ul, "border-right-width");
236 $ul.addClass('sf-sub-modulelist').on('mouseover', function(){
237 $$.addClass(sf.defaults['retainClass']);
238 }).on('mouseout', function(){
239 $$.removeClass(sf.defaults['retainClass']);
240 $('ul.' + sf.c.menuClass + ':visible').removeClass(sf.defaults['retainClass'])[0].sfTimer = setTimeout(function(){
241 $$.hideSuperfishUl();
242 $('ul.' + sf.c.menuClass + ':visible > li').hideSuperfishUl();
246 _top += $$.outerHeight();
249 //append the item into the body element, and then save the id to restore back later
250 $('body').append($ul.attr("id", _id).css({
254 }).on('mouseover',function(){
255 //maintaining the dropdown container
256 var menu = sf.getMenu($menu),
258 clearTimeout(menu.sfTimer);
259 if( $(menu).hasClass(sf.defaults['retainClass']) === false )
260 $(menu).addClass(sf.defaults['retainClass']);
261 }).on('mouseout', function(){
262 //clear out the dropdown menu
263 var menu = sf.getMenu($menu),
265 clearTimeout(menu.sfTimer);
266 menu.sfTimer = setTimeout(function() {
267 $$.hideSuperfishUl();
268 $(menu).removeClass(sf.defaults['retainClass']);
272 $$.attr("ul-child-id", _id);
276 //restore back the element to the original structure
277 this.each(function(){
278 var _id = $(this).attr("ul-child-id");
279 $(this).append($("body>#"+_id).off('mouseover mouseout'));
285 bcClass: 'sf-breadcrumb',
286 menuClass: 'sf-js-enabled',
287 anchorClass: 'sf-with-ul',
288 arrowClass: 'sf-sub-indicator',
289 shadowClass: 'sf-shadow'
292 hoverClass: 'sfHover',
293 retainClass: 'retainThisItem',
295 pathClass: 'overideThisToUse',
305 // true disables hoverIntent detection
306 onInit: function() {},
307 // callback functions
308 onBeforeShow: function() {},
309 onShow: function() {},
310 onHide: function() {},
312 // true - open first level on click (like classic application menu)
316 hideSuperfishUl: function() {
318 not = (o.retainPath === true) ? o.$path: '';
319 o.retainPath = false;
321 var $ul = $(['li.', o.hoverClass].join(''), this).add(this).not
322 (not).removeClass(o.hoverClass).find('>ul').hide().css('visibility', 'hidden');
326 showSuperfishUl: function() {
328 sh = sf.c.shadowClass + '-off',
329 $ul = this.addClass(o.hoverClass).find('>ul:hidden').show().css('visibility', 'visible');
331 sf.positionMenu.call($ul);
332 o.onBeforeShow.call($ul);
333 sf.IEfix.call(this, $ul);
334 $ul.animate(o.animation, o.speed,