Avatar of shepherdIT
shepherdIT
Flag for United States of America asked on

Help modifying expanding menu using javascript

Hi, This web page has an expanding/collapsing menu on the left side and the menu items have links that use onClick to call a javascript function to switch out the image on the right side of the page in the mainContent div.  The sublinks and expanding/collapsing work fine, but I want the top menu items such as 'Introduction' and 'Assistive Technology' to also change the mainContent image when clicked on.    When I try to add a similar link on these top level menu items, then the sub-menu items won't expand.  

--------------------------- Javascript --------------------

function changeImg(img,w,h) 
{
var ipath = "url(" + img + ")" ;
var hstring = h + 'px';
var wstring = w + 'px';

document.getElementById("mainContent").style.backgroundImage = ipath;
document.getElementById("mainContent").style.width = wstring;
document.getElementById("mainContent").style.height = hstring;
}


// JavaScript Document
/* This script and many more are available free online at
The JavaScript Source :: http://javascript.internet.com
Created by: Travis Beckham :: http://www.squidfingers.com | http://www.podlob.com
version date: 06/02/03 :: If want to use this code, feel free to do so,
but please leave this message intact. (Travis Beckham) */

// Node Functions

if(!window.Node){
  var Node = {ELEMENT_NODE : 1, TEXT_NODE : 3};
}

function checkNode(node, filter){
  return (filter == null || node.nodeType == Node[filter] || node.nodeName.toUpperCase() == filter.toUpperCase());
}

function getChildren(node, filter){
  var result = new Array();
  var children = node.childNodes;
  for(var i = 0; i < children.length; i++){
    if(checkNode(children[i], filter)) result[result.length] = children[i];
  }
  return result;
}

function getChildrenByElement(node){
  return getChildren(node, "ELEMENT_NODE");
}

function getFirstChild(node, filter){
  var child;
  var children = node.childNodes;
  for(var i = 0; i < children.length; i++){
    child = children[i];
    if(checkNode(child, filter)) return child;
  }
  return null;
}

function getFirstChildByText(node){
  return getFirstChild(node, "TEXT_NODE");
}

function getNextSibling(node, filter){
  for(var sibling = node.nextSibling; sibling != null; sibling = sibling.nextSibling){
    if(checkNode(sibling, filter)) return sibling;
  }
  return null;
}
function getNextSiblingByElement(node){
        return getNextSibling(node, "ELEMENT_NODE");
}

// Menu Functions & Properties

var activeMenu = null;

function showMenu() {
  if(activeMenu){
    activeMenu.className = "";
    getNextSiblingByElement(activeMenu).style.display = "none";
  }
  if(this == activeMenu){
    activeMenu = null;
  } else {
    this.className = "active";
    getNextSiblingByElement(this).style.display = "block";
    activeMenu = this;
  }
  return false;
}

function initMenu(){
  var menus, menu, text, a, i;
  menus = getChildrenByElement(document.getElementById("menu"));
  for(i = 0; i < menus.length; i++){
    menu = menus[i];
    text = getFirstChildByText(menu);
    a = document.createElement("a");
    menu.replaceChild(a, text);
    a.appendChild(text);
    a.href = "#";
    a.onclick = showMenu;
    a.onfocus = function(){this.blur()};
  }
}

if(document.createElement) window.onload = initMenu;



-------- end of Javascript -----

---------Beginning of CSS ------

@charset "utf-8";
body  {
	font:Arial, Helvetica, sans-serif;
	font-size: 18px;
	background: #CCC;
	margin: 0; 
	padding: 0;
	text-align: center; /* this centers the container in IE 5* browsers. The text is then set to the left aligned default in 

the #container selector */
	color: #000000;
}
.twoColFixLt #container { 	
	width: 1100px;
	background: #FFFFFF;
	margin: 0 auto; /* the auto margins (in conjunction with a width) center the page */
	text-align: left; /* this overrides the text-align: center on the body element. */
}
.twoColFixLt #sidebar1 {
	float: left; /* since this element is floated, a width must be given */
	width: 300px;	
	padding: 15px 10px 15px 20px;
	background: #39C;
}
.twoColFixLt #mainContent { 	
	margin: 0 0 0 350px;
	padding: 0 20px 20px; 
	padding-bottom: 10px;
	position:relative;	
	background-repeat:no-repeat;
	background-position: left top;
	background-image:url(../DME/images/homepage.jpg);
	width: 684px;
	height: 684px;
} 
.fltrt { /* this class can be used to float an element right in your page. The floated element must precede the element it should 

be next to on the page. */
	float: right;
	margin-left: 8px;
}
.fltlft { /* this class can be used to float an element left in your page */
	float: left;
	margin-right: 8px;
}
.clearfloat { /* this class should be placed on a div or break element and should be the final element before the close of a 

container that should fully contain a float */
    clear:both;
    height:0;
    font-size: 1px;
    line-height: 0px;
}
ul#menu {
  width: 250px;
  list-style-type: none;
  border:none;
  margin: 0;
  padding: 0;
}

