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
38 if (!o.firstOnClick || menuActive || $$.parent()[0] != menu)
40 clearTimeout(menu.sfTimer);
41 $$.showSuperfishUl().siblings().hideSuperfishUl();
42 if($$.parent().hasClass('megamenuSiblings')) {
43 $$.parent().siblings().children('li').hideSuperfishUl();
52 clearTimeout(menu.sfTimer);
53 menu.sfTimer = $menu.hasClass(sf.defaults['retainClass']) ? null : setTimeout(function() {
54 if($menu.hasClass(sf.defaults['retainClass']) === false) {
55 o.retainPath = ($.inArray($$[0], o.$path) > -1);
57 if (o.$path.length && $$.parents(['li.', o.hoverClass].join('')).length < 1)
70 getMenu = function($menu) {
71 var menu = $menu.hasClass(sf.menuClass) ? $menu[0] : $menu.parents(['ul.', c.menuClass, ':first'].join(''))[0];
74 sf.op = sf.o[menu.serial];
77 addArrow = function($a) {
78 $a.addClass(c.anchorClass).append($arrow.clone());
81 return this.each(function() {
82 var s = this.serial = sf.o.length;
86 $('li.' + o.pathClass, this).slice(0, o.pathLevels).each
89 $(this).addClass([o.hoverClass, c.bcClass].join(' '))
91 .filter('li:has(ul)').removeClass(o.pathClass);
96 $('li:has(ul)', this).not('li:has( > .' + sf.ignoreClass + ')')['click'](click);
98 $('li:has(ul)', this).not('li:has( > .' + sf.ignoreClass + ')')[($.fn.hoverIntent && !o.disableHI) ? 'hoverIntent' : 'hover'](over, out);
101 $('li:has(ul)', this)
104 if (o.autoArrows) addArrow(
105 $('>a:first-child', this));
107 .not('.' + c.bcClass)
110 var $a = $('a', this);
111 $a.each(function(i) {
112 var $li = $a.eq(i).parents('li');
114 $a.eq(i).attr("tabindex",-1).focus(function() {
123 $a.eq(i).click(function(event)
125 event.preventDefault();
126 if ( !$a.eq(i).hasClass("sf-with-ul") || $li.children('ul').size() == 0) {
127 SUGAR.ajaxUI.loadContent(this.href);
132 $a.eq(i).dblclick(function(event)
134 SUGAR.ajaxUI.loadContent(this.href);
142 var menuClasses = [c.menuClass];
143 if (sf.op.dropShadows && !($.browser.msie &&
145 7)) menuClasses.push(c.shadowClass);
146 $(this).addClass(menuClasses.join(' '));
150 var sf = $.fn.superfish;
154 sf.IE7fix = function() {
156 if ($.browser.msie && $.browser.version > 6 && o.dropShadows &&
157 o.animation.opacity != undefined)
158 this.toggleClass(sf.c.shadowClass + '-off');
161 sf.positionMenu = function($ul) {
163 if(this.offset() && this.parent().parent().hasClass('sf-menu') != true) {
164 var viewPortHeight = $(window).height(),
165 submenuHeight = this.outerHeight(),
166 submenuTop = this.offset().top - $(document).scrollTop();
168 if(submenuTop + submenuHeight > viewPortHeight) {
169 this.css('top','auto');
170 this.css('bottom','0px');
175 * Return css property variale which contains numerical data.
176 * i.e. width, border, padding-left, etc.
177 * @param this - element that is trying to retrive
178 * @param $css - css properity which contains numerical data
179 * @return int - value of the size
181 sf.cssValue = function($css) {
184 var _val = parseInt(this.css($css).replace("px", ""));
185 return (_val) ? _val : 0;
188 * To support IE fixed size rendering,
189 * parse out dom elements out of the fixed element
192 * <div style=position:fixed>
194 * <li jquery-attached>
195 * <ul style=position:absoulte>
202 * <div style=position:fixed>
203 * <li ul-child-id='auto-evaluted-id'>
208 * <ul id='auto-evaluted-id' style=position:fix;left/right/top-positioning:auto-calculated>
211 * @param this - element container which is inside the fixed box model
212 * @param $ul - dropdown box model which needs to render out of the fixed box range
213 * if $ul is not given, it will restore back to the original structure
215 sf.IEfix = function($ul) {
216 if ($.browser.msie && $.browser.version > 6) {
218 //Take out the element out of the fixed box model,
219 //and then append it into the end of body container
220 this.each(function(){
223 _id = $$.attr("ul-child-id") ? $$.attr("ul-child-id") : ($ul.attr('id')) ? $ul.attr('id') : o.megamenuID ? o.megamenuID + ++sf.counter : 'megamenu' + ++sf.counter,
224 _top = $$.position().top + $$.parent().position().top,
225 _left = $$.offset().left - sf.cssValue.call($ul, "border-left-width"),
226 $menu = $('ul.' + sf.c.menuClass + ':visible');
227 //handling sub-sliding menu
228 if($$.css('position') == 'static' || $$.parent().hasClass('megamenuSiblings')) {
229 _left += $$.outerWidth() + sf.cssValue.call($ul, "border-right-width");
230 $ul.addClass('sf-sub-modulelist').on('mouseover', function(){
231 $$.addClass(sf.defaults['retainClass']);
232 }).on('mouseout', function(){
233 $$.removeClass(sf.defaults['retainClass']);
234 $('ul.' + sf.c.menuClass + ':visible').removeClass(sf.defaults['retainClass'])[0].sfTimer = setTimeout(function(){
235 $$.hideSuperfishUl();
236 $('ul.' + sf.c.menuClass + ':visible > li').hideSuperfishUl();
240 _top += $$.outerHeight();
243 //append the item into the body element, and then save the id to restore back later
244 $('body').append($ul.attr("id", _id).css({
248 }).on('mouseover',function(){
249 //maintaining the dropdown container
250 var menu = sf.getMenu($menu),
252 clearTimeout(menu.sfTimer);
253 if( $(menu).hasClass(sf.defaults['retainClass']) === false )
254 $(menu).addClass(sf.defaults['retainClass']);
255 }).on('mouseout', function(){
256 //clear out the dropdown menu
257 var menu = sf.getMenu($menu),
259 clearTimeout(menu.sfTimer);
260 menu.sfTimer = setTimeout(function() {
261 $$.hideSuperfishUl();
262 $(menu).removeClass(sf.defaults['retainClass']);
266 $$.attr("ul-child-id", _id);
270 //restore back the element to the original structure
271 this.each(function(){
272 var _id = $(this).attr("ul-child-id");
273 $(this).append($("body>#"+_id).off('mouseover mouseout'));
279 bcClass: 'sf-breadcrumb',
280 menuClass: 'sf-js-enabled',
281 anchorClass: 'sf-with-ul',
282 arrowClass: 'sf-sub-indicator',
283 shadowClass: 'sf-shadow'
286 hoverClass: 'sfHover',
287 retainClass: 'retainThisItem',
289 pathClass: 'overideThisToUse',
299 // true disables hoverIntent detection
300 onInit: function() {},
301 // callback functions
302 onBeforeShow: function() {},
303 onShow: function() {},
304 onHide: function() {},
306 // true - open first level on click (like classic application menu)
310 hideSuperfishUl: function() {
312 not = (o.retainPath === true) ? o.$path: '';
313 o.retainPath = false;
315 var $ul = $(['li.', o.hoverClass].join(''), this).add(this).not
316 (not).removeClass(o.hoverClass).find('>ul').hide().css('visibility', 'hidden');
320 showSuperfishUl: function() {
322 sh = sf.c.shadowClass + '-off',
323 $ul = this.addClass(o.hoverClass).find('>ul:hidden').show().css('visibility', 'visible');
325 sf.positionMenu.call($ul);
326 o.onBeforeShow.call($ul);
327 sf.IEfix.call(this, $ul);
328 $ul.animate(o.animation, o.speed,