// ******************************** quirksmode: ******************************** //
var QM;
if (!QM) QM = new function() {
//Browser detect - http://www.quirksmode.org/js/detect.html
this.checkIt = function(string)
{
this.place = this.detect.indexOf(string) + 1;
this.thestring = string;
return this.place;
}
this.detect = navigator.userAgent.toLowerCase();
this.OS = 0;
this.browser = 0;
this.version = 0;
this.total = 0;
this.place = 0;
this.thestring = 0;
if (this.checkIt('konqueror')) {
this.browser = "Konqueror";
this.OS = "Linux";
} else if (this.checkIt('safari')) this.browser = "Safari"
else if (this.checkIt('omniweb')) this.browser = "OmniWeb"
else if (this.checkIt('opera')) this.browser = "Opera"
else if (this.checkIt('webtv')) this.browser = "WebTV";
else if (this.checkIt('icab')) this.browser = "iCab"
else if (this.checkIt('msie')) this.browser = "Internet Explorer"
else if (!this.checkIt('compatible'))
{
this.browser = "Netscape Navigator"
this.version = this.detect.charAt(8);
}
else this.browser = "An unknown browser";
if (!this.version) this.version = this.detect.charAt(this.place + this.thestring.length);
if (!this.OS)
{
if (this.checkIt('linux')) this.OS = "Linux";
else if (this.checkIt('x11')) this.OS = "Unix";
else if (this.checkIt('mac')) this.OS = "Mac"
else if (this.checkIt('win')) this.OS = "Windows"
else this.OS = "an unknown operating system";
}
}
// ******************************** listener library: ******************************** //
//todo - do a browser detect before determining which method to use
//and if neither is supported . . . revert to oldschool src["on"+ev] = function() { cycle through all func's in some array and execute them }
//but to do that - for the oldschool support to work - we would need an event listener init . . . and perhaps an event listener object?
function addListener(src, ev, func) {
//W3C DOM Event Handling
if (src.addEventListener) {
src.addEventListener(ev, func, false);
}
//Microsoft?
else { //else if (src.attachEvent) { . . .
src.attachEvent("on" + ev, func);
}
}
// ******************************** mouse library: ******************************** //
var ns4 = !!(document.layers);
var ie4 = !!(document.all && !document.getElementById);
var ie5 = !!(document.all && document.getElementById);
var ns6 = !!(!document.all && document.getElementById);
//mouse handling object
//what happens if multiple instances of this are php-included?
//how about this? "var mouseh;" "if (!mouseh) mouseh = . . . " ? this depends upon the assumption that mouseh == null by default
//this way even if the code is php-included twice, it will still only instanciate a single object
//Notice how I wrote my own multiple-event-handler code in there? thats not necessarily the best.
//pro: can be easily made backwards compatible. con: a lot of extra (possibly wasted) typing
var mouseh;
if (!mouseh) mouseh = {
//last stored mouse position
lastpos:{x:0, y:0},
//someone evaluate this condition for me . . .
ieMouse: (ie4 || ie5) && !(ns4 || ns6),
//cross-browser functionality . . .
getEventMouseX: function(e) { return this.ieMouse ? window.event.clientX : e.pageX;},
getEventMouseY: function(e) { return this.ieMouse ? window.event.clientY : e.pageY;},
//array of functions accepting all cross-browser mouse parameters
onMouseUpFuncs: new Array(),
onMouseDownFuncs: new Array(),
onMouseMoveFuncs: new Array(),
addUpFunc: function (func) { this.onMouseUpFuncs.push(func); },
addDownFunc: function (func) { this.onMouseDownFuncs.push(func); },
addMoveFunc: function (func) { this.onMouseMoveFuncs.push(func); },
// ******** begin callback code ********
//notice - within callback code 'this' refers to the callee, not mouseh, so you gotta reference mouseh specifically
onMouseUp: function (e) {
var x = mouseh.getEventMouseX(e);
var y = mouseh.getEventMouseY(e);
for (i in mouseh.onMouseUpFuncs) {
mouseh.onMouseUpFuncs[i](x,y);
}
},
onMouseDown: function (e) {
var x = mouseh.getEventMouseX(e);
var y = mouseh.getEventMouseY(e);
//cycle through all preregistered functions and execute them . . .
for (i in mouseh.onMouseDownFuncs) {
mouseh.onMouseDownFuncs[i](x,y);
}
},
onMouseMove: function (e) {
var x = mouseh.getEventMouseX(e);
var y = mouseh.getEventMouseY(e);
//cycle through all preregistered functions
for (i in mouseh.onMouseMoveFuncs) {
mouseh.onMouseMoveFuncs[i](x, y);
}
//store the last mouse coords
mouseh.lastpos.x = x;
mouseh.lastpos.y = y;
},
// ******** end callback code ********
hasMouseBeenInitialized: false,
init: function () {
if (this.hasMouseBeenInitialized) return;
if (ie4) {
document.captureEvents(Event.MOUSEMOVE | Event.MOUSEDOWN | Event.MOUSEUP | Event.MOUSEDBLCLICK);
}
addListener(document, "mousedown", this.onMouseDown);
addListener(document, "mousemove", this.onMouseMove);
addListener(document, "mouseup", this.onMouseUp);
this.hasMouseBeenInitialized = true;
}
};
// ******************************** opacity ******************************** //
//todo - detect which method to use (browser-based?) and only set the single required property from there
//rather than the excessive property setting as we have it
function setOpacity(obj, opacity) {
//why do you suppose this line is needed?
opacity = (opacity == 100)?99.999:opacity;
// IE/Win
obj.style.filter = "alpha(opacity:"+opacity+")";
//oldschool IE/Win?
if (obj.style.filters && obj.style.filters.item) {
obj.style.filters.item("DXImageTransform.Microsoft.Alpha").opacity = opacity;
}
// Safari<1.2, Konqueror
obj.style.KHTMLOpacity = opacity/100;
// Older Mozilla and Firefox
obj.style.MozOpacity = opacity/100;
// Safari 1.2, newer Firefox and Mozilla, CSS3
obj.style.opacity = opacity/100;
}
// ******************************** generic functions ******************************** //
//how to grab the absolute position of some HTML object
function getAbsolutePosition(n) {
var pos = {x:0, y:0};
do {
pos.x += n.offsetLeft;
pos.y += n.offsetTop;
} while (n = n.offsetParent);
return pos;
}
//Recursive call for "searchDOMTree". can we make this method private to this file only?
//originally key == "className", val == user-defined
//AND key == "nodeName", val == "UL"
function searchDomTreeR(node, key, val, child, dest) {
//see if we should add this node
if (node[key] == val) {
dest.push(node);
//if we dont want to search through children - and we found this node - then return
if (!child) return;
}
//test all its children
for (var ch = node.firstChild; ch; ch = ch.nextSibling) {
searchDomTreeR(ch, key, val, child, dest);
}
}
//function for searching through the DOM tree and returning all of objects for which one property equals one value
//search for all UL nodes with matching className. do not search the children of parents we have found
//node: which node to start at
//key: what key to pick out
//val: the sought after value of the specified key
//child: boolean flag whether to search children of found objects
function searchDomTree(node, key, val, child) {
var dest = new Array();
searchDomTreeR(node, key, val, child, dest);
return dest;
}
//same as above but with an array rather than a DOM tree
function searchArray(ar, key, val) {
var dest = new Array();
for (i in ar) {
a = ar[i];
if (a[key] == val) dest.push(a);
}
return dest;
}
// timer functions
var lastCloseTime = null;
var lastCloseMenu = null;
var currentSectionOpen = "sideFun";
function processMessages() {
window.setTimeout(processMessages, 100);
if (lastCloseMenu && lastCloseTime) {
var thisTime = new Date();
//if a 'last close time' exists (non-null) and has passed by more than N second
//(one-second delay)
if (lastCloseTime.getTime() + 500 < thisTime.getTime()) {
//then close the menu
lastCloseMenu.closeList();
lastCloseMenu = null;
lastCloseTime = null;
}
}
}
function requestClose(menu) {
lastCloseMenu = menu;
lastCloseTime = new Date();
}
function clearCloseRequest() {
lastCloseMenu = null;
lastCloseTime = null;
}
//utility / cross browser
//testing parentNode is not a valid way in IE to see if an object has been removed from its parent
//why? because in IE once removed the object still retains its parentNode value
//if so then how do we determine whether it is attached to the tree or not?
function nodeIsAttached(n) {
/* if mozilla or other standard-compliant browser: *
return !!n.parentNode;
/**/
/* (this still isn't working with IE) *
var p = n.parentNode;
if (!p) return false;
//manually go through the parent's children, checking to see if 'n' is one of them
for (var ch = p.firstChild; ch; ch = ch.nextSibling) {
if (ch == n) return true;
}
return false;
/**/
/* final option - just switch the display: */
return n.style.display != "none";
/**/
}
//attach the node to the
function attachNode(parent, node) {
/* the mozilla way . . . *
parent.appendChild(node);
/**/
/* IE compatible alternative */
//todo - if node.defaultDisplay is null then set style.display to the default display style for the node (this varies depending on the node tag name)
if (!node.defaultDisplay) node.defaultDisplay = "block";
node.style.display = node.defaultDisplay;
//else . . . error . . . you should have removed it before attaching it again !
/**/
}
function removeNode(parent, node) {
/* standards compliant: *
parent.removeChild(node);
/**/
/* oldschool-IE compatible */
if (node.style.display != "none") node.defaultDisplay = node.style.display; //store for restoring
else node.defaultDisplay = "block"; //is it always block? isnt this conditional depending on the nodeName?
//alert('setting default display as ' + node.defaultDisplay + ' for node type ' + node.tagName + ' parent type ' + parent.tagName);
node.style.display = "none";
/**/
}
// menu initialization
var lastOpenList;
function fix_li(li) {
li.uls = [];
for (var ch = li.firstChild; ch; ch = ch.nextSibling) {
if (ch.nodeName == "UL") {
//now that we've found a UL within our base UL, cut it off and link it separately through an extra field in the child li . . .
//childULs will be a parameter of each li pointing to all children ULs within it . .
li.uls.push(ch);
removeNode(li, ch);
}
}
//if we found any ULs in this child . ..
if (li.uls.length) {
//give it a mouseover to reattach the child UL's
li.openList = function() {
//allow only one open at a time
if (lastOpenList) {
lastOpenList.closeList();
}
lastOpenList = this;
//if we had a menu close request then clear it . . .
clearCloseRequest();
for (i in this.uls) {
var ul = this.uls[i];
//if the ul is not attached then append ul to the end of the li's children . . .
if (!nodeIsAttached(ul)) attachNode(this, ul);
}
}
li.closeList = function() {
//allow only one open at a time:
if (lastOpenList == this) { //this should be the only case in which lastOpenList exists
lastOpenList == null;
}
for (i in this.uls) {
var ul = this.uls[i];
if (nodeIsAttached(ul)) removeNode(ul.parentNode, ul);
}
}
/* pop up on roll over *
li.onmouseover = li.openList;
/**/
/* pop up on click *
li.onclick = li.openList;
/**/
/* toggle open/close on click */
//conditional - solely the link if a link is first, else do the whole li
if (li.firstChild.nodeName == "A") {
li.firstChild.onclick = function() {
var parent = this.parentNode;
if (parent.uls.length && nodeIsAttached(parent.uls[0])) {
parent.closeList();
} else {
parent.openList();
}
}
} else {
li.onclick = function() {
if (this.uls.length && nodeIsAttached(this.uls[0])) {
this.closeList();
} else {
this.openList();
}
}
}
/**/
}
}
function create_sliding_menu(ul) {
//so here, see if we can disconnect all child UL's
//instead apply them as separate fields
//and, upon mouseover, reattach them . . .
ul.lis = [];
//first search through the UL for all LI children
for (var ch = ul.firstChild; ch; ch = ch.nextSibling) {
if (ch.nodeName == "LI") {
//now, within the LI, search for any UL's . . .
fix_li(ch);
//add it to the list
ul.lis.push(ch);
/*
note to self:
looks like, in IE, the link will only fill the whole contents of its containing LI unless
within that LI is a UL with display set to 'block' and also possessing at least one of its own LI nodes
AND in doing so the 4-pixel overlap that IE typically has with first-level LI's is mysteriously removed
... so we no longer need to compensate for that.
*/
//if detect IE then
var eli = document.createElement('li');
eli.style.display = 'none';
var eul = document.createElement('ul');
eul.style.display = 'block';
eul.style.height = '0px';
eul.style.margin = '0px';
eul.appendChild(eli);
ch.appendChild(eul);
}
}
//how about this . . . when the mouse exits the UL, add in a timer function that
//sends a close command to issue after a few seconds.
//however, if an open occurs within that time, cancel the close request
ul.closeList = function() {
for (i in this.lis) {
var li = this.lis[i];
if (li.closeList) {
li.closeList();
}
}
}
//todo - rather than 'ontimeout', we should add a mouse movement listener
//likewise, parellel with the mouse library, we should no longer use the onMouseMove, etc, etc, functions
//or make an array of functions of our own . . .
//looks like we're going to be passing on mouseout closes
// ul.onmouseout = function() {
// requestClose(ul);
// }
}
function initialize_sliding_menu() {
var ar = document.getElementById('nav');
create_sliding_menu(ar);
//init our mouse movement code
//for later - i'm going to override all the 'onmouseover' and 'onmouseout'
//considering how well they're working . ..
mouseh.init();
//todo - add mouse events surrounding the sliding menus (proly within create_sliding_menu) and depend on that rather than 'onmouseover' / 'onmouseout'
//can we add an event listener for this as well? or does one override another? can multiple timeouts be set?
//we only need ths if we ever call requestClose()
// window.setTimeout(processMessages, 100);
var first = document.getElementById(currentSectionOpen);
if (first && first.openList) first.openList();
}
//this should swap out the first matching id with our rotating image list
addListener(window, "load", function() {initialize_sliding_menu();});