ul#menu ol {
  display: none;
  text-align: left;
  list-style-type: none;
  margin: 0;
  padding-left: 12px;
  padding-top: 3px;
  padding-bottom: 3px;
  padding-right: 0px;
}

ul#menu li, 
  ul#menu a {
  font-family: Arial, Helvetica, sans-serif;
  font-size: 20px;
  font-weight:bold;
  color:#000;
}

ul#menu li {
  line-height: 30px;
}

ul#menu ol li {
  border-bottom: none;
}

ul#menu ol li:before {
  content: ">";
}

ul#menu a {
  text-decoration: none;
  outline: none;
}

ul#menu a:hover {
  color: #FFF;
}

ul#menu a.active {
  color:#FFF;
}


------------ end of CSS ------------------------

------------ beginning of HTML -------------------

                         
<body class="twoColFixLt">

<div id="container">

  <div id="header">
	<h1 align="center">DME Guide</h1>
  </div>
  <div id="sidebar1">
    
<ul id="menu">
  <li> Introduction
    <ol>            
      <li> <a href="#" onclick="changeImg('images/introtext.jpg','684','684')">Overview</a>  </li>            	   
      <li> <a href="#" onclick="changeImg('images/committee.jpg','684','792')">Rehab Standards Committee</a></li>

    </ol>
  </li>
  <li>Assistive Technology
    <ol>
      <li> <a href="#">C1-3</a></li>
      <li> <a href="#">C4</a></li>
      <li> <a href="#">C5</a></li>
      <li> <a href="#">C6-T1</a></li>
    </ol>
  </li>
  <li>Bathing and Toileting
    <ol>
      <li> <a href="#">C1-4</a></li>
      <li> <a href="#">C5-6</a></li>
      <li> <a href="#">C7-T1</a></li>
      <li> <a href="#">T2-T12</a></li>
      <li> <a href="#">L1-S5</a></li>
    </ol>
  </li>

</ul>    
    
  <!-- end #sidebar1 --> </div>
  
  <div id="mainContent">
  </div>
	
  <br class="clearfloat" />

<!-- end #container --></div>

</body>
</html>

Open in new window

JavaScriptCSS

Avatar of undefined
Last Comment
shepherdIT

8/22/2022 - Mon
Tom Beck

What if you change line 98 from a.onclick = showmenu; to

a.onmouseover = showmenu;
a.onmouseout = showmenu;

Then, menus would expand on hover (the more common behavior) instead of on click thus freeing up the onclick event for the image change.
shepherdIT

ASKER
I did what you said, and when I hover over 'Introduction', it expands the sub-items under 'Introduction' but when I try to move my pointer to the sub-items, they disappear so I can't even hover over them.  I'd prefer not to have the hover and just click links since it is a user guide.

I just would really like to have the onClick on the top level <li> tags  like the following:

  <ul id="menu">
  <li> <a href="#" onclick="changeImg ('images/homepage.jpg','684','684')">Introduction</a>
    <ol>            
      <li> <a href="#" onclick="changeImg('images/introtext.jpg','684','684')">Overview</a>  </li>                     
      <li> <a href="#" onclick="changeImg('images/committee.jpg','684','792')">Rehab Standards Committee</a></li>

    </ol>
  </li>

....but when I add the onclick on 'Introduction', the onclick works but the menu sub-items for 'Introduction' do not show anymore.
ASKER CERTIFIED SOLUTION
Tom Beck

