Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations Mike Lewis on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

collapsible menu help

Status
Not open for further replies.

electronicmonkey

Technical User
Feb 19, 2007
45
GB
I am intending to use a collapsible menu similar to that used at (left side) . I have two problems however.
1. I want the menu to expand immediately on page load, without need to click on top bar
2. The menu is supposed to be Firefox compatible, but it is not. How can I fix this.


The package can be downloaded from
-----------------------------------
I have included the script below. CAN SOMEONE HELP AMMEND IT ? :


"
var remember = true; //Remember menu states, and restore them on next visit.
var contractall_default= false; //Should all submenus be contracted by default? (true or false)

var menu, titles, submenus, arrows, bypixels;
var heights = new Array();

var n = navigator.userAgent;
if(/Opera/.test(n)) bypixels = 2;
else if(/Firefox/.test(n)) bypixels = 3;
else if(/MSIE/.test(n)) bypixels = 2;

/////DD added expandall() and contractall() functions/////

function slash_expandall(){
if (typeof menu!="undefined"){
for(i=0; i<Math.max(titles.length, submenus.length); i++){
titles.className="title";
arrows.src = "slashfiles/expanded.gif";
submenus.style.display="";
submenus.style.height = heights+"px";
}
}
}

function slash_contractall(){
if (typeof menu!="undefined"){
for(i=0; i<Math.max(titles.length, submenus.length); i++){
titles.className="titlehidden";
arrows.src = "slashfiles/collapsed.gif";
submenus.style.display="none";
submenus.style.height = 0;
}
}
}


/////End DD added functions///////////////////////////////


function init(){
menu = getElementsByClassName("sdmenu", "div", document)[0];
titles = getElementsByClassName("title", "span", menu);
submenus = getElementsByClassName("submenu", "div", menu);
arrows = getElementsByClassName("arrow", "img", menu);
for(i=0; i<Math.max(titles.length, submenus.length); i++) {
titles.onclick = gomenu;
arrows.onclick = gomenu;
heights = submenus.offsetHeight;
submenus.style.height = submenus.offsetHeight+"px";
}
if(remember)
restore()
else if (contractall_default) //DD added code
slash_contractall() //DD added code
}

function restore() {
if(getcookie("menu") != null) {
var hidden = getcookie("menu").split(",");
for(var i in hidden) {
titles[hidden].className = "titlehidden";
submenus[hidden].style.height = "0px";
submenus[hidden].style.display = "none";
arrows[hidden].src = "slashfiles/collapsed.gif";
}
}
}

function gomenu(e) {
if (!e)
var e = window.event;
var ce = (e.target) ? e.target : e.srcElement;
var sm;
for(var i in titles) {
if(titles == ce || arrows == ce)
sm = i;
}
if(parseInt(submenus[sm].style.height) > parseInt(heights[sm])-2) {
hidemenu(sm);
} else if(parseInt(submenus[sm].style.height) < 2) {
titles[sm].className = "title";
showmenu(sm);
}
}

function hidemenu(sm) {
var nr = submenus[sm].getElementsByTagName("a").length*bypixels;
submenus[sm].style.height = (parseInt(submenus[sm].style.height)-nr)+"px";
var to = setTimeout("hidemenu("+sm+")", 30);
if(parseInt(submenus[sm].style.height) <= nr) {
clearTimeout(to);
submenus[sm].style.display = "none";
submenus[sm].style.height = "0px";
arrows[sm].src = "slashfiles/collapsed.gif";
titles[sm].className = "titlehidden";
}
}

function showmenu(sm) {
var nr = submenus[sm].getElementsByTagName("a").length*bypixels;
submenus[sm].style.display = "";
submenus[sm].style.height = (parseInt(submenus[sm].style.height)+nr)+"px";
var to = setTimeout("showmenu("+sm+")", 30);
if(parseInt(submenus[sm].style.height) > (parseInt(heights[sm])-nr)) {
clearTimeout(to);
submenus[sm].style.height = heights[sm]+"px";
arrows[sm].src = "slashfiles/expanded.gif";
}


}

