JavaScript Code for





By Vic Phillips     http://www.vicsjavascripts.org.uk/


Section 1 Introduction

This exercise will produce a simple JavaScript menu with three levels
with a choise of two display formats, Cascade or Compact.
The final Style and JavaScript code size is less than 8K.

A taster with a Compact display format

Topic 1
Topic 1 Sub 1
Topic 1 Sub 1 Ext 1
Topic 1 Sub 1 Ext 2
Topic 1 Sub 2
Topic 1 Sub 2 Ext 1
Topic 1 Sub 3
Topic 1 Sub 3 Ext 1
Topic 1 Sub 3 Ext 2
Topic 2
Topic 2 Sub 1
Topic 2 Sub 2
Topic 3
Topic 3 Sub 1
Topic 3 Sub 2
Topic 3 Sub 2 Ext 1
Topic 3 Sub 2 Ext 2

The menu would normally be used for navigation.
It would be beneficial if the menu would still meet this requirement if client browser has JavaScript switched off.

The menu must function in standard browsers and has been tested with IE6 and Mozilla FireFox

I will start from scratch and progressively modify the script
to accommodate rollover effects, links, images and two display formats.


Before we Start

I will explain some of the features of this presentation.

Segments of code are displayed in 'TextAreas'.
When the textarea has a vertical scroll bar the text area can be expanded by clicking the area.

In addition to the explanations on this page the code segments have in code help notes

Each section has a example accessed by a link.
The full code of these examples has not been displayed
Please use the browsers 'Edit' and 'View Source' to view and save the code as required

Currently this presentation is based on a single large document.
While not ideal for veiwing it makes updates easier for me to implement and control.

Index
Section 1 Introduction
Section 2 The Menu Mounting & Main Topic Entries
Section 3 The Menu Sub Topics
Section 4 Collapsing and Reveling the Menu
Section 5 MouseOver and MouseOut Events
Section 6 Adding Links to Topics
Section 7 Adding Images
Section 8 Taking Stock and Additional Menus & Levels
Section 9 Compact Format
Section 10 Managing the Script
MakeMenu.zip All Files in a zip



Section 2 The Menu Mounting & Main Topic Entries

The menu will need to be positioned on the host page.
For flexibility in positioning the menu elements will be placed in a <div>.



Any id name could be used but I have chosen 'MyMenu'
This name has been prefixed with 'mm' as will all variable, function etc names
in the script to minimise conflicts with other JavaScripts.


The menu will as all DHTML be a combination of JavaScript and CSS
The appearance will be initially defined by CSS and modified by JavaScript

The CSS for 'mmMyMenu' is



The 'mmMyMenu' div is given an attribute of 'class="mmMounting"'

This specifies the width but not the height as that will be dictated by the menu entries



Section 2 The Menu Main Topics

The appearance of the menu topics will be specified using the same technique.

The HTML Code for the menu with two Main Topic entries is now:



The style code is expanded to specify the appearance of the Main Topic Entries



The menu now looks like

Topic 1
Topic 2


The menu may need to be above other elements on the host page.

A JavaScript customising variable 'mmZIndex' will be used to specify the menu Z-Index.

We may also need to separate the topics,
so will allocate a variable 'mmMainSeparation' to define the distance.



You will note that the menu topic entries do not have id or name attributes.
The DOM will be used to identify the elements.
This will be carried out in a function 'mmInitialise()' called from an on load event in the body tag.




Function 'mmInitialise()' will first set the menu Z-Index to the value of 'mmZIndex'.
The position style of each topic is changed to 'absolute' ready to position each topic.
Style display is set to 'block' and overflow to 'hidden' so that exessive content will not effect the topic size.

The value of variable 'mmMainSeparation' is attached to each topic object property '.sep'
for use in function 'mmCascadePos()' which will position each topic. The function 'mmInitialise()' called from an on load event in the body tag.




The first topic is positioned down by the value of 'mmMainSeparation'
which is recorded in the '.sep' property.
The use of '.offsetTop' and '.offsetHeight' establishes dimensions and positions.