THIS SOLUTION ONLY AVAILABLE TO MEMBERS.
View this solution by signing up for a free trial.
Members can start a 7-Day free trial and enjoy unlimited access to the platform.
See Pricing Options
Start Free Trial
GET A PERSONALIZED SOLUTION
Ask your own question & get feedback from real experts
Find out why thousands trust the EE community with their toughest problems.
shepherdIT

ASKER
When I tried the last solution, I lost the pointer altogether and couldn't click on anything in the menu.

 FYI, I've changed my original code to use an inline image instead of the background image because I realized the background image wouldn't print.  So the menu looks like this:

<ul id="menu">
  <li> Introduction
    <ol>  
      <li> <a href="#" Overview</a>  </li>
      <li> <a href="#" onclick="document.getElementById('mainimage').src='images/committee.jpg'">Rehab Standards Committee</a> </li>
    </ol>onclick="document.getElementById('mainimage').src='images/introtext.jpg'">
  </li>
....</ul>

and the mainContent div looks like this:

  <div id="mainContent">
     <img src="images/homepage.jpg" name="mainimage" id="mainimage" border="0" align="left" />
  </div>

Again, I need to somehow call
      onclick="document.getElementById('mainimage').src='images/homepage.jpg'" when 'Introduction' is clicked on, before the menu sub-items expand.

Thanks for any input.
All of life is about relationships, and EE has made a viirtual community a real community. It lifts everyone's boat
William Peck
Tom Beck

I incorporated your new idea of using inline images instead of background images. It required changing a few lines in the showMenu script that I posted earlier.
function showMenu() {
  if(activeMenu){
    activeMenu.className = "";
    getNextSiblingByElement(activeMenu).style.display = "none";
  }
  if(this == activeMenu){
    activeMenu = null;
  } else {
    this.className = "active";
    getNextSiblingByElement(this).style.display = "block";
    activeMenu = this;
  }
  var liId = activeMenu.id;
  var img;
 switch(liId){
    case "Intr":
       img = "images/homepage.jpg";
       break;
    case "Assi":
       img = "images/whatever.jpg";
       break;
    case "Bath":
       img = "images/whatever.jpg";
       break;
    default:
       img = "images/default.jpg";
  }
  document.getElementById('mainimage').src= img;
  return false;
}

Open in new window

It works perfectly (as did the original script). If it is not working for you, let's investigate that. If you are losing the pointer and are unable to click, you likely have a syntax error in your javascript. It's the javascript that creates the links for the top level items. If they are not successfully converted to links, then there is an error.

I'm confused when you say you want to call onclick "when 'Introduction' is clicked on, before the menu sub-items expand." Don't you want the image to change AND the menu expand with the same click? That's what my suggested script does.
shepherdIT

ASKER
I was able to get the behavior working the way I want by hardcoding a change to 'src' in the showMenu function (in 2 places), but I'm not sure how to determine which <li> is active so I can change the image accordingly.  I tried taking the first 4 letters of the link's text value like in your previous example but I couldn't get it to work.  I thought maybe I can check it by looking at id, so I've added id's on the top level <li> items.  Embedded is the most recent version.


--------------------------- Javascript --------------------

function changeImg(img,w,h) 
{
var ipath = "url(" + img + ")" ;
var hstring = h + 'px';
var wstring = w + 'px';

document.getElementById("mainContent").style.backgroundImage = ipath;
document.getElementById("mainContent").style.width = wstring;
document.getElementById("mainContent").style.height = hstring;
}


// JavaScript Document
/* This script and many more are available free online at
The JavaScript Source :: http://javascript.internet.com
Created by: Travis Beckham :: http://www.squidfingers.com | http://www.podlob.com
version date: 06/02/03 :: If want to use this code, feel free to do so,
but please leave this message intact. (Travis Beckham) */

// Node Functions

if(!window.Node){
  var Node = {ELEMENT_NODE : 1, TEXT_NODE : 3};
}

function checkNode(node, filter){
  return (filter == null || node.nodeType == Node[filter] || node.nodeName.toUpperCase() == filter.toUpperCase());
}

function getChildren(node, filter){
  var result = new Array();
  var children = node.childNodes;
  for(var i = 0; i < children.length; i++){
    if(checkNode(children[i], filter)) result[result.length] = children[i];
  }
  return result;
}

function getChildrenByElement(node){
  return getChildren(node, "ELEMENT_NODE");
}