function store() {
var hidden = new Array();
for(var i in titles) {
if(titles.className == "titlehidden")
hidden.push(i);
}
putcookie("menu", hidden.join(","), 30);
}

function getElementsByClassName(strClassName, strTagName, oElm){
var arrElements = (strTagName == "*" && document.all)? document.all : oElm.getElementsByTagName(strTagName);
var arrReturnElements = new Array();
strClassName = strClassName.replace(/\-/g, "\\-");
var oRegExp = new RegExp("(^|\\s)" + strClassName + "(\\s|$)");
var oElement;
for(var i=0; i<arrElements.length; i++){
oElement = arrElements;
if(oRegExp.test(oElement.className)){
arrReturnElements.push(oElement);
}
}
return (arrReturnElements)
}

function putcookie(c_name,value,expiredays) {
var exdate=new Date();
exdate.setDate(exdate.getDate()+expiredays);
document.cookie = c_name + "=" + escape(value) + ((expiredays==null) ? "" : ";expires="+exdate);
}

function getcookie(c_name) {
if(document.cookie.length > 0) {
var c_start = document.cookie.indexOf(c_name + "=");
if(c_start != -1) {
c_start = c_start + c_name.length + 1;
var c_end = document.cookie.indexOf(";",c_start);
if(c_end == -1)
c_end = document.cookie.length;
return unescape(document.cookie.substring(c_start, c_end));
}
}
return null;
}

window.onload = init;
if(remember) window.onunload = store;

"





 
try to change

window.onload = init;

into

window.onload = init(); slash_expandall();
 
Thanks . But the alteration gives a menu that is quite static and does not expand/contract. What I am looking for is an handler which will make the menu to "slide open" and for the slide to commence (and be visible) when the page loads.

 
You want to show the slide of the menu if the page loads?
you might try to change the function:

function slash_expandall(){
if (typeof menu!="undefined"){
for(i=0; i<Math.max(titles.length, submenus.length); i++){
var nr = submenus.getElementsByTagName("a").length*bypixels;
submenus.style.display = "";
submenus.style.height = (parseInt(submenus.style.height)+nr)+"px";
var to = setTimeout("showmenu("+i+")", 100);
if(parseInt(submenus.style.height) > (parseInt(heights)-nr)) {
clearTimeout(to);
submenus.style.height = heights+"px";
arrows.src = "slashfiles/expanded.gif";
}
}
}
}
 
Try this, it works for me:


var contractall_default= false; //Should all submenus be contracted by default? (true or false)
slash_expandall()
var speed = 100;

var menu, titles, submenus, arrows, bypixels;
var heights = new Array();

var n = navigator.userAgent;
if(/Opera/.test(n)) bypixels = 2;
else if(/Firefox/.test(n)) bypixels = 3;
else if(/MSIE/.test(n)) bypixels = 2;

/////DD added expandall() and contractall() functions/////

function slash_expandall(){
if (typeof menu!="undefined"){
for(i=0; i<Math.max(titles.length, submenus.length); i++){
var nr = submenus.getElementsByTagName("a").length*bypixels;
submenus.style.display = "";
submenus.style.height = (parseInt(submenus.style.height)+nr)+"px";
var to = setTimeout("showmenu("+i+")", speed);
if(parseInt(submenus.style.height) > (parseInt(heights)-nr)) {
clearTimeout(to);
submenus.style.height = heights+"px";
arrows.src = "slashfiles/expanded.gif";
}
}
}
}

function slash_contractall(){
if (typeof menu!="undefined"){
for(i=0; i<Math.max(titles.length, submenus.length); i++){
titles.className="titlehidden";
arrows.src = "slashfiles/collapsed.gif";
submenus.style.display="none";
submenus.style.height = 0;
}
}
}