As the menu is developed some topics will be removed by the use of '.display='none'
so positioning of each topic is determined from the previous topic with 'display' set to 'block'.

Note that the container height has not been addressed as yet so with no height specified
and the topics with 'absolue' positioning will appear as a single line of the border color.





Section 3 The Menu Sub Topics

We can now add Sub Menu Topics

We can use the same techniques to specify and add the Menu Sub Topics
First the style definitions are expanded to include the definition of Menu Sub Topics
with a class name of 'mmSubTopic'

We need to ensure that Sub Topics will appear above Main Topics
so will add a Z-Index to both the 'mmMainTopic' and 'mmSubTopic' classes.

While we are changing the style we can consider the MouseOver cursor type

The IE 'pointer' cursor is called 'hand', for other browsers it is called 'pointer'
Adding both to the topic style class of will satisfy most browsers.




The HTML Code is expanded to include the Menu Sub Topics



The variables to refine the appearance are added to the JavaScript



The function mmInitialse() expand to apply these variables.
Conditionals on the topic class name attach the correct seperation value
to the topic '.sep' property.



There is no requirement to change function 'mmCascadePos()'
as the specific topic separation is recorded in the topic '.sep' property.




Section 4Collapsing and Reveling the Menu

Each Main Topic requires an 'onClick' event to collapse and revel the associated Sub Topics


The Sub Menus are collapsed by using 'style.display'
'display='none';' removes the object from the page and therefore cannot be seen of takes up space.
'display='block'; renders the object so it can be seen and takes up its natural space on the page.

Care must be taken with the use of 'style.display'
as the objects attributes cannot always be accessed when its 'display='none';'


The onclick events are added during initialization.
The onclick event calls function 'mmClick(this)'
The topic object (this) is passed to the function

New properties are also added to each topic object
to assist subsequent coding as we increase the menus functionality.
.prime - set property 'prime' to 'yes' to recognise original nodes when expanded
.nu - set to 1 for Main Topics, 2 for Sub Topics, to make easier conditional statements
.group - each Main and Sub Topic group will be given an incrementing number


The modified mmInitialisation() function.



The new functions, 'mmCascadePos()', 'mmStartDisplay()' and 'mmMenuHeight()'
are required to position the topics.

These functions call functions after a 'setTimeout' delay.
This delay is specified in a variable 'mmDelay' with a value of 50.


New function 'mmCascadePos()'



New function 'mmStartDisplay()'



New function 'mmMenuHeight()'



New function 'mmClick()'



The function 'mmClick()' calls a new function 'mmToggle(mm)' to toggle the topic enties.

New function 'mmToggle(mm)'



The functions 'mmToggle()' and 'mmMenuHeight()' use a new function 'mmNormalise()'

As the code progesses additional nodes will be added to the menu topics.
These are child nodes of the clicked topics parent.
Unfortunatly IE and Mozilla interpret the child nodes differently!
Mozilla includes all nested nodes, IE only records the first level nodes.

We therefore need to 'normalise' this inteprtation.
As we are only interested in the first level (original topic nodes)
we can us the .prime tag to extract these nodes in a new function 'mmNormalise(mm)'
which returns these nodes





Section 5 Text Align and MouseOver/MouseOut Events


Up to now text has been aligned 'center' and the top position is dependent on the font size

We will now position the text in its own <div> which can be independently positioned.

The text is copied into a text node and inserted in a <div>
This <div> shares a number of the charactoristics with the topic object.
The original text is then removed from the topic object and the new <div> inserted(appended).

Additional Javascript variables are requires to specify the text horizontal and vertical offsets
and a new function 'mmTopicFormat

The style classes 'mmMainTopic' and 'mmSubTopics' text-align is changed to 'left' to aid the demonstration.


The background and text colors of the Topics can be changed on MouseOver.
We could use style or JavaScript to do this but we will use JavaScript

Additional variables are required to define the mouseover colors

The MouseOver events and these colors are allocated to Topic objects
during execution of 'mmInitialise();'

