PageSourceSearch

https://pochiu.edu.hk/sites/all/themes/ntemplate/ddsmoothmenu/ddsmoothmenu.js

js pochiu.edu.hk collected 2026-10-08 20:12:02 UTC 40,551 bytes, 781 lines download raw bytes

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.