/////End DD added functions///////////////////////////////


function init(){
menu = getElementsByClassName("sdmenu", "div", document)[0];
titles = getElementsByClassName("title", "span", menu);
submenus = getElementsByClassName("submenu", "div", menu);
arrows = getElementsByClassName("arrow", "img", menu);
for(i=0; i<Math.max(titles.length, submenus.length); i++) {
titles.onclick = gomenu;
arrows.onclick = gomenu;
heights = submenus.offsetHeight;
submenus.style.height = submenus.offsetHeight+"px";
}
slash_contractall()
slash_expandall()
}


function gomenu(e) {
if (!e)
var e = window.event;
var ce = (e.target) ? e.target : e.srcElement;
var sm;
for(var i in titles) {
if(titles == ce || arrows == ce)
sm = i;
}
if(parseInt(submenus[sm].style.height) > parseInt(heights[sm])-2) {
hidemenu(sm);
} else if(parseInt(submenus[sm].style.height) < 2) {
titles[sm].className = "title";
showmenu(sm);
}
}

function hidemenu(sm) {
var nr = submenus[sm].getElementsByTagName("a").length*bypixels;
submenus[sm].style.height = (parseInt(submenus[sm].style.height)-nr)+"px";
var to = setTimeout("hidemenu("+sm+")", speed);
if(parseInt(submenus[sm].style.height) <= nr) {
clearTimeout(to);
submenus[sm].style.display = "none";
submenus[sm].style.height = "0px";
arrows[sm].src = "slashfiles/collapsed.gif";
titles[sm].className = "titlehidden";
}
}

function showmenu(sm) {
var nr = submenus[sm].getElementsByTagName("a").length*bypixels;
submenus[sm].style.display = "";
submenus[sm].style.height = (parseInt(submenus[sm].style.height)+nr)+"px";
var to = setTimeout("showmenu("+sm+")", speed);
if(parseInt(submenus[sm].style.height) > (parseInt(heights[sm])-nr)) {
clearTimeout(to);
submenus[sm].style.height = heights[sm]+"px";
arrows[sm].src = "slashfiles/expanded.gif";
}


}


function getElementsByClassName(strClassName, strTagName, oElm){
var arrElements = (strTagName == "*" && document.all)? document.all : oElm.getElementsByTagName(strTagName);
var arrReturnElements = new Array();
strClassName = strClassName.replace(/\-/g, "\\-");
var oRegExp = new RegExp("(^|\\s)" + strClassName + "(\\s|$)");
var oElement;
for(var i=0; i<arrElements.length; i++){
oElement = arrElements;
if(oRegExp.test(oElement.className)){
arrReturnElements.push(oElement);
}
}
return (arrReturnElements)
}



window.onload = init;

 
Thanks for this. It almost works , but this is how it seems to behave : It is first full, then contracts and then expands full again. i am sure this is not how you meant it to behave.

 
you can remove the first and the second line of my previous post. I hope it will help you!


 
You said: "It is first full, then contracts and then expands full again."

You're right. I added that line because this sample is written in the expanded mode. So we have to contract it first (this is so fast i can't see that!!!) and then expand it with the speed variable.

this is all i can do for you...

 
I've commented some of your statements, and added some of my codes which should work (at least it works on my side). My changes and additions are in blue and followed by my comments (// HappyTiger -). Note: The sliding is too slow to be acceptable when I have a lot of contents on the right side of the page (I have the menu on the left side) even if I changed the time interval from 30 to 5 for the setTimeout function, I finally commented out the setTimeout recursive function and got very good effect. If you have no such problem you can leave your “hidemenu(ms)” and “showmenu(sm)” functions as they are. The rest of your codes should remain the same.

//var remember = true; //Remember menu states, and restore them on next visit.
var remember = false; // HappyTiger – I don’t want it to remember the last selections
var contractall_default= false; //Should all submenus be contracted by default? (true or false)

