]> CyberLeo.Net >> Repos - Github/sugarcrm.git/blob - include/javascript/jquery/jquery.superfish.js
Release 6.5.0RC1
[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             //Bug#52225: Activate submenu while hs-activated
39             if($$.parent().hasClass("hs-active")) {
40                 $$.addClass("iefix");
41             } else {
42                 $$.removeClass("iefix");
43             }
44
45             if (!o.firstOnClick || menuActive || $$.parent()[0] != menu)
46             {
47                 clearTimeout(menu.sfTimer);
48                 $$.showSuperfishUl().siblings().hideSuperfishUl();
49                 if($$.parent().hasClass('megamenuSiblings')) {
50                         $$.parent().siblings().children('li').hideSuperfishUl();
51                 }
52             }
53         },
54         out = function() {
55             var $$ = $(this),
56                 menu = getMenu($$),
57                 o = sf.op,
58                 $menu = $(menu);
59
60             if($$.parent().hasClass("hs-active")) {
61                 $$.addClass("iefix");
62                 setTimeout(function() {
63                     if($menu.hasClass(sf.defaults['retainClass']) === false)
64                         $$.hideSuperfishUl();
65                 }, o.delay);
66             } else {
67                 $$.removeClass("iefix");
68             }
69
70             clearTimeout(menu.sfTimer);
71             menu.sfTimer = $menu.hasClass(sf.defaults['retainClass']) ? null : setTimeout(function() {
72                 if($menu.hasClass(sf.defaults['retainClass']) === false) {
73                     o.retainPath = ($.inArray($$[0], o.$path) > -1);
74                     $$.hideSuperfishUl();
75                     if (o.$path.length && $$.parents(['li.', o.hoverClass].join('')).length < 1)
76                     {
77                         over.call(o.$path);
78                     }
79                     else
80                     {
81                         menuActive = false;
82                     }
83                 }
84
85             },
86             o.delay);
87         },
88         getMenu = function($menu) {
89             var menu = $menu.hasClass(sf.menuClass) ? $menu[0] : $menu.parents(['ul.', c.menuClass, ':first'].join(''))[0];
90             if(!menu)
91                 return $menu[0];
92             sf.op = sf.o[menu.serial];
93             return menu;
94         },
95         addArrow = function($a) {
96             $a.addClass(c.anchorClass).append($arrow.clone());
97         };
98         sf.getMenu = getMenu;
99         return this.each(function() {
100             var s = this.serial = sf.o.length;
101             var o = $.extend({},
102             sf.defaults, op);
103             o.$path =
104             $('li.' + o.pathClass, this).slice(0, o.pathLevels).each
105             (function() {
106
107                 $(this).addClass([o.hoverClass, c.bcClass].join(' '))
108
109                 .filter('li:has(ul)').removeClass(o.pathClass);
110             });
111             sf.o[s] = sf.op = o;
112
113                         if(o.firstOnClick){
114                                 $('li:has(ul)', this).not('li:has( > .' + sf.ignoreClass + ')')['click'](click);
115                         } else {
116                                 $('li:has(ul)', this).not('li:has( > .' + sf.ignoreClass + ')')[($.fn.hoverIntent && !o.disableHI) ? 'hoverIntent' : 'hover'](over, out);
117                         }
118             
119             $('li:has(ul)', this)
120             .click(click)
121             .each(function() {
122                 if (o.autoArrows) addArrow(
123                 $('>a:first-child', this));
124             })
125             .not('.' + c.bcClass)
126             .hideSuperfishUl();
127
128             var $a = $('a', this);
129             $a.each(function(i) {
130                 var $li = $a.eq(i).parents('li');
131
132                 $a.eq(i).attr("tabindex",-1).focus(function() {
133                     over.call($li);
134                 }).blur(function()
135                 {
136                     out.call($li);
137                 });
138                 
139                 
140                 if(o.firstOnClick) {
141                         $a.eq(i).click(function(event)
142                         {
143                                           event.preventDefault();
144                                           if ( !$a.eq(i).hasClass("sf-with-ul") || $li.children('ul').size() == 0) {
145                                             SUGAR.ajaxUI.loadContent(this.href);
146                                           }
147                                         });
148                                         
149                                         
150                                         $a.eq(i).dblclick(function(event)
151                         {
152                             SUGAR.ajaxUI.loadContent(this.href);
153                                         });
154                 }
155                                 
156             });
157             o.onInit.call(this);
158
159         }).each(function() {
160             var menuClasses = [c.menuClass];
161             if (sf.op.dropShadows && !($.browser.msie &&
162             $.browser.version <
163             7)) menuClasses.push(c.shadowClass);
164             $(this).addClass(menuClasses.join(' '));
165         });
166     };
167
168     var sf = $.fn.superfish;
169     sf.o = [];
170     sf.op = {};
171     sf.counter = 0;
172     sf.IE7fix = function() {
173         var o = sf.op;
174         if ($.browser.msie && $.browser.version > 6 && o.dropShadows &&
175         o.animation.opacity != undefined)
176         this.toggleClass(sf.c.shadowClass + '-off');
177     };
178     
179      sf.positionMenu = function($ul) {
180         
181         if(this.offset() && this.parent().parent().hasClass('sf-menu') != true) {
182         var viewPortHeight = $(window).height(),
183                 submenuHeight = this.outerHeight(),
184                 submenuTop = this.offset().top - $(document).scrollTop();
185                 
186                 if(submenuTop + submenuHeight > viewPortHeight) {
187                         this.css('top','auto');
188                         this.css('bottom','0px');
189                 } 
190         }
191     }
192     /**
193      * Return css property variale which contains numerical data.
194      * i.e. width, border, padding-left, etc.
195      * @param this - element that is trying to retrive
196      * @param $css - css properity which contains numerical data
197      * @return int - value of the size
198      */
199     sf.cssValue = function($css) {
200         if(this.length == 0)
201             return 0;
202         var _val = parseInt(this.css($css).replace("px", ""));
203         return (_val) ? _val : 0;
204     };
205     /**
206      * To support IE fixed size rendering,
207      * parse out dom elements out of the fixed element
208      *
209      * Prepare ===
210      * <div style=position:fixed>
211      *     ...
212      *     <li jquery-attached>
213      *         <ul style=position:absoulte>
214      *             ...
215      *         </ul>
216      *     </li>
217      * </div>
218      *
219      * Application ===
220      * <div style=position:fixed>
221      *     <li ul-child-id='auto-evaluted-id'>
222      *     ...
223      *     </li>
224      * </div>
225      *
226      * <ul id='auto-evaluted-id' style=position:fix;left/right/top-positioning:auto-calculated>
227      *     ...
228      * </ul>
229      * @param this - element container which is inside the fixed box model
230      * @param $ul - dropdown box model which needs to render out of the fixed box range
231      *              if $ul is not given, it will restore back to the original structure
232      */
233     sf.IEfix = function($ul) {
234         if ( ($.browser.msie && $.browser.version > 6) || $(this).hasClass("iefix") ) {
235             if($ul) {
236                 //Take out the element out of the fixed box model,
237                 //and then append it into the end of body container
238                 this.each(function(){
239                     var $$ = $(this),
240                         o = sf.op,
241                         _id = $$.attr("ul-child-id") ? $$.attr("ul-child-id") : ($ul.attr('id')) ? $ul.attr('id') : o.megamenuID ? o.megamenuID + ++sf.counter : 'megamenu' + ++sf.counter,
242                         _top = $$.position().top + $$.parent().offset().top - $(document).scrollTop(),
243                         _left = $$.offset().left - sf.cssValue.call($ul, "border-left-width"),
244                         $menu = $('ul.' + sf.c.menuClass + ':visible');
245                     //handling sub-sliding menu
246                     if($$.css('position') == 'static' || $$.parent().hasClass('megamenuSiblings')) {
247                         _left += $$.outerWidth() + sf.cssValue.call($ul, "border-right-width");
248                         $ul.addClass('sf-sub-modulelist').on('mouseover', function(){
249                                 $$.addClass(sf.defaults['retainClass']);
250                             }).on('mouseout', function(){
251                                 $$.removeClass(sf.defaults['retainClass']);
252                                 $('ul.' + sf.c.menuClass + ':visible').removeClass(sf.defaults['retainClass'])[0].sfTimer = setTimeout(function(){
253                                     $$.hideSuperfishUl();
254                                     $('ul.' + sf.c.menuClass + ':visible > li').hideSuperfishUl();
255                                 }, o.delay);
256                             });
257                     } else {
258                         _top += $$.outerHeight();
259                     }
260
261                     //append the item into the body element, and then save the id to restore back later
262                     $('body').append($ul.attr("id", _id).css({
263                         top: _top,
264                         left:_left,
265                         position: 'fixed'
266                         }).on('mouseover',function(){
267                             //maintaining the dropdown container
268                             var menu = sf.getMenu($menu),
269                                 o = sf.op;
270                             clearTimeout(menu.sfTimer);
271                             if( $(menu).hasClass(sf.defaults['retainClass']) === false )
272                                 $(menu).addClass(sf.defaults['retainClass']);
273                         }).on('mouseout', function(){
274                             //clear out the dropdown menu
275                             var menu = sf.getMenu($menu),
276                                 o = sf.op;
277                             clearTimeout(menu.sfTimer);
278
279                             menu.sfTimer = setTimeout(function() {
280                                 $$.hideSuperfishUl();
281                                 $(menu).removeClass(sf.defaults['retainClass']);
282                                 $(menu).hideSuperfishUl();
283                             }, o.delay)
284                         })
285                     );
286                     $$.attr("ul-child-id", _id);
287                 });
288
289             } else {
290                 //restore back the element to the original structure
291                 this.each(function(){
292                     var _id = $(this).attr("ul-child-id");
293                     $(this).append($("body>#"+_id).off('mouseover mouseout'));
294                 });
295             }
296         }
297     };
298     sf.c = {
299         bcClass: 'sf-breadcrumb',
300         menuClass: 'sf-js-enabled',
301         anchorClass: 'sf-with-ul',
302         arrowClass: 'sf-sub-indicator',
303         shadowClass: 'sf-shadow'
304     };
305     sf.defaults = {
306         hoverClass: 'sfHover',
307         retainClass: 'retainThisItem',
308         ignoreClass: 'none',
309         pathClass: 'overideThisToUse',
310         pathLevels: 8,
311         delay: 800,
312         animation: {
313             opacity: 'show'
314         },
315         speed: 'normal',
316         autoArrows: true,
317         dropShadows: true,
318         disableHI: false,
319         // true disables hoverIntent detection
320         onInit: function() {},
321         // callback functions
322         onBeforeShow: function() {},
323         onShow: function() {},
324         onHide: function() {},
325         firstOnClick: false
326         // true - open first level on click (like classic application menu)
327
328     };
329     $.fn.extend({
330         hideSuperfishUl: function() {
331             var o = sf.op,
332             not = (o.retainPath === true) ? o.$path: '';
333             o.retainPath = false;
334             sf.IEfix.call(this);
335             var $ul = $(['li.', o.hoverClass].join(''), this).add(this).not
336                 (not).removeClass(o.hoverClass).find('>ul').hide().css('visibility', 'hidden');
337             o.onHide.call($ul);
338             return this;
339         },
340         showSuperfishUl: function() {
341             var o = sf.op,
342             sh = sf.c.shadowClass + '-off',
343             $ul = this.addClass(o.hoverClass).find('>ul:hidden').show().css('visibility', 'visible');
344             sf.IE7fix.call($ul);
345             sf.positionMenu.call($ul);
346             o.onBeforeShow.call($ul);
347             sf.IEfix.call(this, $ul);
348             $ul.animate(o.animation, o.speed,
349             function() {
350                 sf.IE7fix.call($ul);
351                 o.onShow.call($ul);
352             });
353             return this;
354         }
355     });
356
357 })(jQuery);