]> CyberLeo.Net >> Repos - Github/sugarcrm.git/blob - include/javascript/jquery/jquery.superfish.js
Release 6.5.0beta4
[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             if (!o.firstOnClick || menuActive || $$.parent()[0] != menu)
39             {
40                 clearTimeout(menu.sfTimer);
41                 $$.showSuperfishUl().siblings().hideSuperfishUl();
42                 if($$.parent().hasClass('megamenuSiblings')) {
43                         $$.parent().siblings().children('li').hideSuperfishUl();
44                 }
45             }
46         },
47         out = function() {
48             var $$ = $(this),
49             menu = getMenu($$),
50             o = sf.op,
51             $menu = $(menu);
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);
56                     $$.hideSuperfishUl();
57                     if (o.$path.length && $$.parents(['li.', o.hoverClass].join('')).length < 1)
58                     {
59                         over.call(o.$path);
60                     }
61                     else
62                     {
63                         menuActive = false;
64                     }
65                 }
66
67             },
68             o.delay);
69         },
70         getMenu = function($menu) {
71             var menu = $menu.hasClass(sf.menuClass) ? $menu[0] : $menu.parents(['ul.', c.menuClass, ':first'].join(''))[0];
72             if(!menu)
73                 return $menu[0];
74             sf.op = sf.o[menu.serial];
75             return menu;
76         },
77         addArrow = function($a) {
78             $a.addClass(c.anchorClass).append($arrow.clone());
79         };
80         sf.getMenu = getMenu;
81         return this.each(function() {
82             var s = this.serial = sf.o.length;
83             var o = $.extend({},
84             sf.defaults, op);
85             o.$path =
86             $('li.' + o.pathClass, this).slice(0, o.pathLevels).each
87             (function() {
88
89                 $(this).addClass([o.hoverClass, c.bcClass].join(' '))
90
91                 .filter('li:has(ul)').removeClass(o.pathClass);
92             });
93             sf.o[s] = sf.op = o;
94
95                         if(o.firstOnClick){
96                                 $('li:has(ul)', this).not('li:has( > .' + sf.ignoreClass + ')')['click'](click);
97                         } else {
98                                 $('li:has(ul)', this).not('li:has( > .' + sf.ignoreClass + ')')[($.fn.hoverIntent && !o.disableHI) ? 'hoverIntent' : 'hover'](over, out);
99                         }
100             
101             $('li:has(ul)', this)
102             .click(click)
103             .each(function() {
104                 if (o.autoArrows) addArrow(
105                 $('>a:first-child', this));
106             })
107             .not('.' + c.bcClass)
108             .hideSuperfishUl();
109
110             var $a = $('a', this);
111             $a.each(function(i) {
112                 var $li = $a.eq(i).parents('li');
113
114                 $a.eq(i).attr("tabindex",-1).focus(function() {
115                     over.call($li);
116                 }).blur(function()
117                 {
118                     out.call($li);
119                 });
120                 
121                 
122                 if(o.firstOnClick) {
123                         $a.eq(i).click(function(event)
124                         {
125                                           event.preventDefault();
126                                           if ( !$a.eq(i).hasClass("sf-with-ul") || $li.children('ul').size() == 0) {
127                                             SUGAR.ajaxUI.loadContent(this.href);
128                                           }
129                                         });
130                                         
131                                         
132                                         $a.eq(i).dblclick(function(event)
133                         {
134                             SUGAR.ajaxUI.loadContent(this.href);
135                                         });
136                 }
137                                 
138             });
139             o.onInit.call(this);
140
141         }).each(function() {
142             var menuClasses = [c.menuClass];
143             if (sf.op.dropShadows && !($.browser.msie &&
144             $.browser.version <
145             7)) menuClasses.push(c.shadowClass);
146             $(this).addClass(menuClasses.join(' '));
147         });
148     };
149
150     var sf = $.fn.superfish;
151     sf.o = [];
152     sf.op = {};
153     sf.counter = 0;
154     sf.IE7fix = function() {
155         var o = sf.op;
156         if ($.browser.msie && $.browser.version > 6 && o.dropShadows &&
157         o.animation.opacity != undefined)
158         this.toggleClass(sf.c.shadowClass + '-off');
159     };
160     
161      sf.positionMenu = function($ul) {
162         
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();
167                 
168                 if(submenuTop + submenuHeight > viewPortHeight) {
169                         this.css('top','auto');
170                         this.css('bottom','0px');
171                 } 
172         }
173     }
174     /**
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
180      */
181     sf.cssValue = function($css) {
182         if(this.length == 0)
183             return 0;
184         var _val = parseInt(this.css($css).replace("px", ""));
185         return (_val) ? _val : 0;
186     };
187     /**
188      * To support IE fixed size rendering,
189      * parse out dom elements out of the fixed element
190      *
191      * Prepare ===
192      * <div style=position:fixed>
193      *     ...
194      *     <li jquery-attached>
195      *         <ul style=position:absoulte>
196      *             ...
197      *         </ul>
198      *     </li>
199      * </div>
200      *
201      * Application ===
202      * <div style=position:fixed>
203      *     <li ul-child-id='auto-evaluted-id'>
204      *     ...
205      *     </li>
206      * </div>
207      *
208      * <ul id='auto-evaluted-id' style=position:fix;left/right/top-positioning:auto-calculated>
209      *     ...
210      * </ul>
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
214      */
215     sf.IEfix = function($ul) {
216         if ($.browser.msie && $.browser.version > 6) {
217             if($ul) {
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(){
221                     var $$ = $(this),
222                         o = sf.op,
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();
237                                 }, o.delay);
238                             });
239                     } else {
240                         _top += $$.outerHeight();
241                     }
242
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({
245                         top: _top,
246                         left:_left,
247                         position: 'fixed'
248                         }).on('mouseover',function(){
249                             //maintaining the dropdown container
250                             var menu = sf.getMenu($menu),
251                                 o = sf.op;
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),
258                                 o = sf.op;
259                             clearTimeout(menu.sfTimer);
260                             menu.sfTimer = setTimeout(function() {
261                                 $$.hideSuperfishUl();
262                                 $(menu).removeClass(sf.defaults['retainClass']);
263                             }, o.delay)
264                         })
265                     );
266                     $$.attr("ul-child-id", _id);
267                 });
268
269             } else {
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'));
274                 });
275             }
276         }
277     };
278     sf.c = {
279         bcClass: 'sf-breadcrumb',
280         menuClass: 'sf-js-enabled',
281         anchorClass: 'sf-with-ul',
282         arrowClass: 'sf-sub-indicator',
283         shadowClass: 'sf-shadow'
284     };
285     sf.defaults = {
286         hoverClass: 'sfHover',
287         retainClass: 'retainThisItem',
288         ignoreClass: 'none',
289         pathClass: 'overideThisToUse',
290         pathLevels: 8,
291         delay: 800,
292         animation: {
293             opacity: 'show'
294         },
295         speed: 'normal',
296         autoArrows: true,
297         dropShadows: true,
298         disableHI: false,
299         // true disables hoverIntent detection
300         onInit: function() {},
301         // callback functions
302         onBeforeShow: function() {},
303         onShow: function() {},
304         onHide: function() {},
305         firstOnClick: false
306         // true - open first level on click (like classic application menu)
307
308     };
309     $.fn.extend({
310         hideSuperfishUl: function() {
311             var o = sf.op,
312             not = (o.retainPath === true) ? o.$path: '';
313             o.retainPath = false;
314             sf.IEfix.call(this);
315             var $ul = $(['li.', o.hoverClass].join(''), this).add(this).not
316                 (not).removeClass(o.hoverClass).find('>ul').hide().css('visibility', 'hidden');
317             o.onHide.call($ul);
318             return this;
319         },
320         showSuperfishUl: function() {
321             var o = sf.op,
322             sh = sf.c.shadowClass + '-off',
323             $ul = this.addClass(o.hoverClass).find('>ul:hidden').show().css('visibility', 'visible');
324             sf.IE7fix.call($ul);
325             sf.positionMenu.call($ul);
326             o.onBeforeShow.call($ul);
327             sf.IEfix.call(this, $ul);
328             $ul.animate(o.animation, o.speed,
329             function() {
330                 sf.IE7fix.call($ul);
331                 o.onShow.call($ul);
332             });
333             return this;
334         }
335     });
336
337 })(jQuery);