function init(){
menu = getElementsByClassName("sdmenu", "div", document)[0];
titles = getElementsByClassName("title", "span", menu);
submenus = getElementsByClassName("submenu", "div", menu);
arrows = getElementsByClassName("arrow", "img", menu);
for(i=0; i<Math.max(titles.length, submenus.length); i++) {
titles.onclick = gomenu;
arrows.onclick = gomenu;
heights = submenus.offsetHeight;
submenus.style.height = submenus.offsetHeight+"px";
}
/*if(remember)
restore()
else if (contractall_default) //DD added code
slash_contractall() //DD added code */

// HappyTiger – the last else will expand all bars by default
// HappyTiger – or you can simply write one line below instead of testing for all conditions, that is: slash_expandall ();

if (contractall_default)
slash_contractall ();
else
{
if (remember)
restore();
else
slash_expandall ();
}

}

function hidemenu(sm) {
//var nr = submenus[sm].getElementsByTagName("a").length*bypixels;
//submenus[sm].style.height = (parseInt(submenus[sm].style.height)-nr)+"px";
//var to = setTimeout("hidemenu("+sm+")", 30);
//if(parseInt(submenus[sm].style.height) <= nr) {
//clearTimeout(to);
submenus[sm].style.display = "none";
submenus[sm].style.height = "0px";
arrows[sm].src = "slashfiles/collapsed.gif";
titles[sm].className = "titlehidden";
// }
}

