/*************************  Expanding Menu *************************
2-level DHTML navigation menu.
The menu toggles superlink display of sublinks, with specialized styles, and passes individualized responses to menu items.
It can be instantiated as a single (columnar) clamshell menu or as (a horizontal navbar of) multiple drop-down menus.
Can be used in conjunction with ThoughtMesh.js to enable tag-based navigation and remote content selection via pseudo-GET variables in the url.
Version 4.4, modified by Jon Ippolito to fix bug in passing id as argument to respondAsIf().
UPDATE: enable processing of only a tag link.

************************** Directions for Use **********************
CREATE AN HTML MENU.
Menulinks go in <div>s wrapped in a <div id="yourChoiceOfMenuId">, eg:
<div id="fruit-menu">
	<div id="apples">Apples</div>
		<div id="apples-granny">Granny Smith</div>
		<div id="apples-red">Red Delicious</div>
		<div id="apples-mcintosh">McIntosh</div>
	<div id="oranges">Oranges</div>
		<div id="oranges-valencia">Valencia</div>
		<div id="oranges-navel">Navel</div>
		...
		
CREATE HTML CONTENT.
Content goes in <div>s with ids; this obviates annoying escaped characters in dynamically written content. 
Set the initial style of these <div>s to display: none; clicking on the items in your menu will reveal them.

ADD THE SCRIPT.
Include this script in the <head> of the Web page:
<script type="text/javascript" language="JavaScript" src="tech/ExpandingMenu.js"></script>
Then instantiate the menu with your preferences onload, eg:
<body onload="fruitMenu = new ExpandingMenu({
		menuId: 'fruit-menu', 
		isTwoLevelMenu: true, 
		collapseOnParentClick: true,
		collapseOnOtherParentClick: false ,
		useDefaultContentManagement: true
	}); fruitMenu.prepareMenu()"
>
You can also instantiate ExpandingMenu with different ids to create multiple menus.

CUSTOMIZE BEHAVIOR.
The easiest approach is to set useDefaultContentManagement to true when you instantiate the menu.
This option requires:
* Menu ids are associated by hyphens, eg the "apples-red" menulink is a child of the "apples" category.
* Content ids must look like "content-apples", "content-apples-granny", etc.
If you prefer to customize ids and behaviors, set useDefaultContentManagement to false and use these methods:
* associateChildren()
* associateContent()
* setInitialCondition()
To trigger menu actions from other links, you currently have to use this (clumsy) approach:
    document.getElementById( "menulink-fun-3" ).menuItem.respond( {  menuItemEle: document.getElementById(    "menulink-fun-3"    )  } )
    [UPGRADE: Simplify this.]

STYLE THE MENU.
You can customize these classnames for menu items in your stylesheet:
"menulink-bachelor-unselected" 
"menulink-bachelor-selected" 
"menulink-parent-collapsed-unselected"
"menulink-parent-collapsed-selected"
"menulink-parent-expanded-unselected"
"menulink-parent-expanded-selected"
"menulink-child-unselected"
"menulink-child-selected"
Note that some styles must currently hard-coded into setMenuResponse(). [UPGRADE: extract styles from ExpandingMenu.js.]

ENABLE REMOTE CONTENT SELECTION.
You can enable lexia selection via anchors in the url (eg, http://mysite.com/index.html#introduction).
You can also enable tag selection via the url when ThoughtMesh is active (eg, http://mysite.com/index.html?community&defect#introduction )

ENABLE PRINTING.
Requires this file:
<script type="text/javascript" src="tech/sniff.js"></script>
You must also put an empty file in the directory called empty.html to print.
Styles are assumed to be in a file called tech/print.css.

ENABLE DEBUGGING.
Link to the script debug.js by Jon Ippolito from your HTML file, and follow its instructions to open a debugging window.
*************************************************************************/
// Test for debugging script, and disable the debug function if not found.
if (typeof isDebugOn == "undefined") {
	debug = function() {} ; // Do nothing.
	debugIsOn = false ;
}
function MenuItem(argsObj) {
	 // {htmlElement:document.getElementById("myListElement"), responseFunction:myFunction}
	this.htmlElement = argsObj.htmlElement;
	this.responseFunction = (argsObj.responseFunction)? argsObj.responseFunction : "none" ;
	this.htmlElement.style.display = "block";
	this.htmlElement.onclick = this.respond ;
	this.htmlElement.menuItem = this ;
	this.linkType = "bachelor" ; // Default--to be modified later based on associateChildren calls.
	this.htmlElement.onmouseover = actOnMouseover ;
	this.htmlElement.onmouseout = actOnMouseout ;
}
function actOnMouseover(e) {
    return eval( this.menuItem.funMouseover ) ;
}
function actOnMouseout(e) {
    return eval( this.menuItem.funMouseout ) ;
}
MenuItem.prototype.setClasses = function(classObj) {
    this.funMouseover = classObj.argMouseover;
    this.funMouseout = classObj.argMouseout;
	this.classBachelorUnselected = classObj.argBachelorUnselected ;
	this.classBachelorSelected = classObj.argBachelorSelected ;
	if (this.htmlElement.menu.isTwoLevelMenu) { // This argument can be omitted for 1-level menus.
        this.classParentCollapsedUnselected = classObj.argParentCollapsedUnselected ;
        this.classParentCollapsedSelected = classObj.argParentCollapsedSelected ;
        this.classParentExpandedUnselected = classObj.argParentExpandedUnselected ;
        this.classParentExpandedSelected = classObj.argParentExpandedSelected ;
        this.classChildUnselected = classObj.argChildUnselected ;
        this.classChildSelected = classObj.argChildSelected ;
    }
	/* UPGRADE: DO FOLLOWING LATER...MAYBE.
	//You only have to set the selections you want; otherwise they default to the last defined one.
	if (classObj.selected0) {
		this.classSelected0 = classObj.selected0;
		this.classSelected1 = classObj.selected0;
		if (classObj.selected1) {
			this.classSelected1 = classObj.selected1;
		}
	}
	*/
}
MenuItem.prototype.associateContent = function(contentEle){
    // "this" is the JS object whose name is the same as the id for the menulink in question.
	this.content = contentEle ; // The content div (htmlElement) associated with that menulink.
	this.content.menuItem = this ; // Allows you to identify link if you know the content.
	// UPGRADE: Is it a problem that it's the same name as the handle to the menuItem object from the menuItem htmlElement?
}
MenuItem.prototype.associateChildren = function(childrenArr) { //[petMenu.itemManager.itemDante , petMenu.itemManager.itemCritter]
    this.linkType = "parent" ;
	// .children is an array of  JS menuItem objects.
	// You cannot simply assign one array to be equal to another--you must write it out in a loop.
	// I'm trying to write this so you can call associateChildren more than once for the same parent.
	if (!this.children) this.children = new Array() ;
	for (var childNum=0; childNum<childrenArr.length; childNum++) {
		this.children.push( childrenArr[childNum] ) ;
		this.children[this.children.length-1].dad = this ;
		this.children[this.children.length-1].linkType = "child" ;
	}
}
MenuItem.prototype.areChildrenOpen = function() {
	// "this" is the menuItem, ie the JS wrapper of the div in the menu.
	_this = this.htmlElement.id ; debug("_this")
	debug("'areChildrenOpen called:'",1,"start")
    _parentItem = this.htmlElement.id ; debug("_parentItem", 3) ;
    var childItems = this.children ;
	for (var childCounter=0; childCounter < childItems.length; childCounter++) {
		_childItem = childItems[childCounter].htmlElement.id ; debug("_childItem", 2) ;
		_childDisplayStatus = this.children[0].htmlElement.style.display; debug("_childDisplayStatus") ;
	};
	debug("'areChildrenOpen done.'",1,"end")
    return (this.children[0].htmlElement.style.display != "none")? true : false ;
}
MenuItem.prototype.respond = function(argObj) {
	 // argObj can be empty or { menuItemEle: document.getElementById("my-link")}
    debug("'beginning response'",1,"start")
    // If there's no argument, assume "this" is the menuItem's html element, because you clicked on it.
    if (typeof argObj != "undefined") {
        // Firefox will assume argObj is the mouse event if you don't specify it more precisely:
        var menuItemEle = ( typeof argObj.menuItemEle == "undefined" )? this : argObj.menuItemEle ;
    }
    else {
        // IE won't recognize argObj if it's not specified in the function call.
        var menuItemEle = this ;
    }
	// DESELECT ALL STYLES
	menuItemEle.menu.deselectAllItems(); // menuItemEle does not hide children, just deselects them.
	//*********************** SET DISPLAY OF CONTENT *********************** 
	if (menuItemEle.menu.useDefaultContentManagement) {
        //Display only the content of menuItemEle item.
        menuItemEle.menu.hideAllContent();
        menuItemEle.menuItem.content.style.display = "block";
	}
	//*********************** SET DISPLAY AND STYLE OF menuItemEle ITEM'S CHILDREN *********************** 
	//If the item is a superlink, reset the style and/or display of all children.
	// __________ YOU CLICKED ON A PARENT _________
	if ( menuItemEle.menuItem.linkType == "parent" ) {
        debug("'it is a parent'")
		if ( menuItemEle.menu.collapseOnOtherParentClick ) {
			for (var itemCounter=0; itemCounter < menuItemEle.menu.itemManager.length; itemCounter++) {
				var notMyChild = ( menuItemEle.menuItem != menuItemEle.menu.itemManager[itemCounter].dad ) ;
				if ( menuItemEle.menu.itemManager[itemCounter].linkType == "child" && notMyChild ) {
					menuItemEle.menu.itemManager[itemCounter].htmlElement.style.display = "none" ;
				}
			};
		}
        _kidsOpen = menuItemEle.menuItem.areChildrenOpen(); debug("_kidsOpen", 4)
		if ( !menuItemEle.menuItem.areChildrenOpen() ) {		//If the superlink's children are not already open.
            debug("'children are not open'")
            // Display the children and give them unselected style.
			for (var itemNum=0; itemNum < menuItemEle.menuItem.children.length; itemNum++) {
                debug("'displaying child'")
				menuItemEle.menuItem.children[itemNum].htmlElement.style.display = "block";
				menuItemEle.menuItem.children[itemNum].htmlElement.className = menuItemEle.menuItem.children[itemNum].classChildUnselected;
			}
			// Set the style of menuItemEle parent link to expanded and selected.
			debug("'setting className'")
			menuItemEle.menuItem.htmlElement.className = menuItemEle.menuItem.classParentExpandedSelected ;
		}
		else { // If one or more children are already displayed.
            // Hide the children only if appropriate for this implementation.
            _collapseOnParentClick = menuItemEle.menu.collapseOnParentClick ; debug("_collapseOnParentClick", 4)
            if (menuItemEle.menu.collapseOnParentClick) {
                for (var itemNum=0; itemNum < menuItemEle.menuItem.children.length; itemNum++) {
                    menuItemEle.menuItem.children[itemNum].htmlElement.style.display = "none";
                }
                //Set the style of menuItemEle parent link to collapsed and selected.
                menuItemEle.menuItem.htmlElement.className = menuItemEle.menuItem.classParentCollapsedSelected ;
            }
            // If you're using this as a dropdown menu, then you'll want to show all children.
            else {
                for (var itemNum=0; itemNum < menuItemEle.menuItem.children.length; itemNum++) {
                    menuItemEle.menuItem.children[itemNum].htmlElement.style.display = "block";
                }
            }
		}
	}
    // __________ YOU CLICKED ON A CHILD _________
	else if (menuItemEle.menuItem.linkType == "child") {
		//If it's a sublink, reset the style of the sibling sublinks and the superlink.
        // Set the superlink to medium selectedness. UPGRADE: I THINK FOLLOWING DESELECTS ARE REDUNDANT.
        menuItemEle.menuItem.dad.htmlElement.className = menuItemEle.menuItem.dad.classParentExpandedUnselected;
        //Set the siblings to medium selectedness. Display them, just in case the link was not called from the menu.
        for (var itemNum=0; itemNum < menuItemEle.menuItem.dad.children.length; itemNum++) {
            menuItemEle.menuItem.dad.children[itemNum].htmlElement.style.display = "block" ;        
            menuItemEle.menuItem.dad.children[itemNum].htmlElement.className = menuItemEle.menuItem.dad.children[itemNum].classChildUnselected;
        }
        // Set menuItemEle child to selected.
        menuItemEle.menuItem.htmlElement.className = menuItemEle.menuItem.classChildSelected;        
    }
    // __________ YOU CLICKED ON A BACHELOR _________    
    else {
		//If the item is a childless parent.
        menuItemEle.menuItem.htmlElement.className = menuItemEle.menuItem.classBachelorSelected ;	
	}
	//*********************** HANDLE OTHER FUNCTIONS *********************** 
	debug("'handling other functions'")
	if (debugIsOn) {
        try {
            if (menuItemEle.menuItem.responseFun) eval(menuItemEle.menuItem.responseFun) ;
        }
        catch(e) {
            _choked_on_responseFun = menuItemEle.menuItem.responseFun; debug("_choked_on_responseFun", 9)
        }
    }
    else {
        if (menuItemEle.menuItem.responseFun) eval(menuItemEle.menuItem.responseFun) ;    
    }
    debug("'ending response'",1,"end")
	return false;
}
MenuItem.prototype.changeToRolloverStyle = function() {
    this.htmlElement.className = this.classRollover ;
}
MenuItem.prototype.associateResponse = function(responseObj) {
	this.responseFun = responseObj.responseFun;
}
function ExpandingMenu(argsObj) { 
	// Use different names for div id and js obj. Sample: {menuId: "navMenuBlock"}
    // Hide menu until you call setInitialCondition later.
    // You probably want to hide it in the css too.
    // This prevents ugly page load.
    this.htmlElement = document.getElementById(argsObj.menuId) ;
    this.htmlElement.menu = this ;
    this.id = argsObj.menuId + "Obj" ;
    // this.htmlElement.style.display="none";
    // Grab item anchors dynamically.
	this.itemArr = document.getElementById(argsObj.menuId).getElementsByTagName("div"); // Was "a".
	this.itemManager = new Array(); // Contains JS wrappers of HTML elements.
	for (var itemNum=0; itemNum < this.itemArr.length; itemNum++) {
		this.itemManager[itemNum] = new MenuItem({ htmlElement:this.itemArr[itemNum] });
		this.itemManager[this.itemArr[itemNum].id] = this.itemManager[itemNum];
		this.itemManager[itemNum].itemNumber = itemNum ;
		this.itemManager[itemNum].htmlElement.menu = this; // I'm not sure it's a good idea to make the handle from the html element...?
	}
	// Is this a two-level menu?
	this.isTwoLevelMenu = (typeof argsObj.isTwoLevelMenu == "undefined")? true : argsObj.isTwoLevelMenu ;
	// Do you want sublinks to collapse when user clicks on a parent?
	this.collapseOnParentClick = (typeof argsObj.collapseOnParentClick == "undefined")? true : argsObj.collapseOnParentClick ;
	this.collapseOnOtherParentClick = (typeof argsObj.collapseOnOtherParentClick == "undefined")? true : argsObj.collapseOnOtherParentClick ;
	// Do you want default content divs, or customized content management?
	this.useDefaultContentManagement = (typeof argsObj.useDefaultContentManagement == "undefined")? true : argsObj.useDefaultContentManagement ; // Boolean.
	if (this.useDefaultContentManagement) {
		this.prepareMenu() ;
	}
}
ExpandingMenu.prototype.hideAllContent = function() {
	for (var itemNum=0; itemNum < this.itemManager.length; itemNum++) {
		this.itemManager[itemNum].content.style.display = "none";
	}
}
ExpandingMenu.prototype.setInitialCondition = function(itemObjArg) {
	// UPGRADE: This is being called twice on load :P
	// Set initial menu item based on function argument--it may be overwritten later by remotely selected item.
	this.initialItemObj = itemObjArg ;
	initialId = this.initialItemObj.htmlElement.id; debug("initialId")
	// "this" means the menu.
	/* ___________________ Deselect everything. ___________________ */
	// Hide all child items.
	for (var itemNum=0; itemNum < this.itemManager.length; itemNum++) {
		if ( this.itemManager[itemNum].linkType == "parent" ) {
			for (var childNum=0; childNum < this.itemManager[itemNum].children.length; childNum++) {
				this.itemManager[itemNum].children[childNum].htmlElement.style.display = "none";
			}
		}
    }
    //Deselect all items.
    this.deselectAllItems() ;
	/* ___________________ Check for ThoughtMesh. ___________________ */
	// Check if ThoughtMesh implemented.
	this.hasThoughtMesh = false ;
	for (var i=0; i < document.getElementsByTagName("script").length; i++) {
		script_path = document.getElementsByTagName("script")[i].src ;
		if ( script_path.indexOf("ThoughtMesh") != -1 ) {
			this.hasThoughtMesh = true ;
		}
	};
	/* ___________________ Check for remote content request. ___________________ */
	// Using globals so I can package check in another fun called in correct order onload.
	debug("'Check for remote content request'")
	// Url should look like http://mysite.com/index.html?community&defect#introduction
	this.remoteContentRequested = false ;
	/* ___________________ Check for tags and/or anchor in url. ___________________ */
	this.tagsAreRequested = ( document.location.href.indexOf("?") != -1 );
	this.tagsAreNotAtEnd = ( document.location.href.indexOf("?") != document.location.href.length -1 );
	this.anchorExists = ( document.location.href.indexOf("#") != -1 ) ; 
	this.anchorIsNotAtEnd = ( document.location.href.indexOf("#") != document.location.href.length -1 );
	// Check if tags are requested, and subtract any anchor afterward. ___________________ */
	if (this.tagsAreRequested && this.tagsAreNotAtEnd) {
		this.remotelyRequestedContent = document.location.href.split("?")[1] ;
		_this_remoteContentRequest =	this.remotelyRequestedContent ; debug("_this_remoteContentRequest") ;
		// If url contains an anchor, ExpandingMenu will use that to override which content to show first.
		// The anchor name must be the id of the appropriate menu item (such as "bio-cv").
		if (this.anchorExists && this.anchorIsNotAtEnd) {
			// Subtract tags from anchor string.
			this.remoteTagsAsString = this.remotelyRequestedContent.split("#")[0] ;
			this.remotelyRequestedTags = this.remoteTagsAsString.split("&") ;
			this.remotelyRequestedAnchor = this.remotelyRequestedContent.split("#")[1] ;
		}
		else { // Tags but no anchor.
			this.remotelyRequestedTags = this.remotelyRequestedContent.split("&") ;
		}
		this.remoteContentRequested = true ;
	}
	// Check if anchor present without tags.
	if (this.anchorExists && this.anchorIsNotAtEnd) {
		// Subtract tags from anchor string.
		this.remotelyRequestedAnchor = this.remotelyRequestedContent = document.location.href.split("#")[1] ;
		this.remoteContentRequested = true ;
	}
}
ExpandingMenu.prototype.displayInitialCondition = function() {
	debug("'displayInitialCondition'")
	_anchorExists = this.anchorExists; debug("_anchorExists")
	_anchorIsNotAtEnd=this.anchorIsNotAtEnd; debug("_anchorIsNotAtEnd")
	_tagsAreRequested=this.tagsAreRequested; debug("_tagsAreRequested")
	_hasThoughtMesh=this.hasThoughtMesh; debug("_hasThoughtMesh")
	/* ___________________ Set remotely requested item. ___________________ */
	if ( typeof this.remotelyRequestedAnchor != "undefined" ) {
		var itemCandidateEle = document.getElementById( this.remotelyRequestedAnchor )
		if ( itemCandidateEle != null ) { // Anchor corresponds to menu item.
			this.initialItemObj = itemCandidateEle.menuItem  ; // Overwrites default initial item from setInitialCondition().
			requestedItem = this.initialItemObj; debug("requestedItem")
		}
	}
	/* ___________________ Set remotely requested tags. ___________________ */
	if ( this.hasThoughtMesh &&  typeof this.remotelyRequestedTags != "undefined" ) {
		remotelyRequestedTags =		this.remotelyRequestedTags ; debug("remotelyRequestedTags") ;
		respondToTag({tagArg: this.remotelyRequestedTags[0], linkType: "replace"}) ;
		remotelyRequestedTags_0 =			this.remotelyRequestedTags[0] ; debug("remotelyRequestedTags_0", 3) ;
		for (var tagCounter=1; tagCounter < this.remotelyRequestedTags.length; tagCounter++) {
			respondToTag({tagArg: this.remotelyRequestedTags[tagCounter], linkType: "plus"}) ;
			remotelyRequestedTags_tagCounter =			this.remotelyRequestedTags[tagCounter] ; debug("remotelyRequestedTags_tagCounter") ;
		};
	}
	/* ___________________ Show appropriate menu item and content. ___________________ */
    // Set a selected item if user requests one.
    if (typeof this.initialItemObj != "undefined") {
        if ( this.initialItemObj.linkType == "bachelor" ) {
            this.initialItemObj.htmlElement.className = this.initialItemObj.classBachelorSelected ;
        }
        else if ( this.initialItemObj.linkType == "parent" ) {
            this.initialItemObj.htmlElement.className = this.initialItemObj.classParentCollapsedSelected ;
        }
        else { // Must be a child.
            // Set this item's style.
            this.initialItemObj.htmlElement.className = this.initialItemObj.classChildSelected ;
            // Show the child's siblings, but leave their style unselected.
			for (var childNum=0; childNum < this.initialItemObj.dad.children.length; childNum++) {
				this.initialItemObj.dad.children[childNum].htmlElement.style.display = "block";
			}
			// Change the parent's style.
            this.initialItemObj.dad.htmlElement.className = this.initialItemObj.dad.classParentExpandedSelected ;			
        }
    }
	else { // No remotely requested content--default to first menu item.
		this.initialItemObj = this.itemManager[0] ;
	}
    // Turn on display of the menu (initially hidden by ExpandingMenu constructor).
    this.htmlElement.style.display="block";
    // Show content div if user chooses the menu's default content management.
    if ( this.useDefaultContentManagement ) {
        this.initialItemObj.content.style.display = "block" ;
    }
	this_hasThoughtMesh =	this.hasThoughtMesh ; debug("this_hasThoughtMesh") ;
	if (this.hasThoughtMesh && this.remoteContentRequested) {
		hideCloud( document.getElementById('thoughtmesh-header-id'), true ); 
		document.getElementById('content').style.display='block'
	}
	return false;
}
ExpandingMenu.prototype.deselectAllItems = function() {
    // Deselects styles of all menu items, without affecting whether children are hidden or shown. 
	for (var itemNum=0; itemNum < this.itemManager.length; itemNum++) {
        if ( this.itemManager[itemNum].linkType == "bachelor" ) {
            this.itemManager[itemNum].htmlElement.className = this.itemManager[itemNum].classBachelorUnselected;
        }
        if ( this.itemManager[itemNum].linkType == "parent" ) {
            if ( this.itemManager[itemNum].areChildrenOpen() ) {
                this.itemManager[itemNum].htmlElement.className = this.itemManager[itemNum].classParentExpandedUnselected ;
            }
            else { // No children open for this parent.
                this.itemManager[itemNum].htmlElement.className = this.itemManager[itemNum].classParentCollapsedUnselected ;
            }
        }
        if ( this.itemManager[itemNum].linkType == "child" ) {
            this.itemManager[itemNum].htmlElement.className = this.itemManager[itemNum].classChildUnselected;
        }
	}
}
ExpandingMenu.prototype.generatePrintableText = function() { // UPGRADE: Add to argsObj to customize title, pagebreaks, styles, stylesheet name, etc.
    // UPGRADE: Make the printable version into an object of its own?
    this.printableTextVar = "<h1>" + document.title + "</h1>" ;
    // this.printableTextVar += "<div>" + document.getElementById("image-print").innerHTML + "</div>" ;
    this.printableTextVar += "<h4>This is a dynamically generated synopsis of the site '" + document.title + "' in printable form. " ;
    // UPGRADE: INSERT CUSTOM URL OPTION.
    this.printableTextVar += "You can find the interactive version at " + document.location.href + ".</h4>" ;
	for (var itemNum=0; itemNum < this.itemManager.length; itemNum++) {
            /* UPGRADE: ENABLE PAGEBREAK CODE BELOW:
                // Set any desired pagebreaks manually.
                contentDivs[contentDivs.length-1].extraStyle = "" ;
                var idsWithPageBreaksArr = new Array("desc_var", "desc_ope", "desc_min", "desc_mar")
                for ( var idNum = 0; idNum < idsWithPageBreaksArr.length; idNum++ ) {
                    if ( contentDivs[contentDivs.length-1].id == idsWithPageBreaksArr[idNum] ) {
                        contentDivs[contentDivs.length-1].extraStyle = " style='page-break-before: always;' "
                    }
                }
            */
        // Handle headings.
        // Use this for auto headings: // UPGRADE: ADD TEST FOR PARENT LINKS TO GIVE DIFFERENT h's.
        if (this.itemManager[itemNum].linkType == "child") {
            this.printableTextVar += "<h3>" + this.itemManager[itemNum].htmlElement.innerHTML + "</h3><br /><br />" ;
        }
        else {
            this.printableTextVar += "<h2>" + this.itemManager[itemNum].htmlElement.innerHTML + "</h2><br /><br />" ;
        }
            /* UPGRADE: ENABLE CUSTOM HEADING CODE BELOW?
                // Or set headings manually:
                if ( link == menuHeadingsArr[0].getElementsByTagName("a").length ) {
                    printableTextVar += "<div class='emph2'>r e c e n t &nbsp; S t i l l &nbsp; W a t e r &nbsp; p r o j e c t s</div>";
                }
                if ( link == menuHeadingsArr[0].getElementsByTagName("a").length + menuHeadingsArr[1].getElementsByTagName("a").length ) {
                    printableTextVar += "<div class='emph2'>o n g o i n g &nbsp; S t i l l &nbsp; W a t e r &nbsp; p r o j e c t s</div>";
                }
                if ( link == menuHeadingsArr[0].getElementsByTagName("a").length + menuHeadingsArr[1].getElementsByTagName("a").length + menuHeadingsArr[2].getElementsByTagName("a").length ) {
                    printableTextVar += "<div class='emph2'>r e s e a r c h &nbsp; i n t e r e s t s</div>";
                }
            */
            // Capture what goes under the headings.
            this.itemManager[itemNum].extraStyle = "" ; // UPGRADE: ENABLE THIS?
            this.printableTextVar += "<div " + this.itemManager[itemNum].extraStyle + ">" + this.itemManager[itemNum].content.innerHTML + "</div>" ;
        }
}
ExpandingMenu.prototype.openPrintableWindow = function() {
        if ( (browsers.mac && browsers.ie) || (browsers.ns4) || (browsers.saf) ) {
            alert("We're sorry, your browser does not support this action.\n\nPlease consider upgrading to a standards-compliant browser like Firefox.") ;
            return false;
        }
        // YOU HAVE TO PUT AN IMAGE (POSSIBLY HIDDEN) IN YOUR HTML CALLED image-print.
		this.htmlVar = this.printableTextVar ;
		this.printableWindowVar = window.open('empty.html','printableWindowName','status=yes,scrollbars=yes,resizable=yes,width=750,height=550,top=0,left=200') ;
        this.htmlHeader = "<html><head>" ;
        this.htmlHeader += "<link rel=stylesheet href='tech/print.css' type='text/css' />" ;
        // UNUSED: htmlHeader+= "<link rel=stylesheet href='tech/print_styles.css' type='text/css' media='print' />" ;
        this.htmlHeader += "</head><body>" ;
		this.htmlVar = this.htmlHeader + this.htmlVar + "</body></html>" ;
		this.printableWindowVar.document.open() ;
		this.printableWindowVar.document.write(this.htmlVar) ;
		this.printableWindowVar.document.close() ;
}
//____________________ Methods called by useDefaultContentManagement ___________________ //
ExpandingMenu.prototype.prepareMenu = function() {
    //Associate superlinks with sublinks.
    // Assume the first link may be a parent.
    menuParentCandidateObj = this.itemManager[0] ;
    for (var item=1; item < this.itemManager.length; item++) {
        // If the link id has no hyphen, then assume it may be a parent.
        if (this.itemManager[item].htmlElement.id.indexOf("-") == -1 ) {
            menuParentCandidateObj = this.itemManager[item] ;
             //_parentCandidate = this.itemManager[item].htmlElement.id ; debug("_parentCandidate") ;
        }
        // If the link id has a hyphen, associate it with the parent.
        else {
            menuParentCandidateObj.associateChildren(  [ this.itemManager[item] ]  ) ;
             //_childCandidate = this.itemManager[item].htmlElement.id ; debug("_childCandidate") ;
        }
    }
    //Here we automate these assignments for each particular application.
    //Associate all the content using a formulaic approach.
    for (var counter=0; counter < this.itemManager.length; counter++) {
        var contentIdStr = "content-" + this.itemManager[counter].htmlElement.id;
		try {
	        this.itemManager[counter].associateContent( document.getElementById(contentIdStr) );
		}
		catch (e) { // There's a content mismatch in your divs.
			_mismatchError = "ExpandingMenu could not associate menu and content divs for id = <em>" + contentIdStr + "</em>";
			debug("_mismatchError", 6) ;
		}
    }
    // Set classes and custom menu response using formulaic approach based on id nomenclature.
    for (var item=0; item < this.itemManager.length; item++) {
        var itemClassesObj = {
            argBachelorUnselected: "menulink-bachelor-unselected", 
            argBachelorSelected: "menulink-bachelor-selected", 
            argParentCollapsedUnselected: "menulink-parent-collapsed-unselected",
            argParentCollapsedSelected: "menulink-parent-collapsed-selected",
            argParentExpandedUnselected: "menulink-parent-expanded-unselected",
            argParentExpandedSelected: "menulink-parent-expanded-selected",
            argChildUnselected: "menulink-child-unselected",
            argChildSelected: "menulink-child-selected",
            argMouseover: "this.style.cursor = 'pointer'; " ,
            argMouseout: "this.style.cursor = 'default'; "
        }
        /* Use if you want a special style for parent menu items.
        if (this.itemManager[item].linkType != "child") {
            // WAS itemClassesObj.argMouseover = "this.style.cursor = 'pointer'; this.style.border = 'dashed 2px orange'; " ;
            itemClassesObj.argMouseover = "this.style.cursor = 'pointer'; " ;
            itemClassesObj.argMouseout = "this.style.cursor = 'default'; " ;
        }
        */
        this.itemManager[item].setClasses( itemClassesObj ) ;
    }
    // Initialize the menu and choose an initial item to select.
    this.setInitialCondition( this.itemManager[0] );   
}
//____________________ Other useful functions ___________________ //
function respondAsIf(menuItemArg) {
	if (typeof menuItemArg == "string") { // An id was passed.
		document.getElementById(menuItemArg).menuItem.respond(  { menuItemEle: document.getElementById(menuItemArg) }  ) ;
	}
	else { // The element itself was passed.
	    menuItemArg.menuItem.respond({menuItemEle: menuItemArg}) ;
	}
}
function nextContent(argObj) { // argObj looks like { menuContentEle: this [, menuIdArg: "home-menu"] }. Adds a "next slide" button in your content <div>s.
	var menuId = (typeof argObj.menuIdArg == "undefined")? "home-menu" : argObj.menuIdArg ;
	var menuObj = document.getElementById( menuId ).menu ;
	var menuContentEle = argObj.menuContentEle ;
    // nextContent should be called from <a> in content div. anchorEle is typically "this"; we'll back up the DOM ladder until we get to the content div.
	if ( menuContentEle.nodeName.toLowerCase() != "a" ) { // For backward compatibility. UPGRADE: DEPRECATED?
		window.status = "WARNING: incorrect argument for nextContent function." ;
	}
	while ( menuContentEle.id.indexOf("content-") == -1 ) { // Go up to a parent until the div's id looks like "content".
		menuContentEle = menuContentEle.parentNode ;
	}
	menuItemObj = menuObj.itemManager[ (menuContentEle.menuItem.itemNumber + 1) % menuObj.itemManager.length ] ; // Mod tells call at the end of the HTML file to go back to beginning.
    menuItemObj.respond({ menuItemEle: menuItemObj.htmlElement }) ;
}
ExpandingMenu.prototype.setMenuResponse = function(argObj) { // Controls cross-menu behavior when you have instantiated more than one.
    // This particular response function must be called after parent-child relationships established.
	// UPGRADE: Not tested with ThoughtMesh!
    var menuSelected = this.htmlElement.id + "Obj" ;
    var responseFunVar = " " ;
    for ( var menuNum = 0; menuNum < argObj.menusNotSelected.length ; menuNum++ ) {
        responseFunVar += " " + argObj.menusNotSelected[menuNum] + ".setInitialCondition( " + argObj.menusNotSelected[menuNum] + ".itemManager[0] ); " ;
    }
    // Collapse menu selected if you clicked on a child (expand if you didn't).
    if ( this.itemManager[argObj.item].linkType == "child" ) {
        responseFunVar += " " + menuSelected + ".setInitialCondition(" + menuSelected + ".itemManager[0] );" ;
        responseFunVar += " " + menuSelected + ".itemManager[" + argObj.item + "].htmlElement.style.display = 'block' ; " ;
        responseFunVar += " " + menuSelected + ".itemManager[" + argObj.item + "].htmlElement.style.color = 'paleturquoise' ; "; // Emulates visited link color.
        // WAS responseFunVar += " " + menuSelected + ".itemManager[" + argObj.item + "].htmlElement.style.border = 'solid 2px darkslategray' ; " ;        
    }
    for ( var menuNum = 0; menuNum < argObj.menusNotSelected.length ; menuNum++ ) {
        responseFunVar += " " + argObj.menusNotSelected[menuNum] + ".hideAllContent(); " ;
    }
    return responseFunVar ;
}