function getFirstChild(node, filter){
  var child;
  var children = node.childNodes;
  for(var i = 0; i < children.length; i++){
    child = children[i];
    if(checkNode(child, filter)) return child;
  }
  return null;
}

function getFirstChildByText(node){
  return getFirstChild(node, "TEXT_NODE");
}

function getNextSibling(node, filter){
  for(var sibling = node.nextSibling; sibling != null; sibling = sibling.nextSibling){
    if(checkNode(sibling, filter)) return sibling;
  }
  return null;
}
function getNextSiblingByElement(node){
        return getNextSibling(node, "ELEMENT_NODE");
}

// Menu Functions & Properties

var activeMenu = null;

function showMenu() {
  if(activeMenu){
    document.getElementById('mainimage').src='images/homepage.jpg' ;
    activeMenu.className = "";
    getNextSiblingByElement(activeMenu).style.display = "none";
  }
  if(this == activeMenu){
    activeMenu = null;
  } else {
    document.getElementById('mainimage').src='images/homepage.jpg';
    this.className = "active";
    getNextSiblingByElement(this).style.display = "block";
    activeMenu = this;
  }
  return false;
}

function initMenu(){
  var menus, menu, text, a, i;
  menus = getChildrenByElement(document.getElementById("menu"));
  for(i = 0; i < menus.length; i++){
    menu = menus[i];
    text = getFirstChildByText(menu);
    a = document.createElement("a");
    menu.replaceChild(a, text);
    a.appendChild(text);
    a.href = "#";
    a.onclick = showMenu;
    a.onfocus = function(){this.blur()};
  }
}

if(document.createElement) window.onload = initMenu;



-------- end of Javascript -----

---------Beginning of CSS ------

@charset "utf-8";
body  {
	font:Arial, Helvetica, sans-serif;
	font-size: 18px;
	background: #CCC;
	margin: 0; 
	padding: 0;
	text-align: center; /* this centers the container in IE 5* browsers. The text is then set to the left aligned default in 

the #container selector */
	color: #000000;
}
.twoColFixLt #container { 	
	width: 1100px;
	background: #FFFFFF;
	margin: 0 auto; /* the auto margins (in conjunction with a width) center the page */
	text-align: left; /* this overrides the text-align: center on the body element. */
}
.twoColFixLt #sidebar1 {
	float: left; /* since this element is floated, a width must be given */
	width: 300px;	
	padding: 15px 10px 15px 20px;
	background: #39C;
}
.twoColFixLt #mainContent { 	
	margin: 0 0 0 350px;
	padding: 0 20px 20px; 
	padding-bottom: 10px;
	position:relative;	

} 
.fltrt { /* this class can be used to float an element right in your page. The floated element must precede the element it should 

be next to on the page. */
	float: right;
	margin-left: 8px;
}
.fltlft { /* this class can be used to float an element left in your page */
	float: left;
	margin-right: 8px;
}
.clearfloat { /* this class should be placed on a div or break element and should be the final element before the close of a 

container that should fully contain a float */
    clear:both;
    height:0;
    font-size: 1px;
    line-height: 0px;
}
ul#menu {
  width: 300px;
  list-style-type: none;
  border:none;
  margin: 0;
  padding: 0;
}

ul#menu ol {
  display: none;
  text-align: left;
  list-style-type: none;
  margin: 0;
  padding-left: 12px;
  padding-top: 3px;
  padding-bottom: 3px;
  padding-right: 0px;
}

ul#menu li, 
  ul#menu a {
  font-family: Arial, Helvetica, sans-serif;
  font-size: 20px;
  font-weight:bold;
  color:#000;
}

ul#menu li {
  line-height: 30px;
}

ul#menu ol li {
  border-bottom: none;
}

ul#menu ol li:before {
  content: ">";
}

ul#menu a {
  text-decoration: none;
  outline: none;
}

ul#menu a:hover {
  color: #FFF;
}

ul#menu a.active {
  color:#FFF;
}

div#preload { display: none; }


------------ end of CSS ------------------------

------------ beginning of HTML -------------------

                         
<body class="twoColFixLt">

<div id="container">

  <div id="header">
	<h1 align="center">DME Guide</h1>
  </div>
  <div id="sidebar1">
    