The MouseOver event of the Topic Object will call function mmMouseOver(this)






The 'mmInitialise()' function now includes a call to 'mmTopicFormat()'.

This function makes a new <div> node, using the clone created in 'mmInitialise',
appends the topic text to the new node, and sizes the node to the topic dimensions.
The original topic text node is removed from the topic object and replaced by the new node.



The new function 'mmMouseOver(this)' will change the topic background and text colors.



The 'mmMouseOver()' function applies the parent node(topic object) color
to its first child, the <div> containing the text.
It also attaches a new onMouseOut event to restore the original colors on MouseOut




Section 6 Adding Links to Topics

The object of the menu is to navigate to links

Different types of links may be required.
This script will allow a standard link, target '_top'
for frameset application a named frame, target 'FrameName'
and to a JavaScript function.

We would like the menu to be usable if JavaScript is disabled
even if the appearance is rudimentary.
We will therefore use standard HTML in the menu by encasing the topic text in <a> tags.


The HTML code must be modified to include the links

The link target is used to establish the requirement

The target must be specified.

A target specified as '_top' or '_blank' will replace the current page with the specified URL.

A target specified as the target frame name replace the frame URL with the specified URL.
If the target frame name cannot be found the link will not be actioned.

A target specified as 'JavaScript' will action the function specified as URL.


The HTML for the menu becomes:



The function 'mmTopicFormat(mm)' is modified to attach the target value to the Topic object




The new function 'mmTopicFormat(mm)'



The 'mmTopicFormat(mm)' function detects the <A> tag,
attaches the link url to the topic object property .url,
attaches the target value to the topic object property .target,
creates a text node from the link child node 0 (the text),
and then creates a new div object and appends the text

It then removes the original link and text and appends the new
new div containing the text to the Topic object.


A new function 'mmLink(mm)' is introduced.



Another function 'mmJavaScriptCall()' is introduced in the Customising Variables section of the script
as 'mmJavaScriptCall()' is intended to contain custom requirements.



The 'mmClick(mm)' function is modified to call the new function 'mmLink(mm)'






Note
Links have been removed from Examples 7 and 8

Section 7 Adding Images

While we have a perfectly good menu for navigation
the appearance could be enhance with MouseOut and MouseOut Images

Images are good but it would be better if the text could be retained.
This can save a mass of image editing and provide clearer text.

The structure of 'mmMainAry' allows for this requirement.

The images are specified in the HTML Code.



The image width and height must be set to '0'.
Therefore images will not be displayed if JavaScript is switched off.
The first of each topic is used as the MouseOver image,
the second as the MouseOut image
If only one image is specified the background color will be displayed on MouseOut.
To retain the image on MouseOver, two identical images must be specified>

The function 'mmEntryFormat(mm)' currently sets the Z-Index of the text to 4.
The function is now modified create clones of the images.
with a Z-Index of 3 for the MouseOut image and 2 for the MouseOver image.
The original images are removed and the clones appended to the topic object.


The amended 'mmTopicFormat(mm)' Function.



The 'mmMouseOver(mm)' requires extending to remove the MouseOut image on MouseOver
and replace it on MouseOut


The extended 'mmMouseOver(mm)' Function





While we are addressing images we can address marking the topics which have a sub menu.

Topic sub menus are recorded in the object property array .sub.
The function 'mmTopicFormat(mm)' can be expanded to recognise if this array contains any sub menus
and if so append a marker image to the topic object.

A customising variable 'mmMarker' will be used to record the marker image file path and name.




and the function 'mmTopicFormat(mm)' expanded




The function mmMouseOver(mm) will also require modification
to distinguish between the MouseOut Image and Marker Image.






Section 8 Taking Stock and Additional More Menus & Levels
It is time to take stock of what has been achieved so far

  • We have a working and practical menu with two levels.
  • The appearance is specified by style classes.
  • Separation between topics is specified by JavaScript variables.
  • Alternative text and background colors are specified by
    JavaScript variables and are applied on MouseOver.
  • The Sub Menus can be reveled and collapsed by clicking a main topic.
  • The Menu Container height and Main Topic positions
    are controlled as Sub Menus are reveled and collapsed.
  • An onClick Link can be applied to any Main or Sub Topic.
  • Images may be used for both MouseOver and MouseOut.
  • The menu can still provide navigation with JavaScript disabled.


