]> CyberLeo.Net >> Repos - Github/sugarcrm.git/blob - include/javascript/jquery/jquery.superfish.js
Release 6.5.0beta6
[Github/sugarcrm.git] / include / javascript / jquery / jquery.superfish.js
1 /*
2 * Superfish v1.4.8 - jQuery menu widget
3 * Copyright (c) 2008 Joel Birch
4 *
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
8 *
9 * CHANGELOG: http://users.tpg.com.au/j_birch/plugins/superfish/changelog.txt
10 */
11
12 ; (function($) {
13     $.fn.superfish = function(op) {
14
15         var sf = $.fn.superfish,
16         c = sf.c,
17         menuActive = false,
18         $arrow = $(['<span class="', c.arrowClass, '"> &#187;</span>'].join('')),
19         click = function(evt) {
20                 $(".subnav.ddopen").hide();
21             var $$ = $(this),
22             menu = getMenu($$),
23             o = sf.op;
24             if (o.firstOnClick && !menuActive && $$.parent()[0] == menu)
25             {
26                 menuActive = true;
27                 clearTimeout(menu.sfTimer);
28
29                 $$.showSuperfishUl().siblings().hideSuperfishUl();
30                 // prevent redirect to anchor target href
31                 evt.preventDefault();
32             }
33         },
34         over = function() {
35             var $$ = $(this),
36             menu = getMenu($$),
37             o = sf.op;
38
39             if($$.parent().hasClass("hs-active")) {
40                 //Bug#51993: deactive submenu while hoverscroll is activated
41                 return;
42             }
43
44             if (!o.firstOnClick || menuActive || $$.parent()[0] != menu)
45             {
46                 clearTimeout(menu.sfTimer);
47                 $$.showSuperfishUl().siblings().hideSuperfishUl();
48                 if($$.parent().hasClass('megamenuSiblings')) {
49                         $$.parent().siblings().children('li').hideSuperfishUl();
50                 }
51             }
52         },
53         out = function() {
54             var $$ = $(this),
55             menu = getMenu($$),
56             o = sf.op,
57             $menu = $(menu);
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);
62                     $$.hideSuperfishUl();
63                     if (o.$path.length && $$.parents(['li.', o.hoverClass].join('')).length < 1)
64                     {
65                         over.call(o.$path);
66                     }
67                     else
68                     {
69                         menuActive = false;
70                     }
71                 }
72
73             },
74             o.delay);
75         },
76         getMenu = function($menu) {
77             var menu = $menu.hasClass(sf.menuClass) ? $menu[0] : $menu.parents(['ul.', c.menuClass, ':first'].join(''))[0];
78             if(!menu)
79                 return $menu[0];
80             sf.op = sf.o[menu.serial];
81             return menu;
82         },
83         addArrow = function($a) {
84             $a.addClass(c.anchorClass).append($arrow.clone());
85         };
86         sf.getMenu = getMenu;
87         return this.each(function() {
88             var s = this.serial = sf.o.length;
89             var o = $.extend({},
90             sf.defaults, op);
91             o.$path =
92             $('li.' + o.pathClass, this).slice(0, o.pathLevels).each
93             (function() {
94
95                 $(this).addClass([o.hoverClass, c.bcClass].join(' '))
96
97                 .filter('li:has(ul)').removeClass(o.pathClass);
98             });
99             sf.o[s] = sf.op = o;
100
101                         if(o.firstOnClick){
102                                 $('li:has(ul)', this).not('li:has( > .' + sf.ignoreClass + ')')['click'](click);
103                         } else {
104                                 $('li:has(ul)', this).not('li:has( > .' + sf.ignoreClass + ')')[($.fn.hoverIntent && !o.disableHI) ? 'hoverIntent' : 'hover'](over, out);
105                         }
106             
107             $('li:has(ul)', this)
108             .click(click)
109             .each(function() {
110                 if (o.autoArrows) addArrow(
111                 $('>a:first-child', this));
112             })
113             .not('.' + c.bcClass)
114             .hideSuperfishUl();
115
116             var $a = $('a', this);
117             $a.each(function(i) {
118                 var $li = $a.eq(i).parents('li');
119
120                 $a.eq(i).attr("tabindex",-1).focus(function() {
121                     over.call($li);
122                 }).blur(function()
123                 {
124                     out.call($li);
125                 });
126                 
127                 
128                 if(o.firstOnClick) {
129                         $a.eq(i).click(function(event)
130                         {
131                                           event.preventDefault();
132                                           if ( !$a.eq(i).hasClass("sf-with-ul") || $li.children('ul').size() == 0) {
133                                             SUGAR.ajaxUI.loadContent(this.href);
134                                           }
135                                         });
136                                         
137                                         
138                                         $a.eq(i).dblclick(function(event)
139                         {
140                             SUGAR.ajaxUI.loadContent(this.href);
141                                         });
142                 }
143                                 
144             });
145             o.onInit.call(this);
146
147         }).each(function() {
148             var menuClasses = [c.menuClass];
149             if (sf.op.dropShadows && !($.browser.msie &&
150             $.browser.version <
151             7)) menuClasses.push(c.shadowClass);
152             $(this).addClass(menuClasses.join(' '));
153         });
154     };
155
156     var sf = $.fn.superfish;
157     sf.o = [];
158     sf.op = {};
159     sf.counter = 0;
160     sf.IE7fix = function() {
161         var o = sf.op;
162         if ($.browser.msie && $.browser.version > 6 && o.dropShadows &&
163         o.animation.opacity != undefined)
164         this.toggleClass(sf.c.shadowClass + '-off');
165     };
166     
167      sf.positionMenu = function($ul) {
168         
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();
173                 
174                 if(submenuTop + submenuHeight > viewPortHeight) {
175                         this.css('top','auto');
176                         this.css('bottom','0px');
177                 } 
178         }
179     }
180     /**
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
186      */
187     sf.cssValue = function($css) {
188         if(this.length == 0)
189             return 0;
190         var _val = parseInt(this.css($css).replace("px", ""));
191         return (_val) ? _val : 0;
192     };
193     /**
194      * To support IE fixed size rendering,
195      * parse out dom elements out of the fixed element
196      *
197      * Prepare ===
198      * <div style=position:fixed>
199      *     ...
200      *     <li jquery-attached>
201      *         <ul style=position:absoulte>
202      *             ...
203      *         </ul>
204      *     </li>
205      * </div>
206      *
207      * Application ===
208      * <div style=position:fixed>
209      *     <li ul-child-id='auto-evaluted-id'>
210      *     ...
211      *     </li>
212      * </div>
213      *
214      * <ul id='auto-evaluted-id' style=position:fix;left/right/top-positioning:auto-calculated>
215      *     ...
216      * </ul>
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
220      */
221     sf.IEfix = function($ul) {
222         if ($.browser.msie && $.browser.version > 6) {
223             if($ul) {
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(){
227                     var $$ = $(this),
228                         o = sf.op,
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();
243                                 }, o.delay);
244                             });
245                     } else {
246                         _top += $$.outerHeight();
247                     }
248
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({
251                         top: _top,
252                         left:_left,
253                         position: 'fixed'
254                         }).on('mouseover',function(){
255                             //maintaining the dropdown container
256                             var menu = sf.getMenu($menu),
257                                 o = sf.op;
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),
264                                 o = sf.op;
265                             clearTimeout(menu.sfTimer);
266                             menu.sfTimer = setTimeout(function() {
267                                 $$.hideSuperfishUl();
268                                 $(menu).removeClass(sf.defaults['retainClass']);
269                             }, o.delay)
270                         })
271                     );
272                     $$.attr("ul-child-id", _id);
273                 });
274
275             } else {
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'));
280                 });
281             }
282         }
283     };
284     sf.c = {
285         bcClass: 'sf-breadcrumb',
286         menuClass: 'sf-js-enabled',
287         anchorClass: 'sf-with-ul',
288         arrowClass: 'sf-sub-indicator',
289         shadowClass: 'sf-shadow'
290     };
291     sf.defaults = {
292         hoverClass: 'sfHover',
293         retainClass: 'retainThisItem',
294         ignoreClass: 'none',
295         pathClass: 'overideThisToUse',
296         pathLevels: 8,
297         delay: 800,
298         animation: {
299             opacity: 'show'
300         },
301         speed: 'normal',
302         autoArrows: true,
303         dropShadows: true,
304         disableHI: false,
305         // true disables hoverIntent detection
306         onInit: function() {},
307         // callback functions
308         onBeforeShow: function() {},
309         onShow: function() {},
310         onHide: function() {},
311         firstOnClick: false
312         // true - open first level on click (like classic application menu)
313
314     };
315     $.fn.extend({
316         hideSuperfishUl: function() {
317             var o = sf.op,
318             not = (o.retainPath === true) ? o.$path: '';
319             o.retainPath = false;
320             sf.IEfix.call(this);
321             var $ul = $(['li.', o.hoverClass].join(''), this).add(this).not
322                 (not).removeClass(o.hoverClass).find('>ul').hide().css('visibility', 'hidden');
323             o.onHide.call($ul);
324             return this;
325         },
326         showSuperfishUl: function() {
327             var o = sf.op,
328             sh = sf.c.shadowClass + '-off',
329             $ul = this.addClass(o.hoverClass).find('>ul:hidden').show().css('visibility', 'visible');
330             sf.IE7fix.call($ul);
331             sf.positionMenu.call($ul);
332             o.onBeforeShow.call($ul);
333             sf.IEfix.call(this, $ul);
334             $ul.animate(o.animation, o.speed,
335             function() {
336                 sf.IE7fix.call($ul);
337                 o.onShow.call($ul);
338             });
339             return this;
340         }
341     });
342
343 })(jQuery);