maretzke.com
English version of maretzke.de Deutsche Version von maretzke.com
Navigation in JavaScript™

Valid HTML 4.01!

Clientside, page-spanning (!) navigation with JavaScript™

Sourcecode -  01.01.2005

The navigation menu of this homepage saw the one or the other reincarnation ... First, static HTML, simulated menues as static HTML in frames next and some other weird ideas. At some stage I found JavaScript™ quite interesting and decided to do some tests ... The result is the current navigation of the homepage.

The search for a pretty, meaningful and simple navigation method for the homepage started with pure static HTML. After a while, I landed at a dynamic technology - JavaScript™. Looking around in the net, I found some quite different approaches to model menues in JavaScript™. Some of them are commercial, some of them are freeware, some of them are powerful and unbelievable complex, others are simply too stupid to really work with them. After some studies, I realized that I will never ever understand all the coding needed for one of these complex menues - I am not a JavaScript™ expert and - Heaven forbid! - will never ever be one. However, the ambition ... and the curiosity.

Especially, the issue of page-spanning navigation without interacting with a server instance was a bit ... tricky. However, some of the real experts solved the problem and did me the favor to document the solution in the web :) So, it's more an act of cherry-picking ...

What's the problem? Uhm, perhaps worth mentioning :) JavaScript™'s object model's root is the object "window", which contains the displayed "document". Unfortunately, "window" does not offer any possibilities to store information, which then could be accessed from other "document" objects - other pages. So, every "document" or displayed HTML page is disconnected from each other. To enable a consistent navigation menu the information about which menu is folded and unfolded needs to be transported between pages. A page-spanning data store is needed ...

In principle there are two possibilites:

  • Memorize the information in a superordinate frame
  • Memorize the information in "window.name"

Memorize the information in a superordinate frame

The basic principle is relatively easy: Define a frameset whereas one of the frames does solely stores information and contains no content and the other one presents all the content. How's this done?

The starting page "navigation-js_index.html" looks like this:

      <?xml version="1.0"?>
      <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN"
           "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">
      <html xmlns="http://www.w3.org/1999/xhtml">   
        <head>
          <title>Text of the very universal title</title>
        </head>
        <frameset cols="0,*">
          <frame src="navigation-js_variables.html" name="variable" />
          <frame src="navigation-js_page1.html" name="content" />
          <noframes>
            Your browser can't display the content!
          </noframes>
        </frameset>
      </html>
      

The page containing the variables "navigation-js_variables.html" looks like:

      <?xml version="1.0"?>
      <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
          "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
      <html xmlns="http://www.w3.org/1999/xhtml">
        <head>
          <title>Maretzke.com - Navigationexample with JavaScript and Frames</title>
          <script src="navigation-js_v1.0.js" type="text/javascript"></script>
        </head>
        <body>
        </body>
      </html>
      

Hmmmh. Looks like there happens absolutely nothing. Right! This page does merely contain the variable to store information. Where? The page includes the JavaScript™ code that contains the variable.

The navigation script "navigation-js_v1.0.js" looks like this:

      var submenu = new Array("none", "none");
      
      function toggle(id) {
        if (document.getElementById) {
        	if (parent.variable.submenu[id] == "none")  {
        		parent.variable.submenu[id] = "block";
        		document.getElementById(id).style.display = "block";
        	}
        	else {
        		parent.variable.submenu[id] = "none";
        		document.getElementById(id).style.display = "none";
      		}      		
        }
      }
      
      function initNavigation() {
      	document.getElementById("1").style.display = parent.variable.submenu[1];
      	document.getElementById("2").style.display = parent.variable.submenu[2];
      }
      

What happens? The very first line defines an array containing the CSS attributes for the individual menu areas. The variable "submenu" contains values representing the visibility of menu items. This variable is defined in the frame "variable".