There may be a requirement to display more than one menu on a page.
The topic size, position and color are defined in the style classes and customising variables
but the number of topics, topic text, links and images are defined by the HTML code

The functional code may therefore be used for any number of menus so long a the menu id name is unique.

the <body> onload event needs to call 'mmInitialise()' for each menu.



The structure and existing functions allow additional levels to be added with realtive ease.

The first level has been called 'Main', the second level 'Sub',
a third level called 'Ext' can be added by additions to
the style definitions, HTML code, customising variables and function 'mmInitalise()'.


The 'style' class 'mmExtTopic'.



The additional customising variables.



The expanded 'mmInitialise()' function.



The expanded HTML Code.



Additional levels may be added as required
by duplicating the technique used for adding the 'Ext' Topics.




Section 9 Compact Format

The current menu cascades the Sub Topics.

This is fine but the cascade changes the menu's height
which may be undesirable for some applications.

This cascade can be avoided by changing the positioning of the SubTopics to 'absolute'
in the JavaScript and displaying them ajacent to their parent Main Topic.

The 'Cascade' format requires a topic 'Click' to revel and collapse the menu
MouseOver has not been used due to the changing position of the topics as the menu cascades.

This is not an issue with the 'Compact' format, so 'onMouseOver' is used to revele and collapse.


An additional customising variable 'mmFormat' will specify the required format
as 'Cascade' or 'Compact'.
Note the style ZIndex for the topic types.
'mmMainTopic' ZIndex is set to 0, 'mmSubTopic' is set to 1, 'mmExtTopic' is set to 2.
This is not important for the 'Cascade' menu
but ensures that the Sub Topic is above the Main topic for a 'Compact' Menu.




The function 'mmInitialise()' is expanded
to call new function 'mmCompactFormat(mmMenuObj);' if the variable 'mmFormat' is specified as 'Compact'.



If 'mmFormat' is set to 'Compact' a new function mmCompactFormat(mmMenuObj) is called.



A conditional is added to function 'mmToggle'
to prevent repositioning the Main Topics and setting the menu height



The function 'mmMouseOver' is expanded to call 'mmToggle()'
and to collapse the menu on mouseout if another mouseover does not occur within a specified time.



Before we complete this section.

Up to now the menu has been positioned relativly.
Absolute positioning is esily achieved by placing the menu container and is content
in another <div> and giving that <div> a style position of 'absolute'
and the top and left positions as required.

For this example the absolute position of the additional <div>
has been set to left:50px; and top:100px;




The menu can now be displayed in either 'Cascade' or 'Compact' format
and the positioning can be 'relative' or absolute'.

As many menus of the same format as required can be displayed on the same page.
With JavaScipt switched off the menu will be cascaded.





Section 10 Managing the Script

It is best that the code is partioned.

The HTML code for the menu must be in the body of the host document.

The host document must include - onload="mmInitalise('theMenuId');" in the <body> tag.


I recommend that the fourteen customising variables are specified in mmPart1
The size without notes is less than 1K.
mmPart1 should be positioned between in the <head> and </head> tags.
A typical mmPart1 is in the zip folder as mmPart1.txt
and includes an Application Summary



The functional code is best as an External JavaScipt
called from the host document by
<script language="JavaScript" src="your file path/mmPart2.js" type="text/javascript"></script>
This is in the zip folder as mmPart2.js
For three menu levels but without comments the size is less than 8K.


The menu style can also be called for an external css file by
<link rel="stylesheet" href="your file path/mmStyle.css" type="text/css">
This is in the zip folder as mmStyle.css
The size is about 1K.


The total size of the style and JavaScript code is less than 8K!

All script varible, funtion etc. names are prefixed with 'mm'
to minimise conflicts with other JavaScripts.



I think thats about it
Have Fun