function showmenu(sm) {
//var nr = submenus[sm].getElementsByTagName("a").length*bypixels;
submenus[sm].style.display = "";
//submenus[sm].style.height = (parseInt(submenus[sm].style.height)+nr)+"px";
//var to = setTimeout("showmenu("+sm+")", 30);
//if(parseInt(submenus[sm].style.height) > (parseInt(heights[sm])-nr)) {
//clearTimeout(to);
submenus[sm].style.height = heights[sm]+"px";
arrows[sm].src = "slashfiles/expanded.gif";
//}
 
I’ve modified the code to make the menu bar behave differently. Only the top bar is expanded by default and only one menu is expanded each time. You can not close a menu by clicking on its title when it’s already expanded. However you don’t need to close a menu, you simply click on a different menu title, the one which is currently closed and which you want to open, the previously expanded menu should contract and the menu you just clicked should expand now.

I've commented out and modified some of your statements, and added some of my codes which should work (at least it works on my side). My changes and additions are in blue and followed by my comments in red(// HappyTiger -). Note: The sliding is too slow to be acceptable when I have a lot of contents on the right side of the page (I have the menu on the left side) even if I changed the time interval from 30 to 5 for the setTimeout function, I finally commented out the setTimeout recursive function and got very good effect. If you have no such problem you can leave your “hidemenu(ms)” and “showmenu(sm)” functions as they are. The rest of your codes should remain the same.


// var remember = true; //Remember menu states, and restore them on next visit.
var remember = false; // HappyTiger – I don’t want it to remember the last selections
var expandfirst_default= true; // HappyTiger – I created this variable to allow only the top bar expanded by default

var menu, titles, submenus, arrows, bypixels;
var heights = new Array();
var expands = new Array(); // HappyTiger – I created this array to hold the status of each bar (expand or contract)

// HappyTiger – I created this function to contract all bars except the top one

function contractexceptfirst(){
if (typeof menu!="undefined"){
for(i=1; i<Math.max(titles.length, submenus.length); i++){
// HappyTiger – the variable should start from 1 instead of 0 to start contract from the second bar
titles.className="titlehidden";
arrows.src = "images/collapsed.gif";
submenus.style.display="none";
submenus.style.height = 0;
}
}
}


function init(){
menu = getElementsByClassName("sdmenu", "div", document)[0];
titles = getElementsByClassName("title", "span", menu);
submenus = getElementsByClassName("submenu", "div", menu);
arrows = getElementsByClassName("arrow", "img", menu);
for(i=0; i<Math.max(titles.length, submenus.length); i++) {
titles.onclick = gomenu;
arrows.onclick = gomenu;
heights = submenus.offsetHeight;
submenus.style.height = submenus.offsetHeight+"px";
}

// HappyTiger – I added the four lines below to set the default status of the top bar to be expand (true) and the rest of the bars to be contract (false)
expands[0] = true;
for(i=1; i<Math.max(titles.length, submenus.length); i++) {
expands = false;
}


/* if(remember)
restore()
else if (contractall_default) //DD added code
slash_contractall() //DD added code*/

// HappyTiger – I first test whether the variable “expandfirst_default” is true, if yes, then call the “contractexceptfirst()” function that I have created to expand the top bar and contract the rest
if(expandfirst_default)
contractexceptfirst();
else {
if (contractall_default)
contractall();
else if (remember)
restore();
}

}

function gomenu(e) {
if (!e)
var e = window.event;
var ce = (e.target) ? e.target : e.srcElement;
var sm;
for(var i in titles) {
if(titles == ce || arrows == ce)
sm = i;
}
/* if(parseInt(submenus[sm].style.height) > parseInt(heights[sm])-2) {
hidemenu(sm);
} else if(parseInt(submenus[sm].style.height) < 2) {
titles[sm].className = "title";
showmenu(sm);
}*/

// HappyTiger – I added this loop to test which menu is currently expanded and to hide it
for(var i in expands) {
if(expands && i != sm)
hidemenu(i);
}

titles[sm].className = "title";
showmenu(sm);
}

function hidemenu(sm) {
/* var nr = submenus[sm].getElementsByTagName("a").length*bypixels;
submenus[sm].style.height = (parseInt(submenus[sm].style.height)-nr)+"px";
var to = setTimeout("hidemenu("+sm+")", 30);
if(parseInt(submenus[sm].style.height) <= nr) {
clearTimeout(to); */
submenus[sm].style.display = "none";
submenus[sm].style.height = "0px";
arrows[sm].src = "slashfiles/collapsed.gif";
titles[sm].className = "titlehidden";
expands[sm] = false; // HappyTiger – after hiding the menu, I added this code to change the status of the menu to be contract instead of expand
// }
}

function showmenu(sm) {
// var nr = submenus[sm].getElementsByTagName("a").length*bypixels;
submenus[sm].style.display = "";
/* submenus[sm].style.height = (parseInt(submenus[sm].style.height)+nr)+"px";
var to = setTimeout("showmenu("+sm+")", 30);
if(parseInt(submenus[sm].style.height) > (parseInt(heights[sm])-nr)) {
clearTimeout(to); */
submenus[sm].style.height = heights[sm]+"px";
arrows[sm].src = "slashfiles/expanded.gif";
expands[sm] = true; // HappyTiger - after showing the menu, I added this code to change the status of the menu to be expand instead of contract
// }
}


 
Very nice modifications HappyTiger.

I would like to change this menu in some ways:

1: If a menu-item has not sub-items (Like 'Home' or 'Login') the user can click on it an has a link, like home.htm or login.htm

2. Sub-items do have a hover affect. It would be nice that also the menu-items had this nice affect.

I tried to modify the .css file but no luck. Maybe somebody can help me with this???

 
Thanks HappyTiger. It almost works; but the submenus still seem to "appear suddenly" instead of gently sliding open. It may be due to speed of transition. Can you ammend the transition speed. Thanks again.

 
I would like to change this menu in some ways:

1: If a menu-item has not sub-items (Like 'Home' or 'Login') the user can click on it an has a link, like home.htm or login.htm

2. Sub-items do have a hover affect. It would be nice that also the menu-items had this nice affect.

I tried to modify the .css file but no luck. Maybe somebody can help me with this???
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top