diff -r 902822492a68 -r fe660c52c48f includes/clientside/static/dropdown.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/includes/clientside/static/dropdown.js Wed Jun 13 16:07:17 2007 -0400 @@ -0,0 +1,508 @@ +/* + * The jBox menu system. Written by Dan Fuhry and licensed under the GPL. + */ + +// Cache of DOM and event objects, used in setTimeout() calls due to scope rules +var jBoxObjCache = new Object(); + +// Cache of "correct" heights for unordered list objects used in submenus. Helps the animation routine know what height it's aiming for. +var jBoxMenuHeights = new Object(); + +// Blocks animations from running if there's already an animation going on the same object +var jBoxSlideBlocker = new Object(); + +// Speed at which the menus should slide open. 1 to 100 or -1 to disable. +// Setting this higher than 100 will cause an infinite loop in the browser. +// Default is 80 - anything higher than 90 means exponential speed increase +var slide_speed = 80; + +// Inertia value to start with +// Default is 0 +var inertia_base = 0; + +// Value added to inertia_base on each frame - generally 1 to 3 is good, with 1 being slowest animation +// Default is 1 +var inertia_inc = 1; + +// Opacity that menus should fade to. 1 to 100 or -1 to disable fades. This only works if the slide effect is also enabled. +// Default is 100 +var jBox_opacity = 100; + +// Adds the jBox CSS to the HTML header. Called on window onload. +function jBoxInit() +{ + setTimeout('jBoxBatchSetup();', 200); +} + +// Initializes each menu. +function jBoxBatchSetup() +{ + var menus = document.getElementsByClassName('div', 'menu_nojs'); + if ( menus.length > 0 ) + { + for ( var i in menus ) + { + if ( typeof(menus[i]) != 'object') + continue; // toJSONString() compatibility + jBoxSetup(menus[i]); + } + } +} + +// Initializes a div with a jBox menu in it. +function jBoxSetup(obj) +{ + $(obj).addClass('menu'); + removeTextNodes(obj); + for ( var i in obj.childNodes ) + { + /* normally this would be done in about 2 lines of code, but javascript is so picky..... */ + if ( obj.childNodes[i] ) + { + if ( obj.childNodes[i].tagName ) + { + if ( obj.childNodes[i].tagName.toLowerCase() == 'a' ) + { + if ( obj.childNodes[i].nextSibling.tagName ) + { + if ( obj.childNodes[i].nextSibling.tagName.toLowerCase() == 'ul' || ( obj.childNodes[i].nextSibling.tagName.toLowerCase() == 'div' && obj.childNodes[i].nextSibling.className == 'submenu' ) ) + { + // Calculate height + var ul = obj.childNodes[i].nextSibling; + domObjChangeOpac(0, ul); + ul.style.display = 'block'; + var dim = fetch_dimensions(ul); + if ( !ul.id ) + ul.id = 'jBoxmenuobj_' + Math.floor(Math.random() * 10000000); + jBoxMenuHeights[ul.id] = parseInt(dim['h']) - 2; // subtract 2px for border width + ul.style.display = 'none'; + domObjChangeOpac(100, ul); + + // Setup events + obj.childNodes[i].onmouseover = function() { jBoxOverHandler(this); }; + obj.childNodes[i].onmouseout = function(e) { jBoxOutHandler(this, e); }; + obj.childNodes[i].nextSibling.onmouseout = function(e) { jBoxOutHandler(this, e); }; + } + } + } + } + } + } +} + +// Called when user hovers mouse over a submenu +function jBoxOverHandler(obj) +{ + // Random ID used to track the object to perform on + var seed = Math.floor(Math.random() * 1000000); + jBoxObjCache[seed] = obj; + + // Sleep for a (little more than a tenth of a) second to see if the user really wants the menu to expand + setTimeout('if(isOverObj(jBoxObjCache['+seed+'], false, false)) jBoxOverHandlerBin(jBoxObjCache['+seed+']);', 150); +} + +// Displays a menu. +function jBoxOverHandlerBin(obj) +{ + var others = obj.parentNode.getElementsByTagName('ul'); + for ( var i in others ) + { + if(typeof(others[i]) == 'object') + { + others[i].style.display = 'none'; + others[i].previousSibling.className = ''; + } + } + var others = obj.parentNode.getElementsByTagName('div'); + for ( var i in others ) + { + if(typeof(others[i]) == 'object') + { + if ( others[i].className == 'submenu' ) + { + others[i].style.display = 'none'; + others[i].previousSibling.className = ''; + } + } + } + if(obj.nextSibling.tagName.toLowerCase() == 'ul' || ( obj.nextSibling.tagName.toLowerCase() == 'div' && obj.nextSibling.className == 'submenu' )) + { + obj.className = 'liteselected'; + var ul = obj.nextSibling; + var dim = fetch_dimensions(obj); + var off = fetch_offset(obj); + var dimh = parseInt(dim['h']); + var offtop = parseInt(off['top']); + var top = dimh + offtop; + left = off['left']; + ul.style.left = left + 'px'; + ul.style.top = top + 'px'; + domObjChangeOpac(0, ul); + ul.style.clip = 'rect(auto,auto,auto,auto)'; + ul.style.overflow = 'visible'; + ul.style.display = 'block'; + slideOut(ul); + } +} + +function jBoxOutHandler(obj, event) +{ + var seed = Math.floor(Math.random() * 1000000); + var seed2 = Math.floor(Math.random() * 1000000); + jBoxObjCache[seed] = obj; + jBoxObjCache[seed2] = event; + setTimeout('jBoxOutHandlerBin(jBoxObjCache['+seed+'], jBoxObjCache['+seed2+']);', 750); +} + +function jBoxOutHandlerBin(obj, event) +{ + var caller = obj.tagName.toLowerCase(); + if(caller == 'a') + { + a = obj; + ul = obj.nextSibling; + } + else if(caller == 'ul' || caller == 'div') + { + a = obj.previousSibling; + ul = obj; + } + else + { + return false; + } + + if (!isOverObj(a, false, event) && !isOverObj(ul, true, event)) + { + a.className = ''; + + slideIn(ul); + + } + + return true; +} + +// Slide an element downwards until it is at full height. +// First parameter should be a DOM object with style.display = block and opacity = 0. + +var sliderobj = new Object(); + +function slideOut(obj) +{ + if ( jBoxSlideBlocker[obj.id] ) + return false; + + jBoxSlideBlocker[obj.id] = true; + + if ( slide_speed == -1 ) + { + obj.style.display = 'block'; + return false; + } + + var currentheight = 0; + var targetheight = jBoxMenuHeights[obj.id]; + var inertiabase = inertia_base; + var inertiainc = inertia_inc; + slideStep(obj, 0); + domObjChangeOpac(100, obj); + obj.style.overflow = 'hidden'; + + // Don't edit past here + var timercnt = 0; + + var seed = Math.floor(Math.random() * 1000000); + sliderobj[seed] = obj; + + var framecnt = 0; + + while(true) + { + framecnt++; + timercnt += ( 100 - slide_speed ); + inertiabase += inertiainc; + currentheight += inertiabase; + if ( currentheight > targetheight ) + currentheight = targetheight; + setTimeout('slideStep(sliderobj['+seed+'], '+currentheight+', '+targetheight+');', timercnt); + if ( currentheight >= targetheight ) + break; + } + timercnt = timercnt + ( 100 - slide_speed ); + setTimeout('jBoxSlideBlocker[sliderobj['+seed+'].id] = false;', timercnt); + var opacstep = jBox_opacity / framecnt; + var opac = 0; + var timerstep = 0; + domObjChangeOpac(0, obj); + while(true) + { + timerstep += ( 100 - slide_speed ); + opac += opacstep; + setTimeout('domObjChangeOpac('+opac+', sliderobj['+seed+']);', timerstep); + if ( opac >= jBox_opacity ) + break; + } +} + +function slideIn(obj) +{ + if ( obj.style.display != 'block' ) + return false; + + if ( jBoxSlideBlocker[obj.id] ) + return false; + + jBoxSlideBlocker[obj.id] = true; + + var targetheight = 0; + var dim = fetch_dimensions(obj); + var currentheight = jBoxMenuHeights[obj.id]; + var origheight = currentheight; + var inertiabase = inertia_base; + var inertiainc = inertia_inc; + domObjChangeOpac(100, obj); + obj.style.overflow = 'hidden'; + + // Don't edit past here + var timercnt = 0; + + var seed = Math.floor(Math.random() * 1000000); + sliderobj[seed] = obj; + + var framecnt = 0; + + for(var j = 0;j<100;j++) // while(true) + { + framecnt++; + timercnt = timercnt + ( 100 - slide_speed ); + inertiabase = inertiabase + inertiainc; + currentheight = currentheight - inertiabase; + if ( currentheight < targetheight ) + currentheight = targetheight; + setTimeout('slideStep(sliderobj['+seed+'], '+currentheight+');', timercnt); + if ( currentheight <= targetheight ) + break; + } + timercnt += ( 100 - slide_speed ); + setTimeout('sliderobj['+seed+'].style.display="none";sliderobj['+seed+'].style.height="'+origheight+'px";jBoxSlideBlocker[sliderobj['+seed+'].id] = false;', timercnt); + + var opacstep = jBox_opacity / framecnt; + var opac = jBox_opacity; + var timerstep = 0; + domObjChangeOpac(100, obj); + while(true) + { + timerstep += ( 100 - slide_speed ); + opac -= opacstep; + setTimeout('domObjChangeOpac('+opac+', sliderobj['+seed+']);', timerstep); + if ( opac <= 0 ) + break; + } + +} + +function slideStep(obj, height, maxheight) +{ + obj.style.height = height + 'px'; + //obj.style.clip = 'rect(3px,auto,'+maxheight+'px,auto)'; + obj.style.overflow = 'hidden'; + //obj.style.clip = 'rect('+height+'px,0px,'+maxheight+'px,auto);'; +} + +function isOverObj(obj, bias, event) +{ + var fieldUL = new Object(); + var dim = fetch_dimensions(obj); + var off = fetch_offset(obj); + fieldUL['top'] = off['top']; + fieldUL['left'] = off['left']; + fieldUL['right'] = off['left'] + dim['w']; + fieldUL['bottom'] = off['top'] + dim['h']; + + //document.getElementById('debug').innerHTML = '




