PageSourceSearch

http://niiiis.com/SpryAssets/SpryMenuBar.js

js niiiis.com collected 2026-09-25 02:22:47 UTC 22,093 bytes, 763 lines download raw bytes

1// SpryMenuBar.js - version 0.13 - Spry Pre-Release 1.6.1
2//
3// Copyright (c) 2006. Adobe Systems Incorporated.
4// All rights reserved.
5//
6// Redistribution and use in source and binary forms, with or without
7// modification, are permitted provided that the following conditions are met:
8//
9//   * Redistributions of source code must retain the above copyright notice,
10//     this list of conditions and the following disclaimer.
11//   * Redistributions in binary form must reproduce the above copyright notice,
12//     this list of conditions and the following disclaimer in the documentation
13//     and/or other materials provided with the distribution.
14//   * Neither the name of Adobe Systems Incorporated nor the names of its
15//     contributors may be used to endorse or promote products derived from this
16//     software without specific prior written permission.
17//
18// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
22// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28// POSSIBILITY OF SUCH DAMAGE.
29
30/*******************************************************************************
31
32 SpryMenuBar.js
33 This file handles the JavaScript for Spry Menu Bar.  You should have no need
34 to edit this file.  Some highlights of the MenuBar object is that timers are
35 used to keep submenus from showing up until the user has hovered over the parent
36 menu item for some time, as well as a timer for when they leave a submenu to keep
37 showing that submenu until the timer fires.
38
39 *******************************************************************************/
40
41(function() { // BeginSpryComponent
42
43if (typeof Spry == "undefined") window.Spry = {}; if (!Spry.Widget) Spry.Widget = {};
44
45Spry.BrowserSniff = function()
46{
47	var b = navigator.appName.toString();
48	var up = navigator.platform.toString();
49	var ua = navigator.userAgent.toString();
50
51	this.mozilla = this.ie = this.opera = this.safari = false;
52	var re_opera = /Opera.([0-9\.]*)/i;
53	var re_msie = /MSIE.([0-9\.]*)/i;
54	var re_gecko = /gecko/i;
55	var re_safari = /(applewebkit|safari)\/([\d\.]*)/i;
56	var r = false;
57
58	if ( (r = ua.match(re_opera))) {
59		this.opera = true;
60		this.version = parseFloat(r[1]);
61	} else if ( (r = ua.match(re_msie))) {
62		this.ie = true;
63		this.version = parseFloat(r[1]);
64	} else if ( (r = ua.match(re_safari))) {
65		this.safari = true;
66		this.version = parseFloat(r[2]);
67	} else if (ua.match(re_gecko)) {
68		var re_gecko_version = /rv:\s*([0-9\.]+)/i;
69		r = ua.match(re_gecko_version);
70		this.mozilla = true;
71		this.version = parseFloat(r[1]);
72	}
73	this.windows = this.mac = this.linux = false;
74
75	this.Platform = ua.match(/windows/i) ? "windows" :
76					(ua.match(/linux/i) ? "linux" :
77					(ua.match(/mac/i) ? "mac" :
78					ua.match(/unix/i)? "unix" : "unknown"));
79	this[this.Platform] = true;
80	this.v = this.version;
81
82	if (this.safari && this.mac && this.mozilla) {
83		this.mozilla = false;
84	}
85};
86
87Spry.is = new Spry.BrowserSniff();
88
89// Constructor for Menu Bar
90// element should be an ID of an unordered list (<ul> tag)
91// preloadImage1 and preloadImage2 are images for the rollover state of a menu
92Spry.Widget.MenuBar = function(element, opts)
93{
94	this.init(element, opts);
95};
96
97Spry.Widget.MenuBar.prototype.init = function(element, opts)
98{
99	this.element = this.getElement(element);
100
101	// represents the current (sub)menu we are operating on
102	this.currMenu = null;
103	this.showDelay = 250;
104	this.hideDelay = 600;
105	if(typeof document.getElementById == 'undefined' || (navigator.vendor == 'Apple Computer, Inc.' && typeof window.XMLHttpRequest == 'undefined') || (Spry.is.ie && typeof document.uniqueID == 'undefined'))
106	{
107		// bail on older unsupported browsers
108		return;
109	}
110
111	// Fix IE6 CSS images flicker
112	if (Spry.is.ie && Spry.is.version < 7){
113		try {
114			document.execCommand("BackgroundImageCache", false, true);
115		} catch(err) {}
116	}
117
118	this.upKeyCode = Spry.Widget.MenuBar.KEY_UP;
119	this.downKeyCode = Spry.Widget.MenuBar.KEY_DOWN;
120	this.leftKeyCode = Spry.Widget.MenuBar.KEY_LEFT;
121	this.rightKeyCode = Spry.Widget.MenuBar.KEY_RIGHT;
122	this.escKeyCode = Spry.Widget.MenuBar.KEY_ESC;
123
124	this.hoverClass = 'MenuBarItemHover';
125	this.subHoverClass = 'MenuBarItemSubmenuHover';
126	this.subVisibleClass ='MenuBarSubmenuVisible';
127	this.hasSubClass = 'MenuBarItemSubmenu';
128	this.activeClass = 'MenuBarActive';
129	this.isieClass = 'MenuBarItemIE';
130	this.verticalClass = 'MenuBarVertical';
131	this.horizontalClass = 'MenuBarHorizontal';
132	this.enableKeyboardNavigation = true;
133
134	this.hasFocus = false;
135	// load hover images now
136	if(opts)
137	{
138		for(var k in opts)
139		{
140			if (typeof this[k] == 'undefined')
141			{
142				var rollover = new Image;
143				rollover.src = opts[k];
144			}
145		}
146		Spry.Widget.MenuBar.setOptions(this, opts);
147	}
148
149	// safari doesn't support tabindex
150	if (Spry.is.safari)
151		this.enableKeyboardNavigation = false;
152
153	if(this.element)
154	{
155		this.currMenu = this.element;
156		var items = this.element.getElementsByTagName('li');
157		for(var i=0; i<items.length; i++)
158		{
159			if (i > 0 && this.enableKeyboardNavigation)
160				items[i].getElementsByTagName('a')[0].tabIndex='-1';
161
162			this.initialize(items[i], element);
163			if(Spry.is.ie)
164			{
165				this.addClassName(items[i], this.isieClass);
166				items[i].style.position = "static";
167			}
168		}
169		if (this.enableKeyboardNavigation)
170		{
171			var self = this;
172			this.addEventListener(document, 'keydown', function(e){self.keyDown(e); }, false);
173		}
174
175		if(Spry.is.ie)
176		{
177			if(this.hasClassName(this.element, this.verticalClass))
178			{
179				this.element.style.position = "relative";
180			}
181			var linkitems = this.element.getElementsByTagName('a');
182			for(var i=0; i<linkitems.length; i++)
183			{
184				linkitems[i].style.position = "relative";
185			}
186		}
187	}
188};
189Spry.Widget.MenuBar.KEY_ESC = 27;
190Spry.Widget.MenuBar.KEY_UP = 38;
191Spry.Widget.MenuBar.KEY_DOWN = 40;
192Spry.Widget.MenuBar.KEY_LEFT = 37;
193Spry.Widget.MenuBar.KEY_RIGHT = 39;
194
195Spry.Widget.MenuBar.prototype.getElement = function(ele)
196{
197	if (ele && typeof ele == "string")
198		return document.getElementById(ele);
199	return ele;
200};
201
202Spry.Widget.MenuBar.prototype.hasClassName = function(ele, className)
203{
204	if (!ele || !className || !ele.className || ele.className.search(new RegExp("\\b" + className + "\\b")) == -1)
205	{
206		return false;
207	}
208	return true;
209};
210
211Spry.Widget.MenuBar.prototype.addClassName = function(ele, className)
212{
213	if (!ele || !className || this.hasClassName(ele, className))
214		return;
215	ele.className += (ele.className ? " " : "") + className;
216};
217
218Spry.Widget.MenuBar.prototype.removeClassName = function(ele, className)
219{
220	if (!ele || !className || !this.hasClassName(ele, className))
221		return;
222	ele.className = ele.className.replace(new RegExp("\\s*\\b" + className + "\\b", "g"), "");
223};
224
225// addEventListener for Menu Bar
226// attach an event to a tag without creating obtrusive HTML code
227Spry.Widget.MenuBar.prototype.addEventListener = function(element, eventType, handler, capture)
228{
229	try
230	{
231		if (element.addEventListener)
232		{
233			element.addEventListener(eventType, handler, capture);
234		}
235		else if (element.attachEvent)
236		{
237			element.attachEvent('on' + eventType, handler);
238		}
239	}
240	catch (e) {}
241};
242
243// createIframeLayer for Menu Bar
244// creates an IFRAME underneath a menu so that it will show above form controls and ActiveX
245Spry.Widget.MenuBar.prototype.createIframeLayer = function(menu)
246{
247	var layer = document.createElement('iframe');
248	layer.tabIndex = '-1';
249	layer.src = 'javascript:""';
250	layer.frameBorder = '0';
251	layer.scrolling = 'no';
252	menu.parentNode.appendChild(layer);
253	
254	layer.style.left = menu.offsetLeft + 'px';
255	layer.style.top = menu.offsetTop + 'px';
256	layer.style.width = menu.offsetWidth + 'px';
257	layer.style.height = menu.offsetHeight + 'px';
258};
259
260// removeIframeLayer for Menu Bar
261// removes an IFRAME underneath a menu to reveal any form controls and ActiveX
262Spry.Widget.MenuBar.prototype.removeIframeLayer =  function(menu)
263{
264	var layers = ((menu == this.element) ? menu : menu.parentNode).getElementsByTagName('iframe');
265	while(layers.length > 0)
266	{
267		layers[0].parentNode.removeChild(layers[0]);
268	}
269};
270
271// clearMenus for Menu Bar
272// root is the top level unordered list (<ul> tag)
273Spry.Widget.MenuBar.prototype.clearMenus = function(root)
274{
275	var menus = root.getElementsByTagName('ul');
276	for(var i=0; i<menus.length; i++)
277		this.hideSubmenu(menus[i]);
278
279	this.removeClassName(this.element, this.activeClass);
280};
281
282// bubbledTextEvent for Menu Bar
283// identify bubbled up text events in Safari so we can ignore them
284Spry.Widget.MenuBar.prototype.bubbledTextEvent = function()
285{
286	return Spry.is.safari && (event.target == event.relatedTarget.parentNode || (event.eventPhase == 3 && event.target.parentNode == event.relatedTarget));
287};
288
289// showSubmenu for Menu Bar
290// set the proper CSS class on this menu to show it
291Spry.Widget.MenuBar.prototype.showSubmenu = function(menu)
292{
293	if(this.currMenu)
294	{
295		this.clearMenus(this.currMenu);
296		this.currMenu = null;
297	}
298	
299	if(menu)
300	{
301		this.addClassName(menu, this.subVisibleClass);
302		if(typeof document.all != 'undefined' && !Spry.is.opera && navigator.vendor != 'KDE')
303		{
304			if(!this.hasClassName(this.element, this.horizontalClass) || menu.parentNode.parentNode != this.element)
305			{
306				menu.style.top = menu.parentNode.offsetTop + 'px';
307			}
308		}
309		if(Spry.is.ie && Spry.is.version < 7)
310		{
311			this.createIframeLayer(menu);
312		}
313	}
314	this.addClassName(this.element, this.activeClass);
315};
316
317// hideSubmenu for Menu Bar
318// remove the proper CSS class on this menu to hide it
319Spry.Widget.MenuBar.prototype.hideSubmenu = function(menu)
320{
321	if(menu)
322	{
323		this.removeClassName(menu, this.subVisibleClass);
324		if(typeof document.all != 'undefined' && !Spry.is.opera && navigator.vendor != 'KDE')
325		{
326			menu.style.top = '';
327			menu.style.left = '';
328		}
329		if(Spry.is.ie && Spry.is.version < 7)
330			this.removeIframeLayer(menu);
331	}
332};
333
334// initialize for Menu Bar
335// create event listeners for the Menu Bar widget so we can properly
336// show and hide submenus
337Spry.Widget.MenuBar.prototype.initialize = function(listitem, element)
338{
339	var opentime, closetime;
340	var link = listitem.getElementsByTagName('a')[0];
341	var submenus = listitem.getElementsByTagName('ul');
342	var menu = (submenus.length > 0 ? submenus[0] : null);
343
344	if(menu)
345		this.addClassName(link, this.hasSubClass);
346
347	if(!Spry.is.ie)
348	{
349		// define a simple function that comes standard in IE to determine
350		// if a node is within another node
351		listitem.contains = function(testNode)
352		{
353			// this refers to the list item
354			if(testNode == null)
355				return false;
356
357			if(testNode == this)
358				return true;
359			else
360				return this.contains(testNode.parentNode);
361		};
362	}
363
364	// need to save this for scope further down
365	var self = this;
366	this.addEventListener(listitem, 'mouseover', function(e){self.mouseOver(listitem, e);}, false);
367	this.addEventListener(listitem, 'mouseout', function(e){if (self.enableKeyboardNavigation) self.clearSelection(); self.mouseOut(listitem, e);}, false);
368
369	if (this.enableKeyboardNavigation)
370	{
371		this.addEventListener(link, 'blur', function(e){self.onBlur(listitem);}, false);
372		this.addEventListener(link, 'focus', function(e){self.keyFocus(listitem, e);}, false);
373	}
374};
375Spry.Widget.MenuBar.prototype.keyFocus = function (listitem, e)
376{
377	this.lastOpen = listitem.getElementsByTagName('a')[0];
378	this.addClassName(this.lastOpen, listitem.getElementsByTagName('ul').length > 0 ? this.subHoverClass : this.hoverClass);
379	this.hasFocus = true;
380};
381Spry.Widget.MenuBar.prototype.onBlur = function (listitem)
382{
383	this.clearSelection(listitem);
384};
385Spry.Widget.MenuBar.prototype.clearSelection = function(el){
386	//search any intersection with the current open element
387	if (!this.lastOpen)
388		return;
389
390	if (el)
391	{
392		el = el.getElementsByTagName('a')[0];
393		
394		// check children
395		var item = this.lastOpen;
396		while (item != this.element)
397		{
398			var tmp = el;
399			while (tmp != this.element)
400			{
401				if (tmp == item)
402					return;
403				try{
404					tmp = tmp.parentNode;
405				}catch(err){break;}
406			}
407			item = item.parentNode;
408		}
409	}
410	var item = this.lastOpen;
411	while (item != this.element)
412	{
413		this.hideSubmenu(item.parentNode);
414		var link = item.getElementsByTagName('a')[0];
415		this.removeClassName(link, this.hoverClass);
416		this.removeClassName(link, this.subHoverClass);
417		item = item.parentNode;
418	}
419	this.lastOpen = false;
420};
421Spry.Widget.MenuBar.prototype.keyDown = function (e)
422{
423	if (!this.hasFocus)
424		return;
425
426	if (!this.lastOpen)
427	{
428		this.hasFocus = false;
429		return;
430	}
431
432	var e = e|| event;
433	var listitem = this.lastOpen.parentNode;
434	var link = this.lastOpen;
435	var submenus = listitem.getElementsByTagName('ul');
436	var menu = (submenus.length > 0 ? submenus[0] : null);
437	var hasSubMenu = (menu) ? true : false;
438
439	var opts = [listitem, menu, null, this.getSibling(listitem, 'previousSibling'), this.getSibling(listitem, 'nextSibling')];
440	
441	if (!opts[3])
442		opts[2] = (listitem.parentNode.parentNode.nodeName.toLowerCase() == 'li')?listitem.parentNode.parentNode:null;
443
444	var found = 0;
445	switch (e.keyCode){
446		case this.upKeyCode:
447			found = this.getElementForKey(opts, 'y', 1);
448			break;
449		case this.downKeyCode:
450			found = this.getElementForKey(opts, 'y', -1);
451			break;
452		case this.leftKeyCode:
453			found = this.getElementForKey(opts, 'x', 1);
454			break;
455		case this.rightKeyCode:
456			found = this.getElementForKey(opts, 'x', -1);
457			break;
458		case this.escKeyCode:
459		case 9:
460			this.clearSelection();
461			this.hasFocus = false;
462		default: return;
463	}
464	switch (found)
465	{
466		case 0: return;
467		case 1:
468			//subopts
469			this.mouseOver(listitem, e);
470			break;
471		case 2:
472			//parent
473			this.mouseOut(opts[2], e);
474			break;
475		case 3:
476		case 4:
477			// left - right
478			this.removeClassName(link, hasSubMenu ? this.subHoverClass : this.hoverClass);
479			break;
480	}
481	var link = opts[found].getElementsByTagName('a')[0];
482	if (opts[found].nodeName.toLowerCase() == 'ul')
483		opts[found] = opts[found].getElementsByTagName('li')[0];
484
485	this.addClassName(link, opts[found].getElementsByTagName('ul').length > 0 ? this.subHoverClass : this.hoverClass);
486	this.lastOpen = link;
487	opts[found].getElementsByTagName('a')[0].focus();
488  
489        //stop further event handling by the browser
490	return Spry.Widget.MenuBar.stopPropagation(e);
491};
492Spry.Widget.MenuBar.prototype.mouseOver = function (listitem, e)
493{
494	var link = listitem.getElementsByTagName('a')[0];
495	var submenus = listitem.getElementsByTagName('ul');
496	var menu = (submenus.length > 0 ? submenus[0] : null);
497	var hasSubMenu = (menu) ? true : false;
498	if (this.enableKeyboardNavigation)
499		this.clearSelection(listitem);
500
501	if(this.bubbledTextEvent())
502	{
503		// ignore bubbled text events
504		return;
505	}
506
507	if (listitem.closetime)
508		clearTimeout(listitem.closetime);
509
510	if(this.currMenu == listitem)
511	{
512		this.currMenu = null;
513	}
514
515	// move the focus too
516	if (this.hasFocus)
517		link.focus();
518
519	// show menu highlighting
520	this.addClassName(link, hasSubMenu ? this.subHoverClass : this.hoverClass);
521	this.lastOpen = link;
522	if(menu && !this.hasClassName(menu, this.subHoverClass))
523	{
524		var self = this;
525		listitem.opentime = window.setTimeout(function(){self.showSubmenu(menu);}, this.showDelay);
526	}
527};
528Spry.Widget.MenuBar.prototype.mouseOut = function (listitem, e)
529{
530	var link = listitem.getElementsByTagName('a')[0];
531	var submenus = listitem.getElementsByTagName('ul');
532	var menu = (submenus.length > 0 ? submenus[0] : null);
533	var hasSubMenu = (menu) ? true : false;
534	if(this.bubbledTextEvent())
535	{
536		// ignore bubbled text events
537		return;
538	}
539
540	var related = (typeof e.relatedTarget != 'undefined' ? e.relatedTarget : e.toElement);
541	if(!listitem.contains(related))
542	{
543		if (listitem.opentime) 
544			clearTimeout(listitem.opentime);
545		this.currMenu = listitem;
546
547		// remove menu highlighting
548		this.removeClassName(link, hasSubMenu ? this.subHoverClass : this.hoverClass);
549		if(menu)
550		{
551			var self = this;
552			listitem.closetime = window.setTimeout(function(){self.hideSubmenu(menu);}, this.hideDelay);
553		}
554		if (this.hasFocus)
555			link.blur();
556	}
557};
558Spry.Widget.MenuBar.prototype.getSibling = function(element, sibling)
559{
560	var child = element[sibling];
561	while (child && child.nodeName.toLowerCase() !='li')
562		child = child[sibling];
563
564	return child;
565};
566Spry.Widget.MenuBar.prototype.getElementForKey = function(els, prop, dir)
567{
568	var found = 0;
569	var rect = Spry.Widget.MenuBar.getPosition;
570	var ref = rect(els[found]);
571
572	var hideSubmenu = false;
573	//make the subelement visible to compute the position
574	if (els[1] && !this.hasClassName(els[1], this.MenuBarSubmenuVisible))
575	{
576		els[1].style.visibility = 'hidden';
577		this.showSubmenu(els[1]);
578		hideSubmenu = true;
579	}
580
581	var isVert = this.hasClassName(this.element, this.verticalClass);
582	var hasParent = els[0].parentNode.parentNode.nodeName.toLowerCase() == 'li' ? true : false;
583	
584	for (var i = 1; i < els.length; i++){
585		//when navigating on the y axis in vertical menus, ignore children and parents
586		if(prop=='y' && isVert && (i==1 || i==2))
587		{
588			continue;
589		}
590		//when navigationg on the x axis in the FIRST LEVEL of horizontal menus, ignore children and parents
591		if(prop=='x' && !isVert && !hasParent && (i==1 || i==2))
592		{
593			continue;
594		}
595			
596		if (els[i])
597		{
598			var tmp = rect(els[i]); 
599			if ( (dir * tmp[prop]) < (dir * ref[prop]))
600			{
601				ref = tmp;
602				found = i;
603			}
604		}
605	}
606	
607	// hide back the submenu
608	if (els[1] && hideSubmenu){
609		this.hideSubmenu(els[1]);
610		els[1].style.visibility =  '';
611	}
612
613	return found;
614};
615Spry.Widget.MenuBar.camelize = function(str)
616{
617	if (str.indexOf('-') == -1){
618		return str;	
619	}
620	var oStringList = str.split('-');
621	var isFirstEntry = true;
622	var camelizedString = '';
623
624	for(var i=0; i < oStringList.length; i++)
625	{
626		if(oStringList[i].length>0)
627		{
628			if(isFirstEntry)
629			{
630				camelizedString = oStringList[i];
631				isFirstEntry = false;
632			}
633			else
634			{
635				var s = oStringList[i];
636				camelizedString += s.charAt(0).toUpperCase() + s.substring(1);
637			}
638		}
639	}
640
641	return camelizedString;
642};
643
644Spry.Widget.MenuBar.getStyleProp = function(element, prop)
645{
646	var value;
647	try
648	{
649		if (element.style)
650			value = element.style[Spry.Widget.MenuBar.camelize(prop)];
651
652		if (!value)
653			if (document.defaultView && document.defaultView.getComputedStyle)
654			{
655				var css = document.defaultView.getComputedStyle(element, null);
656				value = css ? css.getPropertyValue(prop) : null;
657			}
658			else if (element.currentStyle) 
659			{
660					value = element.currentStyle[Spry.Widget.MenuBar.camelize(prop)];
661			}
662	}
663	catch (e) {}
664
665	return value == 'auto' ? null : value;
666};
667Spry.Widget.MenuBar.getIntProp = function(element, prop)
668{
669	var a = parseInt(Spry.Widget.MenuBar.getStyleProp(element, prop),10);
670	if (isNaN(a))
671		return 0;
672	return a;
673};
674
675Spry.Widget.MenuBar.getPosition = function(el, doc)
676{
677	doc = doc || document;
678	if (typeof(el) == 'string') {
679		el = doc.getElementById(el);
680	}
681
682	if (!el) {
683		return false;
684	}
685
686	if (el.parentNode === null || Spry.Widget.MenuBar.getStyleProp(el, 'display') == 'none') {
687		//element must be visible to have a box
688		return false;
689	}
690
691	var ret = {x:0, y:0};
692	var parent = null;
693	var box;
694
695	if (el.getBoundingClientRect) { // IE
696		box = el.getBoundingClientRect();
697		var scrollTop = doc.documentElement.scrollTop || doc.body.scrollTop;
698		var scrollLeft = doc.documentElement.scrollLeft || doc.body.scrollLeft;
699		ret.x = box.left + scrollLeft;
700		ret.y = box.top + scrollTop;
701	} else if (doc.getBoxObjectFor) { // gecko
702		box = doc.getBoxObjectFor(el);
703		ret.x = box.x;
704		ret.y = box.y;
705	} else { // safari/opera
706		ret.x = el.offsetLeft;
707		ret.y = el.offsetTop;
708		parent = el.offsetParent;
709		if (parent != el) {
710			while (parent) {
711				ret.x += parent.offsetLeft;
712				ret.y += parent.offsetTop;
713				parent = parent.offsetParent;
714			}
715		}
716		// opera & (safari absolute) incorrectly account for body offsetTop
717		if (Spry.is.opera || Spry.is.safari && Spry.Widget.MenuBar.getStyleProp(el, 'position') == 'absolute')
718			ret.y -= doc.body.offsetTop;
719	}
720	if (el.parentNode)
721			parent = el.parentNode;
722	else
723		parent = null;
724	if (parent.nodeName){
725		var cas = parent.nodeName.toUpperCase();
726		while (parent && cas != 'BODY' && cas != 'HTML') {
727			cas = parent.nodeName.toUpperCase();
728			ret.x -= parent.scrollLeft;
729			ret.y -= parent.scrollTop;
730			if (parent.parentNode)
731				parent = parent.parentNode;
732			else
733				parent = null;
734		}
735	}
736	return ret;
737};
738
739Spry.Widget.MenuBar.stopPropagation = function(ev)
740{
741	if (ev.stopPropagation)
742		ev.stopPropagation();
743	else
744		ev.cancelBubble = true;
745	if (ev.preventDefault) 
746		ev.preventDefault();
747	else 
748		ev.returnValue = false;
749};
750
751Spry.Widget.MenuBar.setOptions = function(obj, optionsObj, ignoreUndefinedProps)
752{
753	if (!optionsObj)
754		return;
755	for (var optionName in optionsObj)
756	{
757		if (ignoreUndefinedProps && optionsObj[optionName] == undefined)
758			continue;
759		obj[optionName] = optionsObj[optionName];
760	}
761};
762
763})(); // EndSpryComponent

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.