<ul id="menu">
  <li id="li_intro"> Introduction
    <ol>            
      <li> <a href="#" onclick="document.getElementById('mainimage').src='images/introtext.jpg'">Overview</a>  </li>
      <li> <a href="#" onclick="document.getElementById('mainimage').src='images/committee.jpg'">Rehab Standards Committee</a></li>
    </ol>
  </li>
  <li id="li_assist">Assistive Technology
    <ol>
      <li> <a href="#">C1-3</a></li>
      <li> <a href="#">C4</a></li>
      <li> <a href="#">C5</a></li>
      <li> <a href="#">C6-T1</a></li>
    </ol>
  </li>
  <li id="li_bath">Bathing and Toileting
    <ol>
      <li> <a href="#">C1-4</a></li>
      <li> <a href="#">C5-6</a></li>
      <li> <a href="#">C7-T1</a></li>
      <li> <a href="#">T2-T12</a></li>
      <li> <a href="#">L1-S5</a></li>
    </ol>
  </li>

</ul>    
    
  <!-- end #sidebar1 --> </div>
  
  <div id="mainContent">

     <img src="images/homepage.jpg" name="mainimage" id="mainimage" border="0" align="left" />

  </div>
	
  <br class="clearfloat" />

<!-- end #container --></div>

<div id="preload">
   <img src="images/homepage.jpg" />
   <img src="images/introtext.jpg" />
   <img src="images/committee.jpg" />	
</div>

</body>
</html>

Open in new window

shepherdIT

ASKER
Sorry, I didn't see your last post before I posted.  I will take a look at it.
⚡ FREE TRIAL OFFER
Try out a week of full access for free.
Find out why thousands trust the EE community with their toughest problems.
Tom Beck

Putting ids in the top level <li>s is not going to help. You need ids in the anchor tags that are being created inside the top level <li>s by the init function. I have done this for you in ID: 37717318 on line 10 of the init function. The id of the anchor tag is set to the first four characters of the text in the <li>. Now you only need the showMenu function from ID: 37726725 to get the id of the active menu item's anchor tag to change the image according to the id.
shepherdIT

ASKER
Okay I didn't see before that I was getting a javascript error '..textContent is null or not an object' and I am using IE 8 and I see from looking around that some versions of IE have a problem with textContent.  And when I tested it in Firefox, it worked!  So I need to find out what is an alternative to textContent I could use that would work in all browsers.  
  Also the image change was not occurring when I clicked the top-level menu item when the sub-menu items were already expanded.  The sub-menu items would collapse like normal but the image that was already there would stay.  To fix this, I just copied that same case statement code before the lines that collapse the menu.

function showMenu() {
  var liId;
  var img;
  
  if(activeMenu){
      liId = activeMenu.id;
      switch(liId) {
     	 case "Intr":
           img = "images/homepage.jpg";
           break;
         case "Assi":
           img = "images/homepage.jpg";
           break;
         case "Bath":
           img = "images/whatever.jpg";
           break;
         default:
           img = "images/homepage.jpg";
       }
     document.getElementById('mainimage').src= img;
	
     activeMenu.className = "";
     getNextSiblingByElement(activeMenu).style.display = "none";
  }
  if(this == activeMenu){
    activeMenu = null;
  } else {
         this.className = "active";
         getNextSiblingByElement(this).style.display = "block";
         activeMenu = this;
         }
  
  liId = activeMenu.id;
  switch(liId) {
   	 case "Intr":
       img = "images/homepage.jpg";
       break;
     case "Assi":
       img = "images/homepage.jpg";
       break;
     case "Bath":
       img = "images/whatever.jpg";
       break;
     default:
       img = "images/homepage.jpg";
     }
     document.getElementById('mainimage').src= img;
	
  return false;
}

Open in new window

SOLUTION
Tom Beck

THIS SOLUTION ONLY AVAILABLE TO MEMBERS.
View this solution by signing up for a free trial.
Members can start a 7-Day free trial and enjoy unlimited access to the platform.
See Pricing Options
Start Free Trial
⚡ FREE TRIAL OFFER
Try out a week of full access for free.
Find out why thousands trust the EE community with their toughest problems.
shepherdIT

ASKER
Thank you SO much!  That did the trick!
Your help has saved me hundreds of hours of internet surfing.
fblack61