Mouse: x: '+mouseX+', y:' + mouseY + '
'; // + document.getElementById('debug').innerHTML; + + if(bias) + { + if ( ( mouseX < fieldUL['left'] + 2 || mouseX > fieldUL['right'] - 5 ) || + ( mouseY < fieldUL['top'] - 2 || mouseY > fieldUL['bottom'] - 2 ) ) + { + return false; + } + } + else + { + if ( ( mouseX < fieldUL['left'] || mouseX > fieldUL['right'] ) || + ( mouseY < fieldUL['top'] || mouseY > fieldUL['bottom'] ) ) + return false; + } + + return true; + + /* + var tgt = event.target; + if ( !tgt ) + return false; + do { + if ( tgt == obj ) + return true; + tgt = tgt.parentNode; + } while (tgt.tagName.toLowerCase() != 'body' ); + return false; + */ +} + +function jBoxGarbageCollection(e) +{ + setMousePos(e); + var menus = document.getElementsByClassName('div', 'menu'); + if ( menus.length > 0 ) + { + for ( var i in menus ) + { + if ( typeof(menus[i]) != 'object') + continue; // toJSONString() compatibility + var uls = menus[i].getElementsByTagName('ul'); + if ( uls.length > 0 ) + { + for ( var j = 0; j < uls.length; j++ ) + { + if ( !isOverObj(uls[j], false, e) ) + { + uls[j].previousSibling.className = ''; + //uls[j].style.display = 'none'; + slideIn(uls[j]); + } + } + } + var uls = getElementsByClassName(menus[i], 'divs', 'submenu'); + if ( uls.length > 0 ) + { + for ( var j = 0; j < uls.length; j++ ) + { + if ( !isOverObj(uls[j], false, e) ) + { + uls[j].previousSibling.className = ''; + //uls[j].style.display = 'none'; + slideIn(uls[j]); + } + } + } + } + } +} + +document.onclick = jBoxGarbageCollection; + +function removeTextNodes(obj) +{ + if(obj) + { + if(typeof(obj.tagName) != 'string') + { + if ( obj.nodeType == 3 && obj.data.match(/^([\s]*)$/ig) ) + { + obj.parentNode.removeChild(obj); + return; + } + } + if(obj.firstChild) + { + for(var i in obj.childNodes) + { + removeTextNodes(obj.childNodes[i]); + } + } + } +} + +var getElementsByClassName = function(parent, type, cls) { + if(!type) + type = '*'; + ret = new Array(); + el = parent.getElementsByTagName(type); + for ( var i in el ) + { + if ( typeof(el[i]) != 'object') + continue; // toJSONString() compatibility + if(el[i].className) + { + if(el[i].className.indexOf(' ') > 0) + { + classes = el[i].className.split(' '); + } + else + { + classes = new Array(); + classes.push(el[i].className); + } + if ( in_array(cls, classes) ) + ret.push(el[i]); + } + } + return ret; +} + +document.getElementsByClassName = function(type, cls) { + return getElementsByClassName(document, type, cls); +} + +function setMousePos(event) +{ + if(IE) + { + if(!event) + { + event = window.event; + } + clX = event.clientX; + sL = document.body.scrollLeft; + mouseX = clX + sL; + mouseY = event.clientY + document.body.scrollTop; + return; + } + if( typeof(event.clientX) == 'number' ) + { + mouseX = event.clientX; + mouseY = event.clientY; + return; + } + else if( typeof(event.layerX) == 'number' ) + { + mouseX = event.layerX; + mouseY = event.layerY; + return; + } + else if( typeof(event.offsetX) == 'number' ) + { + mouseX = event.offsetX; + mouseY = event.offsetY; + return; + } + else if( typeof(event.screenX) == 'number' ) + { + mouseX = event.screenX; + mouseY = event.screenY; + return; + } + else if( typeof(event.x) == 'number' ) + { + mouseX = event.x; + mouseY = event.y; + return; + } +} + +document.onmousemove = function(e) +{ + setMousePos(e); +}; + +function domObjChangeOpac(opacity, id) { + var object = id.style; + object.opacity = (opacity / 100); + object.MozOpacity = (opacity / 100); + object.KhtmlOpacity = (opacity / 100); + object.filter = "alpha(opacity=" + opacity + ")"; +} +