The function "initNavigation()" defines the state of the menu items. During the very first load process all the predefined states (here: "none" for not visible) are assigned. The menu items are folded away. During a click on a menu item the function "toggle(id)" is invoked. The menu items define a unique ID in the HTML code. The IDs are consecutive numbers - starting with "1". The function "toggle(id)" swaps the visibility from visible to invisible and vice versa. The script above is only capable of handling two menu items. If you need more the array "submenu" must be extended (simply add some "none" strings in the definition) and "initNavigation()" needs to be extended with according lines. Ready!
Ah, a page like e.g. "navigation-js_page1.html" looks like this:

      <?xml version="1.0"?>
      <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
          "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
      <html xmlns="http://www.w3.org/1999/xhtml">
        <head>
          <title>maretzke.com - Navigation with JavaScript and Frames - Page 1</title>
          <script src="navigation-js_v1.0.js" type="text/javascript"></script>
      </head>
      
      <body onload="initNavigation()" bgcolor="#FFFFFF" text="#000000">
      
          <table width="300" border="1">
          	<tr style="display:block">
          		<td style="cursor:pointer;" align="left" width="300" 
          		  onmouseover="this.bgColor='#3E4C69'" 
          		  onmouseout="this.bgColor=''" 
          		  onclick="javascript:toggle('1')">
          		  Main Menu One (Klick me!)
          		</td>
          	</tr>
          </table>
          
          <table id="1" width="300" border="1">	
          	<tr>
          		<td align="left" width="300">
          		    <a href="navigation-js_page1.html">Go to page 1</a>
          		</td>
          	</tr>
          	<tr>
          		<td align="left" width="300">
          		    <a href="navigation-js_page2.html">Go to page 2</a>
          		</td>
          	</tr>
          </table>	
          
          <table width="300" border="1">
          	<tr style="display:block">
          		<td style="cursor:pointer;" align="left" width="300" 
          		  onmouseover="this.bgColor='#3E4C69'" 
          		  onmouseout="this.bgColor=''" 
          		  onclick="javascript:toggle('2')">
          		  Main Menu Two (Klick me!)
          		</td>
          	</tr>
          </table>
          
          <table id="2" width="300" border="1">	
          	<tr>
          		<td align="left" width="300">  Sub Menu 1</td>
          	</tr>
          	<tr>
          		<td align="left" width="300">  Sub Menu 2</td>
          	</tr>
          	<tr>
          		<td align="left" width="300">  Sub Menu 3</td>
          	</tr>
          	<tr>
          		<td align="left" width="300">  Sub Menu 4</td>
          	</tr>
          </table>
      
          <h1>This is the first page of the navigation example!</h1>
      
        </body>
      </html>
      

The complete example is stored in the archive. The archive is free for download from this website.

Memorize the information in "window.name"

Yeah, the frames version for the navigation was already quite good. However, search engine spiders and robots don't look for information in framed pages ... Bad, bad, bad! Thus, a version without any frames should solve this issue.

The most tidy fact with the new solution is that only the JavaScript™ code changes - the HTML code remains exactly the same ...
The script looks like:

      function toggle(id) {
        if (document.getElementById) {
        	if (window.name.charAt(id) == '0')  {
        	  window.name = replace(window.name, 1, id);
        	  document.getElementById(id).style.display = "block";
        	}
        	else {
        		window.name = replace(window.name, 0, id);
        		document.getElementById(id).style.display = "none";
      		}      		
        }
      }
      
      function initNavigation() {
        if (window.name.length != 32) window.name = 
          "00000000000000000000000000000000";  
      	if (window.name.charAt(1) == '0')
      		document.getElementById("1").style.display = "none";
      	else document.getElementById("1").style.display = "block";
      	
      	if (window.name.charAt(2) == '0')
      		document.getElementById("2").style.display = "none";
      	else document.getElementById("2").style.display = "block";
      }
      

			function replace(s, c, i) {
			  return (s.slice(0, i) + c + s.slice(i+1, s.length));
			}
      

The basic functionality still solves the same problem. However, this solution does not need a "global" variable stored in a frame. Here, "window.name" is used to store the menu information. The state is memorized in a string. "0" represents the CSS state "none" and "1" equals "block". And ready is the solution!

Copy the sources from this page or download them ...

Downloads at maretzke.com 
Navigation with Frames
Michael Maretzke
2005, [ZIP, 3kb]
Navigation with Frames. Compressed Archive.
Navigation with "window.name"
Michael Maretzke
2005, [ZIP, 3kb]
Navigation with

Related info at maretzke.com 

Links into the Web