1//** Smooth Navigational Menu- By Dynamic Drive DHTML code library: http://www.dynamicdrive.com 2//** Script Download/ instructions page: http://www.dynamicdrive.com/dynamicindex1/ddlevelsmenu/ 3//** Menu created: Nov 12, 2008 4 5//** Dec 12th, 08" (v1.01): Fixed Shadow issue when multiple LIs within the same UL (level) contain sub menus: http://www.dynamicdrive.com/forums/showthread.php?t=39177&highlight=smooth 6 7//** Feb 11th, 09" (v1.02): The currently active main menu item (LI A) now gets a CSS class of ".selected", including sub menu items. 8 9//** May 1st, 09" (v1.3): 10//** 1) Now supports vertical (side bar) menu mode- set "orientation" to 'v' 11//** 2) In IE6, shadows are now always disabled 12 13//** July 27th, 09" (v1.31): Fixed bug so shadows can be disabled if desired. 14//** Feb 2nd, 10" (v1.4): Adds ability to specify delay before sub menus appear and disappear, respectively. See showhidedelay variable below 15 16//** Dec 17th, 10" (v1.5): Updated menu shadow to use CSS3 box shadows when the browser is FF3.5+, IE9+, Opera9.5+, or Safari3+/Chrome. Only .js file changed. 17 18//** Jun 28th, 2012: Unofficial update adds optional hover images for down and right arrows in the format: filename_over.ext 19//** These must be present for whichever or both of the arrow(s) are used and will preload. 20 21//** Dec 23rd, 2012 Unofficial update to fixed configurable z-index, add method option to init "toggle" which activates on click or "hover" 22//** which activates on mouse over/out - defaults to "toggle" (click activation), with detection of touch devices to activate on click for them. 23//** Add option for when there are two or more menus using "toggle" activation, whether or not all previously opened menus collapse 24//** on new menu activation, or just those within that specific menu 25//** See: http://www.dynamicdrive.com/forums/showthread.php?72449-PLEASE-HELP-with-Smooth-Navigational-Menu-(v1-51)&p=288466#post288466 26 27//** Feb 7th, 2013 Unofficial update change fixed configurable z-index back to graduated for cases of main UL wrapping. Update off menu click detection in 28//** ipad/iphone to touchstart because document click wasn't registering. see: http://www.dynamicdrive.com/forums/showthread.php?72825 29 30//** Feb 14th, 2013 Add window.ontouchstart to means tests for detecting touch browsers - thanks DD! 31//** Feb 15th, 2013 Add 'ontouchstart' in window and 'ontouchstart' in document.documentElement to means tests for detecting touch browsers - thanks DD! 32 33//** Feb 20th, 2013 correct for IE 9+ sometimes adding a pixel to the offsetHeight of the top level trigger for horizontal menus 34//** Feb 23rd, 2013 move CSS3 shadow adjustment for IE 9+ to the script, add resize event for all browsers to reposition open toggle 35//** menus and shadows in window if they would have gone to a different position at the new window dimensions 36//** Feb 25th, 2013 (v2.0) All unofficial updates by John merged into official and now called v2.0. Changed "method" option's default value to "hover" 37//** May 14th, 2013 (v2.1) Adds class 'repositioned' to menus moved due to being too close to the browser's right edge 38//** May 30th, 2013 (v2.1) Change from version sniffing to means testing for jQuery versions which require added code for click toggle event handling 39//** Sept 15th, 2013 add workaround for false positives for touch on Chrome 40//** Sept 22nd, 2013 (v2.2) Add vertical repositioning if sub menu will not fit in the viewable vertical area. May be turned off by setting 41// repositionv: false, 42//** in the init. Sub menus that are vertically repositioned will have the class 'repositionedv' added to them. 43//** March 17th, 15' (v3.0): Adds fully mobile friendly, compact version of menu that's activated in mobile and small screen browsers. 44//** Refines drop down menu behaviour when there's neither space to the right nor left to accommodate sub menu; in that case sub menu overlaps parent menu. 45//** Nov 3rd, 15' (v3.01): Fixed long drop down menus causing a vertical document scrollbar when page loads 46//** April 1st, 16' (v3.02): Fixed Chrome desktop falsely reporting as touch enabled, requiring clicking on menu items to drop down. 47var ddsmoothmenu = { 48 49///////////////////////// Global Configuration Options: ///////////////////////// 50 51mobilemediaquery: "screen and (max-width: 700px)", // CSS media query string that when matched activates mobile menu (while hiding default) 52//Specify full URL to down and right arrow images (23 is padding-right for top level LIs with drop downs, 6 is for vertical top level items with fly outs): 53arrowimages: {down:['downarrowclass', '/sites/all/themes/ntemplate/ddsmoothmenu/space.gif', 0], right:['rightarrowclass', '/sites/all/themes/ntemplate/ddsmoothmenu/right.png', 0], left:['leftarrowclass', '/sites/all/themes/ntemplate/ddsmoothmenu/left.gif']}, 54transition: {overtime:300, outtime:300}, //duration of slide in/ out animation, in milliseconds 55mobiletransition: 200, // duration of slide animation in mobile menu, in milliseconds 56shadow: false, //enable shadow? (offsets now set in ddsmoothmenu.css stylesheet) 57showhidedelay: {showdelay: 100, hidedelay: 200}, //set delay in milliseconds before sub menus appear and disappear, respectively 58zindexvalue: 999, //set z-index value for menus 59closeonnonmenuclick: true, //when clicking outside of any "toggle" method menu, should all "toggle" menus close? 60closeonmouseout: false, //when leaving a "toggle" menu, should all "toggle" menus close? Will not work on touchscreen 61
62/////////////////////// End Global Configuration Options //////////////////////// 63 64overarrowre: /(?=\.(gif|jpg|jpeg|png|bmp))/i, 65overarrowaddtofilename: '', 66detecttouch: !!('ontouchstart' in window) || !!('ontouchstart' in document.documentElement) || !!window.ontouchstart || (!!window.Touch && !!window.Touch.length) || !!window.onmsgesturechange || (window.DocumentTouch && window.document instanceof window.DocumentTouch), 67detectwebkit: navigator.userAgent.toLowerCase().indexOf("applewebkit") > -1, //detect WebKit browsers (Safari, Chrome etc) 68detectchrome: navigator.userAgent.toLowerCase().indexOf("chrome") > -1, //detect chrome 69ismobile: navigator.userAgent.match(/(iPad)|(iPhone)|(iPod)|(android)|(webOS)/i) != null, //boolean check for popular mobile browsers 70idevice: /ipad|iphone/i.test(navigator.userAgent), 71detectie6: (function(){var ie; return (ie = /MSIE (\d+)/.exec(navigator.userAgent)) && ie[1] < 7;})(), 72detectie9: (function(){var ie; return (ie = /MSIE (\d+)/.exec(navigator.userAgent)) && ie[1] > 8;})(), 73ie9shadow: function(){}, 74css3support: typeof document.documentElement.style.boxShadow === 'string' || (!document.all && document.querySelector), //detect browsers that support CSS3 box shadows (ie9+ or FF3.5+, Safari3+, Chrome etc) 75prevobjs: [], menus: null, 76mobilecontainer: {$main: null, $topulsdiv: null, $toggler: null, hidetimer: null}, 77mobilezindexvalue: 2000, // mobile menus starting zIndex 78 79executelink: function($, prevobjs, e){ 80 var prevscount = prevobjs.length, link = e.target; 81 while(--prevscount > -1){ 82 if(prevobjs[prevscount] === this){ 83 prevobjs.splice(prevscount, 1); 84 if(link.href !== ddsmoothmenu.emptyhash && link.href && $(link).is('a') && !$(link).children('span.' + ddsmoothmenu.arrowimages.down[0] +', span.' + ddsmoothmenu.arrowimages.right[0]).length){ 85 if(link.target && link.target !== '_self'){ 86 window.open(link.href, link.target); 87 } else { 88 window.location.href = link.href; 89 } 90 e.stopPropagation(); 91 } 92 } 93 } 94}, 95 96repositionv: function($subul, $link, newtop, winheight, doctop, method, menutop){ 97 menutop = menutop || 0; 98 var topinc = 0, doclimit = winheight + doctop; 99 $subul.css({top: newtop, display: 'block'}); 100 while($subul.offset().top < doctop) { 101 $subul.css({top: ++newtop}); 102 ++topinc; 103 } 104 if(!topinc && $link.offset().top + $link.outerHeight() < doclimit && $subul.data('height') + $subul.offset().top > doclimit){ 105 $subul.css({top: doctop - $link.parents('ul').last().offset().top - $link.position().top}); 106 } 107 method === 'toggle' && $subul.css({display: 'none'}); 108 if(newtop !== menutop){$subul.addClass('repositionedv');} 109 return [topinc, newtop]; 110}, 111 112updateprev: function($, prevobjs, $curobj){ 113 var prevscount = prevobjs.length, prevobj, $indexobj = $curobj.parents().add(this); 114 while(--prevscount > -1){ 115 if($indexobj.index((prevobj = prevobjs[prevscount])) < 0){ 116 $(prevobj).trigger('click', [1]); 117 prevobjs.splice(prevscount, 1); 118 } 119 } 120 prevobjs.push(this); 121}, 122 123subulpreventemptyclose: function(e){ 124 var link = e.target; 125 if(link.href === ddsmoothmenu.emptyhash && $(link).parent('li').find('ul').length < 1){ 126 e.preventDefault(); 127 e.stopPropagation(); 128 } 129}, 130 131getajaxmenu: function($, setting, nobuild){ //function to fetch external page containing the panel DIVs 132 var $menucontainer=$('#'+setting.contentsource[0]); //reference empty div on page that will hold menu 133 $menucontainer.html("Loading Menu..."); 134 $.ajax({ 135 url: setting.contentsource[1], //path to external menu file 136 async: true, 137 dataType: 'html', 138 error: function(ajaxrequest){ 139 setting.menustate = "error" 140 $menucontainer.html('Error fetching content. Server Response: '+ajaxrequest.responseText); 141 }, 142 success: function(content){ 143 setting.menustate = "fetched" 144 $menucontainer.html(content).find('#' + setting.mainmenuid).css('display', 'block'); 145 !!!nobuild && ddsmoothmenu.buildmenu($, setting); 146 } 147 }); 148}, 149 150getajaxmenuMobile: function($, setting){ //function to fetch external page containing the primary menu UL 151 setting.mobilemenustate = 'fetching' 152 $.ajax({ 153 url: setting.contentsource[1], //path to external menu file 154 async: true, 155 dataType: 'html', 156 error: function(ajaxrequest){ 157 setting.mobilemenustate = 'error' 158 alert("Error fetching Ajax content " + ajaxrequest.responseText) 159 }, 160 success: function(content){ 161 var $ul = $(content).find('>ul') 162 setting.mobilemenustate = 'fetched' 163 ddsmoothmenu.buildmobilemenu($, setting, $ul); 164 } 165 }); 166}, 167 168closeall: function(e){ 169 var smoothmenu = ddsmoothmenu, prevscount; 170 if(!smoothmenu.globaltrackopen){return;} 171 if(e.type === 'mouseleave' || ((e.type === 'click' || e.type === 'touchstart') && smoothmenu.menus.index(e.target) < 0)){ 172 prevscount = smoothmenu.prevobjs.length; 173 while(--prevscount > -1){ 174 $(smoothmenu.prevobjs[prevscount]).trigger('click'); 175 smoothmenu.prevobjs.splice(prevscount, 1); 176 } 177 } 178}, 179 180emptyhash: $('<a href="#"></a>').get(0).href, 181 182togglemobile: function(action, duration){ 183 if (!this.mobilecontainer.$main) 184 return 185 clearTimeout(this.mobilecontainer.hidetimer) 186 var $mobilemenu = this.mobilecontainer.$main 187 var duration = duration || this.mobiletransition 188 if ($mobilemenu.css('visibility') == 'hidden' && (!action || action == 'open')){ 189 $mobilemenu.css({right: '-100%', visibility: 'visible'}).animate({right: 0}, duration) 190 this.mobilecontainer.$toggler.addClass('open') 191 } 192 else if ($mobilemenu.css('visibility') == 'visible' && (!action || action != 'open')){ 193 $mobilemenu.animate({right: '-100%'}, duration, function(){this.style.visibility = 'hidden'}) 194 this.mobilecontainer.$toggler.removeClass('open') 195 } 196 return false 197 198}, 199 200buildmobilemenu: function($, setting, $ul){ 201 202 function flattenuls($mainul, cloneulBol, callback, finalcall){ 203 var callback = callback || function(){} 204 var finalcall = finalcall || function(){} 205 var $headers = $mainul.find('ul').parent() 206 var $mainulcopy = cloneulBol? $mainul.clone() : $mainul 207 var $flattened = jQuery(document.createDocumentFragment()) 208 var $headers = $mainulcopy.find('ul').parent() 209 for (var i=$headers.length-1; i>=0; i--){ // loop through headers backwards, so we end up with topmost UL last 210 var $header = $headers.eq(i) 211 var $subul = $header.find('>ul').prependTo($flattened) 212 callback(i, $header, $subul) 213 } 214 $mainulcopy.prependTo($flattened) // Add top most UL to collection 215 finalcall($mainulcopy) 216 return $flattened 217 } 218 219 var $mainmenu = $('#' + setting.mainmenuid) 220 var $mainul = $ul 221 var $topulref = null 222 223 var flattened = flattenuls($mainul, false, 224 function(i, $header, $subul){ // loop through header LIs and sub ULs 225 $subul.addClass("submenu") 226 var $breadcrumb = $('<li class="breadcrumb" />') 227 .html('<img src="' + ddsmoothmenu.arrowimages.left[1] +'" class="' + ddsmoothmenu.arrowimages.left[0] +'" />' + $header.text()) 228 .prependTo($subul) 229 $header.find('a:eq(0)').append('<img src="' + ddsmoothmenu.arrowimages.right[1] +'" class="' + ddsmoothmenu.arrowimages.right[0] +'" />') 230 $header.on('click', function(e){ 231 var $headermenu = $(this).parent('ul') 232 $headermenu = $headermenu.hasClass('submenu')? $headermenu : $headermenu.parent() 233 $headermenu.css({zIndex: ddsmoothmenu.mobilezindexvalue++, left: 0}).animate({right: '-100%'}, ddsmoothmenu.mobiletransition) 234 $subul.css({zIndex: ddsmoothmenu.mobilezindexvalue++, left: '100%'}).animate({left: 0}, ddsmoothmenu.mobiletransition) 235 e.stopPropagation() 236 e.preventDefault() 237 }) 238 $breadcrumb.on('click', function(e){ 239 var $headermenu = $header.parent('ul') 240 $headermenu = $headermenu.hasClass('submenu')? $headermenu : $headermenu.parent() 241 $headermenu.css({zIndex: ddsmoothmenu.mobilezindexvalue++, right: '-100%'}).animate({left: 0}, ddsmoothmenu.mobiletransition) 242 $subul.css({zIndex: ddsmoothmenu.mobilezindexvalue++, left: 0}).animate({left: '100%'}, ddsmoothmenu.mobiletransition) 243 e.stopPropagation() 244 e.preventDefault() 245 }) 246 }, 247 function($topul){ 248 $topulref = $topul 249 } 250 ) 251 252 253 if (!this.mobilecontainer.$main){ // if primary mobile menu container not defined yet
254 var $maincontainer = $('<div class="ddsmoothmobile"><div class="topulsdiv"></div></div>').appendTo(document.body) 255 $maincontainer 256 .css({zIndex: this.mobilezindexvalue++, right: '-100%', visibility: 'hidden'}) 257 .on('click', function(e){ // assign click behavior to mobile container 258 ddsmoothmenu.mobilecontainer.hidetimer = setTimeout(function(){ 259 ddsmoothmenu.togglemobile('close', 0) 260 }, 50) 261 e.stopPropagation() 262 }) 263 .on('touchstart', function(e){ 264 e.stopPropagation() 265 }) 266 var $topulsdiv = $maincontainer.find('div.topulsdiv') 267 var $mobiletoggler = $('#ddsmoothmenu-mobiletoggle').css({display: 'block'}) 268 $mobiletoggler 269 .on('click', function(e){ // assign click behavior to main mobile menu toggler 270 ddsmoothmenu.togglemobile() 271 e.stopPropagation() 272 }) 273 .on('touchstart', function(e){ 274 e.stopPropagation() 275 }) 276 var hidemobilemenuevent = /(iPad|iPhone|iPod)/g.test( navigator.userAgent )? 'touchstart' : 'click' // ios doesnt seem to respond to clicks on BODY 277 $(document.body).on(hidemobilemenuevent, function(e){ 278 if (!$maincontainer.is(':animated')) 279 ddsmoothmenu.togglemobile('close', 0) 280 }) 281 282 this.mobilecontainer.$main = $maincontainer 283 this.mobilecontainer.$topulsdiv = $topulsdiv 284 this.mobilecontainer.$toggler = $mobiletoggler 285 } 286 else{ // else, just reference mobile container on page 287 var $maincontainer = this.mobilecontainer.$main 288 var $topulsdiv = this.mobilecontainer.$topulsdiv 289 } 290 $topulsdiv.append($topulref).css({zIndex: this.mobilezindexvalue++}) 291 $maincontainer.append(flattened) 292 293 setting.mobilemenustate = 'done' 294 295 296}, 297 298buildmenu: function($, setting){ 299 // additional step to detect true touch support. Chrome desktop mistakenly returns true for this.detecttouch 300 var detecttruetouch = (this.detecttouch && !this.detectchrome) || (this.detectchrome && this.ismobile) 301 var smoothmenu = ddsmoothmenu; 302 smoothmenu.globaltrackopen = smoothmenu.closeonnonmenuclick || smoothmenu.closeonmouseout; 303 var zsub = 0; //subtractor to be incremented so that each top level menu can be covered by previous one's drop downs 304 var prevobjs = smoothmenu.globaltrackopen? smoothmenu.prevobjs : []; 305 var $mainparent = $("#"+setting.mainmenuid).removeClass("ddsmoothmenu ddsmoothmenu-v").addClass(setting.classname || "ddsmoothmenu"); 306 setting.repositionv = setting.repositionv !== false; 307 var $mainmenu = $mainparent.find('>ul'); //reference main menu UL 308 var method = (detecttruetouch)? 'toggle' : setting.method === 'toggle'? 'toggle' : 'hover'; 309 var $topheaders = $mainmenu.find('>li>ul').parent();//has('ul'); 310 var orient = setting.orientation!='v'? 'down' : 'right', $parentshadow = $(document.body); 311 $mainmenu.click(function(e){e.target.href === smoothmenu.emptyhash && e.preventDefault();}); 312 if(method === 'toggle') { 313 if(smoothmenu.globaltrackopen){ 314 smoothmenu.menus = smoothmenu.menus? smoothmenu.menus.add($mainmenu.add($mainmenu.find('*'))) : $mainmenu.add($mainmenu.find('*')); 315 } 316 if(smoothmenu.closeonnonmenuclick){ 317 if(orient === 'down'){$mainparent.click(function(e){e.stopPropagation();});} 318 $(document).unbind('click.smoothmenu').bind('click.smoothmenu', smoothmenu.closeall); 319 if(smoothmenu.idevice){ 320 document.removeEventListener('touchstart', smoothmenu.closeall, false); 321 document.addEventListener('touchstart', smoothmenu.closeall, false); 322 } 323 } else if (setting.closeonnonmenuclick){ 324 if(orient === 'down'){$mainparent.click(function(e){e.stopPropagation();});} 325 $(document).bind('click.' + setting.mainmenuid, function(e){$mainmenu.find('li>a.selected').parent().trigger('click');}); 326 if(smoothmenu.idevice){ 327 document.addEventListener('touchstart', function(e){$mainmenu.find('li>a.selected').parent().trigger('click');}, false); 328 } 329 } 330 if(smoothmenu.closeonmouseout){ 331 var $leaveobj = orient === 'down'? $mainparent : $mainmenu; 332 $leaveobj.bind('mouseleave.smoothmenu', smoothmenu.closeall); 333 } else if (setting.closeonmouseout){ 334 var $leaveobj = orient === 'down'? $mainparent : $mainmenu; 335 $leaveobj.bind('mouseleave.smoothmenu', function(){$mainmenu.find('li>a.selected').parent().trigger('click');}); 336 } 337 if(!$('style[title="ddsmoothmenushadowsnone"]').length){ 338 $('head').append('<style title="ddsmoothmenushadowsnone" type="text/css">.ddsmoothmenushadowsnone{display:none!important;}</style>'); 339 } 340 var shadowstimer; 341 $(window).bind('resize scroll', function(){ 342 clearTimeout(shadowstimer); 343 var $selected = $mainmenu.find('li>a.selected').parent(), 344 $shadows = $('.ddshadow').addClass('ddsmoothmenushadowsnone'); 345 $selected.eq(0).trigger('click'); 346 $selected.trigger('click');
347 if ( !window.matchMedia || (window.matchMedia && !setting.mobilemql.matches)) 348 shadowstimer = setTimeout(function(){$shadows.removeClass('ddsmoothmenushadowsnone');}, 100); 349 }); 350 } 351 352 $topheaders.each(function(){ 353 var $curobj=$(this).css({zIndex: (setting.zindexvalue || smoothmenu.zindexvalue) + zsub--}); //reference current LI header 354 var $subul=$curobj.children('ul:eq(0)').css({display:'block'}).data('timers', {}); 355 var $link = $curobj.children("a:eq(0)").css({paddingRight: smoothmenu.arrowimages[orient][2]}).append( //add arrow images 356 '<span style="display: block;" class="' + smoothmenu.arrowimages[orient][0] + '"></span>' 357 ); 358 var dimensions = { 359 w : $link.outerWidth(), 360 h : $curobj.innerHeight(), 361 subulw : $subul.outerWidth(), 362 subulh : $subul.outerHeight() 363 }; 364 var menutop = orient === 'down'? dimensions.h : 0; 365 $subul.css({top: menutop}); 366 function restore(){$link.removeClass('selected');} 367 method === 'toggle' && $subul.click(smoothmenu.subulpreventemptyclose); 368 $curobj[method]( 369 function(e){ 370 if(!$curobj.data('headers')){ 371 smoothmenu.buildsubheaders($, $subul, $subul.find('>li>ul').parent(), setting, method, prevobjs); 372 $curobj.data('headers', true).find('>ul').each(function(i, ul){ 373 var $ul = $(ul); 374 $ul.data('height', $ul.outerHeight()); 375 }).css({display:'none', visibility:'visible'}); 376 } 377 method === 'toggle' && smoothmenu.updateprev.call(this, $, prevobjs, $curobj); 378 clearTimeout($subul.data('timers').hidetimer); 379 $link.addClass('selected'); 380 $subul.data('timers').showtimer=setTimeout(function(){ 381 var menuleft = orient === 'down'? 0 : dimensions.w; 382 var menumoved = menuleft, newtop, doctop, winheight, topinc = 0; 383 var offsetLeft = $curobj.offset().left 384 menuleft=(offsetLeft+menuleft+dimensions.subulw>$(window).width())? (orient === 'down'? -dimensions.subulw+dimensions.w : -dimensions.w) : menuleft; 385//calculate this sub menu's offsets from its parent 386 if (orient === 'right' && menuleft < 0){ // for vertical menu, if top level sub menu drops left, test to see if it'll be obscured by left window edge 387 var scrollX = window.pageXOffset || (document.documentElement || document.body.parentNode || document.body).scrollLeft 388 if (offsetLeft - dimensions.subulw < 0) // if menu will be obscured by left window edge 389 menuleft = 0 390 } 391 menumoved = menumoved !== menuleft; 392 $subul.css({top: menutop}).removeClass('repositionedv');
393 if(setting.repositionv && $link.offset().top + menutop + $subul.data('height') > (winheight = $(window).height()) + (doctop = $(document).scrollTop())){ 394 newtop = (orient === 'down'? 0 : $link.outerHeight()) - $subul.data('height'); 395 topinc = smoothmenu.repositionv($subul, $link, newtop, winheight, doctop, method, menutop)[0]; 396 } 397 $subul.css({left:menuleft, width:dimensions.subulw}).stop(true, true).animate({height:'show',opacity:'show'}, smoothmenu.transition.overtime, function(){this.style.removeAttribute && this.style.removeAttribute('filter');}); 398 if(menumoved){$subul.addClass('repositioned');} else {$subul.removeClass('repositioned');} 399 if (setting.shadow){ 400 if(!$curobj.data('$shadow')){ 401 $curobj.data('$shadow', $('<div></div>').addClass('ddshadow toplevelshadow').prependTo($parentshadow).css({zIndex: $curobj.css('zIndex')})); //insert shadow DIV and set it to parent node for the next shadow div 402 } 403 smoothmenu.ie9shadow($curobj.data('$shadow')); 404 var offsets = $subul.offset(); 405 var shadowleft = offsets.left; 406 var shadowtop = offsets.top; 407 $curobj.data('$shadow').css({overflow: 'visible', width:dimensions.subulw, left:shadowleft, top:shadowtop}).stop(true, true).animate({height:dimensions.subulh}, smoothmenu.transition.overtime); 408 } 409 }, smoothmenu.showhidedelay.showdelay); 410 }, 411 function(e, speed){ 412 var $shadow = $curobj.data('$shadow'); 413 if(method === 'hover'){restore();} 414 else{smoothmenu.executelink.call(this, $, prevobjs, e);} 415 clearTimeout($subul.data('timers').showtimer); 416 $subul.data('timers').hidetimer=setTimeout(function(){ 417 $subul.stop(true, true).animate({height:'hide', opacity:'hide'}, speed || smoothmenu.transition.outtime, function(){method === 'toggle' && restore();}); 418 if ($shadow){ 419 if (!smoothmenu.css3support && smoothmenu.detectwebkit){ //in WebKit browsers, set first child shadow's opacity to 0, as "overflow:hidden" doesn't work in them 420 $shadow.children('div:eq(0)').css({opacity:0}); 421 } 422 $shadow.stop(true, true).animate({height:0}, speed || smoothmenu.transition.outtime, function(){if(method === 'toggle'){this.style.overflow = 'hidden';}}); 423 } 424 }, smoothmenu.showhidedelay.hidedelay); 425 } 426 ); //end hover/toggle 427 $subul.css({display: 'none'}); // collapse sub UL 428 }); //end $topheaders.each() 429}, 430 431buildsubheaders: function($, $subul, $headers, setting, method, prevobjs){ 432 //setting.$mainparent.data('$headers').add($headers); 433 $subul.css('display', 'block'); 434 $headers.each(function(){ //loop through each LI header 435 var smoothmenu = ddsmoothmenu; 436 var $curobj=$(this).css({zIndex: $(this).parent('ul').css('z-index')}); //reference current LI header 437 var $subul=$curobj.children('ul:eq(0)').css({display:'block'}).data('timers', {}), $parentshadow; 438 method === 'toggle' && $subul.click(smoothmenu.subulpreventemptyclose); 439 var $link = $curobj.children("a:eq(0)").append( //add arrow images 440 '<span style="display: block;" class="' + smoothmenu.arrowimages['right'][0] + '"></span>' 441 ); 442 var dimensions = { 443 w : $link.outerWidth(), 444 subulw : $subul.outerWidth(), 445 subulh : $subul.outerHeight() 446 }; 447 $subul.css({top: 0}); 448 function restore(){$link.removeClass('selected');} 449 $curobj[method]( 450 function(e){ 451 if(!$curobj.data('headers')){ 452 smoothmenu.buildsubheaders($, $subul, $subul.find('>li>ul').parent(), setting, method, prevobjs); 453 $curobj.data('headers', true).find('>ul').each(function(i, ul){ 454 var $ul = $(ul); 455 $ul.data('height', $ul.height()); 456 }).css({display:'none', visibility:'visible'}); 457 } 458 method === 'toggle' && smoothmenu.updateprev.call(this, $, prevobjs, $curobj); 459 clearTimeout($subul.data('timers').hidetimer); 460 $link.addClass('selected'); 461 $subul.data('timers').showtimer=setTimeout(function(){ 462 var menuleft= dimensions.w; 463 var menumoved = menuleft, newtop, doctop, winheight, topinc = 0; 464 var offsetLeft = $curobj.offset().left 465 menuleft=(offsetLeft+menuleft+dimensions.subulw>$(window).width())? -dimensions.w : menuleft; //calculate this sub menu's offsets from its parent 466 if (menuleft < 0){ // if drop left, test to see if it'll be obscured by left window edge 467 var scrollX = window.pageXOffset || (document.documentElement || document.body.parentNode || document.body).scrollLeft 468 if (offsetLeft - dimensions.subulw < scrollX) // if menu will be obscured by left window edge 469 menuleft = 0 470 } 471 menumoved = menumoved !== menuleft; 472 473 $subul.css({top: 0}).removeClass('repositionedv'); 474 if(setting.repositionv && $link.offset().top + $subul.data('height') > (winheight = $(window).height()) + (doctop = $(document).scrollTop())){ 475 newtop = $link.outerHeight() - $subul.data('height'); 476 topinc = smoothmenu.repositionv($subul, $link, newtop, winheight, doctop, method); 477 newtop = topinc[1]; 478 topinc = topinc[0]; 479 } 480 $subul.css({left:menuleft, width:dimensions.subulw}).stop(true, true).animate({height:'show',opacity:'show'}
480, smoothmenu.transition.overtime, function(){this.style.removeAttribute && this.style.removeAttribute('filter');}); 481 if(menumoved){$subul.addClass('repositioned');} else {$subul.removeClass('repositioned');} 482 if (setting.shadow){ 483 if(!$curobj.data('$shadow')){ 484 $parentshadow = $curobj.parents("li:eq(0)").data('$shadow'); 485 $curobj.data('$shadow', $('<div></div>').addClass('ddshadow').prependTo($parentshadow).css({zIndex: $parentshadow.css('z-index')})); //insert shadow DIV and set it to parent node for the next shadow div 486 } 487 var offsets = $subul.offset(); 488 var shadowleft = menuleft; 489 var shadowtop = $curobj.position().top - (newtop? $subul.data('height') - $link.outerHeight() - topinc : 0); 490 if (smoothmenu.detectwebkit && !smoothmenu.css3support){ //in WebKit browsers, restore shadow's opacity to full 491 $curobj.data('$shadow').css({opacity:1}); 492 } 493 $curobj.data('$shadow').css({overflow: 'visible', width:dimensions.subulw, left:shadowleft, top:shadowtop}).stop(true, true).animate({height:dimensions.subulh}, smoothmenu.transition.overtime); 494 } 495 }, smoothmenu.showhidedelay.showdelay); 496 }, 497 function(e, speed){ 498 var $shadow = $curobj.data('$shadow'); 499 if(method === 'hover'){restore();} 500 else{smoothmenu.executelink.call(this, $, prevobjs, e);} 501 clearTimeout($subul.data('timers').showtimer); 502 $subul.data('timers').hidetimer=setTimeout(function(){ 503 $subul.stop(true, true).animate({height:'hide', opacity:'hide'}, speed || smoothmenu.transition.outtime, function(){ 504 method === 'toggle' && restore(); 505 }); 506 if ($shadow){ 507 if (!smoothmenu.css3support && smoothmenu.detectwebkit){ //in WebKit browsers, set first child shadow's opacity to 0, as "overflow:hidden" doesn't work in them 508 $shadow.children('div:eq(0)').css({opacity:0}); 509 } 510 $shadow.stop(true, true).animate({height:0}, speed || smoothmenu.transition.outtime, function(){if(method === 'toggle'){this.style.overflow = 'hidden';}}); 511 } 512 }, smoothmenu.showhidedelay.hidedelay); 513 } 514 ); //end hover/toggle for subheaders 515 }); //end $headers.each() for subheaders 516}, 517 518 519initmenu: function(setting){ 520 if (setting.mobilemql.matches){ // if mobile mode 521 jQuery(function($){ 522 var $mainmenu = $('#' + setting.mainmenuid) 523 $mainmenu.css({display: 'none'}) // hide regular menu 524 //setTimeout(function(){$('.ddshadow').addClass('ddsmoothmenushadowsnone')}, 150) 525 if (!setting.$mainulclone){ // store a copy of the main menu's UL menu before it gets manipulated 526 setting.$mainulclone = $mainmenu.find('>ul').clone() 527 } 528 var mobilemenustate = setting.mobilemenustate 529 if (setting.contentsource == "markup" && !mobilemenustate){ // if mobile menu not built yet 530 ddsmoothmenu.buildmobilemenu($, setting, setting.$mainulclone) 531 } 532 else if (setting.contentsource != "markup" && (!mobilemenustate || mobilemenustate == "error")){ // if Ajax content and mobile menu not built yet 533 ddsmoothmenu.getajaxmenuMobile($, setting) 534 } 535 else{ // if mobile menu built already, just show mobile togger 536 $('#ddsmoothmenu-mobiletoggle').css({display: 'block'}) 537 } 538 }) 539 return 540 } 541 else{ // if desktop mode 542 var menustate = setting.menustate 543 if (menustate && menustate != "error"){ // if menustate is anything other than "error" (meaning error fetching ajax content), it means menu's built already, so exit init() 544 var $mainmenu = $('#' + setting.mainmenuid) 545 $mainmenu.css({display: 'block'}) // show regular menu 546 if (this.mobilecontainer.$main){ // if mobile menu defined, hide it 547 this.togglemobile('close', 0) 548 } 549 $('#ddsmoothmenu-mobiletoggle').css({display: 'none'}) // hide mobile menu toggler 550 return 551 } 552 } 553 554 if(this.detectie6 && parseFloat(jQuery.fn.jquery) > 1.3){ 555 this.initmenu = function(setting){ 556 if (typeof setting.contentsource=="object"){ //if external ajax menu 557 jQuery(function($){ddsmoothmenu.getajaxmenu($, setting, 'nobuild');}); 558 } 559 return false; 560 }; 561 jQuery('link[href*="ddsmoothmenu"]').attr('disabled', true); 562 jQuery(function($){ 563 alert('You Seriously Need to Update Your Browser!\n\nDynamic Drive Smooth Navigational Menu Showing Text Only Menu(s)\n\nDEVELOPER\'s NOTE: This script will run in IE 6 when using jQuery 1.3.2 or less,\nbut not real well.'); 564 $('link[href*="ddsmoothmenu"]').attr('disabled', true); 565 }); 566 return this.initmenu(setting); 567 } 568 var mainmenuid = '#' + setting.mainmenuid, right, down, stylestring = ['</style>\n'], stylesleft = setting.arrowswap? 4 : 2; 569 function addstyles(){ 570 if(stylesleft){return;} 571 if (typeof setting.customtheme=="object" && setting.customtheme.length==2){ //override default menu colors (default/hover) with custom set? 572 var mainselector=(setting.orientation=="v")? mainmenuid : mainmenuid+', '+mainmenuid; 573 stylestring.push([mainselector,' ul li a {background:',setting.customtheme[0],';}\n', 574 mainmenuid,' ul li a:hover {background:',setting.customtheme[1],';}'].join('')); 575 } 576 stylestring.push('\n<style type="text/css">'); 577 stylestring.reverse(); 578 jQuery('head').append(stylestring.join('\n')); 579 } 580 if(setting.arrowswap){ 581 right = ddsmoothmenu.arrowimages.right[1].replace(ddsmoothmenu.overarrowre, ddsmoothmenu.overarrowaddtofilename); 582 down = ddsmoothmenu.arrowimages.down[1].replace(ddsmoothmenu.overarrowre, ddsmoothmenu.overarrowaddtofilename); 583 jQuery(new Image()).bind('load error', function(e){ 584 setting.rightswap = e.type === 'load'; 585 if(setting.rightswap){ 586 stylestring.push([mainmenuid, ' ul li a:hover .', ddsmoothmenu.arrowimages.right[0], ', ', 587 mainmenuid, ' ul li a.selected .', ddsmoothmenu.arrowimages.right[0], 588 ' { background-image: url(', this.src, ');}'].join('')); 589 } 590 --stylesleft; 591 addstyles(); 592 }).attr('src', right); 593 jQuery(new Image()).bind('load error', function(e){ 594 setting.downswap = e.type === 'load'; 595 if(setting.downswap){ 596 stylestring.push([mainmenuid, ' ul li a:hover .', ddsmoothmenu.arrowimages.down[0], ', ', 597 mainmenuid, ' ul li a.selected .', ddsmoothmenu.arrowimages.down[0], 598 ' { background-image: url(', this.src, ');}'].join('')); 599 } 600 --stylesleft; 601 addstyles(); 602 }).attr('src', down); 603 } 604 jQuery(new Image()).bind('load error', function(e){ 605 if(e.type === 'load'){ 606 stylestring.push([mainmenuid+' ul li a .', ddsmoothmenu.arrowimages.right[0],' { background: url(', this.src, ') no-repeat;width:', this.width,'px;height:', this.height, 'px;}'].join('')); 607 } 608 --stylesleft; 609 addstyles(); 610 }).attr('src', ddsmoothmenu.arrowimages.right[1]); 611 jQuery(new Image()).bind('load error', function(e){ 612 if(e.type === 'load'){ 613 stylestring.push([mainmenuid+' ul li a .', ddsmoothmenu.arrowimages.down[0],' { background: url(', this.src, ') no-repeat;width:', this.width,'px;height:', this.height, 'px;}'].join('')); 614 } 615 --stylesleft; 616 addstyles(); 617 }).attr('src', ddsmoothmenu.arrowimages.down[1]);
618 setting.shadow = this.detectie6 && (setting.method === 'hover' || setting.orientation === 'v')? false : setting.shadow || this.shadow; //in IE6, always disable shadow except for horizontal toggle menus 619 jQuery(document).ready(function($){ 620 var $mainmenu = $('#' + setting.mainmenuid) 621 $mainmenu.css({display: 'block'}) // show regular menu (in case previously hidden by mobile menu activation) 622 if (ddsmoothmenu.mobilecontainer.$main){ // if mobile menu defined, hide it 623 ddsmoothmenu.togglemobile('close', 0) 624 } 625 $('#ddsmoothmenu-mobiletoggle').css({display: 'none'}) // hide mobile menu toggler 626 if (!setting.$mainulclone){ // store a copy of the main menu's UL menu before it gets manipulated 627 setting.$mainulclone = $mainmenu.find('>ul').clone() 628 } 629 if (setting.shadow && ddsmoothmenu.css3support){$('body').addClass('ddcss3support');} 630 if (typeof setting.contentsource=="object"){ //if external ajax menu 631 ddsmoothmenu.getajaxmenu($, setting); 632 } 633 else{ //else if markup menu 634 ddsmoothmenu.buildmenu($, setting); 635 } 636 637 setting.menustate = "initialized" // set menu state to initialized 638 }); 639}, 640 641init: function(setting){ 642 setting.mobilemql = (window.matchMedia)? window.matchMedia(this.mobilemediaquery) : {matches: false, addListener: function(){}} 643 this.initmenu(setting) 644 setting.mobilemql.addListener(function(){ 645 ddsmoothmenu.initmenu(setting) 646 }) 647} 648}; //end ddsmoothmenu variable 649 650 651// Patch for jQuery 1.9+ which lack click toggle (deprecated in 1.8, removed in 1.9) 652// Will not run if using another patch like jQuery Migrate, which also takes care of this 653if( 654 (function($){ 655 var clicktogglable = false; 656 try { 657 $('<a href="#"></a>').toggle(function(){}, function(){clicktogglable = true;}).trigger('click').trigger('click'); 658 } catch(e){} 659 return !clicktogglable; 660 })(jQuery) 661){ 662 (function(){ 663 var toggleDisp = jQuery.fn.toggle; // There's an animation/css method named .toggle() that toggles display. Save a reference to it. 664 jQuery.extend(jQuery.fn, { 665 toggle: function( fn, fn2 ) { 666 // The method fired depends on the arguments passed. 667 if ( !jQuery.isFunction( fn ) || !jQuery.isFunction( fn2 ) ) { 668 return toggleDisp.apply(this, arguments); 669 } 670 // Save reference to arguments for access in closure 671 var args = arguments, guid = fn.guid || jQuery.guid++, 672 i = 0, 673 toggler = function( event ) { 674 // Figure out which function to execute 675 var lastToggle = ( jQuery._data( this, "lastToggle" + fn.guid ) || 0 ) % i; 676 jQuery._data( this, "lastToggle" + fn.guid, lastToggle + 1 ); 677 678 // Make sure that clicks stop 679 event.preventDefault(); 680 681 // and execute the function 682 return args[ lastToggle ].apply( this, arguments ) || false; 683 }; 684 685 // link all the functions, so any of them can unbind this click handler 686 toggler.guid = guid; 687 while ( i < args.length ) { 688 args[ i++ ].guid = guid; 689 } 690 691 return this.click( toggler ); 692 } 693 }); 694 })(); 695} 696 697/* TECHNICAL NOTE: To overcome an intermittent layout bug in IE 9+, the script will change margin top and left for the shadows to 698 1px less than their computed values, and the first two values for the box-shadow property will be changed to 1px larger than 699 computed, ex: -1px top and left margins and 6px 6px 5px #aaa box-shadow results in what appears to be a 5px box-shadow. 700 Other browsers skip this step and it shouldn't affect you in most cases. In some rare cases it will result in 701 slightly narrower (by 1px) box shadows for IE 9+ on one or more of the drop downs. Without this, sometimes 702 the shadows could be 1px beyond their drop down resulting in a gap. This is the first of the two patches below. 703 and also relates to the MS CSSOM which uses decimal fractions of pixels for layout while only reporting rounded values. 704 There appears to be no computedStyle workaround for this one. */ 705 706//Scripted CSS Patch for IE 9+ intermittent mis-rendering of box-shadow elements (see above TECHNICAL NOTE for more info) 707//And jQuery Patch for IE 9+ CSSOM re: offset Width and Height and re: getBoundingClientRect(). Both run only in IE 9 and later. 708//IE 9 + uses decimal fractions of pixels internally for layout but only reports rounded values using the offset and getBounding methods. 709//These are sometimes rounded inconsistently. This second patch gets the decimal values directly from computedStyle. 710if(ddsmoothmenu.detectie9){ 711 (function($){ //begin Scripted CSS Patch 712 function incdec(v, how){return parseInt(v) + how + 'px';} 713 ddsmoothmenu.ie9shadow = function($elem){ //runs once 714 var getter = document.defaultView.getComputedStyle($elem.get(0), null), 715 curshadow = getter.getPropertyValue('box-shadow').split(' '), 716 curmargin = {top: getter.getPropertyValue('margin-top'), left
716: getter.getPropertyValue('margin-left')}; 717 $('head').append(['\n<style title="ie9shadow" type="text/css">', 718 '.ddcss3support .ddshadow {', 719 '\tbox-shadow: ' + incdec(curshadow[0], 1) + ' ' + incdec(curshadow[1], 1) + ' ' + curshadow[2] + ' ' + curshadow[3] + ';', 720 '}', '.ddcss3support .ddshadow.toplevelshadow {', 721 '\topacity: ' + ($('.ddcss3support .ddshadow').css('opacity') - 0.1) + ';', 722 '\tmargin-top: ' + incdec(curmargin.top, -1) + ';', 723 '\tmargin-left: ' + incdec(curmargin.left, -1) + ';', '}', 724 '</style>\n'].join('\n')); 725 ddsmoothmenu.ie9shadow = function(){}; //becomes empty function after running once 726 }; //end Scripted CSS Patch 727 var jqheight = $.fn.height, jqwidth = $.fn.width; //begin jQuery Patch for IE 9+ .height() and .width() 728 $.extend($.fn, { 729 height: function(){ 730 var obj = this.get(0); 731 if(this.length < 1 || arguments.length || obj === window || obj === document){ 732 return jqheight.apply(this, arguments); 733 } 734 return parseFloat(document.defaultView.getComputedStyle(obj, null).getPropertyValue('height')); 735 }, 736 innerHeight: function(){ 737 if(this.length < 1){return null;} 738 var val = this.height(), obj = this.get(0), getter = document.defaultView.getComputedStyle(obj, null); 739 val += parseInt(getter.getPropertyValue('padding-top')); 740 val += parseInt(getter.getPropertyValue('padding-bottom')); 741 return val; 742 }, 743 outerHeight: function(bool){ 744 if(this.length < 1){return null;} 745 var val = this.innerHeight(), obj = this.get(0), getter = document.defaultView.getComputedStyle(obj, null); 746 val += parseInt(getter.getPropertyValue('border-top-width')); 747 val += parseInt(getter.getPropertyValue('border-bottom-width')); 748 if(bool){ 749 val += parseInt(getter.getPropertyValue('margin-top')); 750 val += parseInt(getter.getPropertyValue('margin-bottom')); 751 } 752 return val; 753 }, 754 width: function(){ 755 var obj = this.get(0); 756 if(this.length < 1 || arguments.length || obj === window || obj === document){ 757 return jqwidth.apply(this, arguments); 758 } 759 return parseFloat(document.defaultView.getComputedStyle(obj, null).getPropertyValue('width')); 760 }, 761 innerWidth: function(){ 762 if(this.length < 1){return null;} 763 var val = this.width(), obj = this.get(0), getter = document.defaultView.getComputedStyle(obj, null); 764 val += parseInt(getter.getPropertyValue('padding-right')); 765 val += parseInt(getter.getPropertyValue('padding-left')); 766 return val; 767 }, 768 outerWidth: function(bool){ 769 if(this.length < 1){return null;} 770 var val = this.innerWidth(), obj = this.get(0), getter = document.defaultView.getComputedStyle(obj, null); 771 val += parseInt(getter.getPropertyValue('border-right-width')); 772 val += parseInt(getter.getPropertyValue('border-left-width')); 773 if(bool){ 774 val += parseInt(getter.getPropertyValue('margin-right')); 775 val += parseInt(getter.getPropertyValue('margin-left')); 776 } 777 return val; 778 } 779 }); //end jQuery Patch for IE 9+ .height() and .width() 780 })(jQuery); 781}
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.