Universal Related Popup Menus / Live Popups
Live Popups
Universal Related Popup Menus
To save a trip to the server, and the user an extra click, we use JavaScript to make our popup menus "live." A live popup acts similarly to a Mac menu, you pull down, select an option, and release the mouse button. This triggers the onChange event which calls the jmp(Page) function (or the relate(Menu) function in the case of the first menu with browsers that support the new Option command (Netscape 3+ and Explorer 4+)).
Live Select Lists
By adding the SIZE attribute to the SELECT tag, you can display multiple options at once. The SELECT menu displays as a scrolling list of options, rather than a popup menu. For the first SIZE options it takes just a single click to select and submit an option. This is useful for site navigation menus (see palm.com for an example). The JavaScript and CGI are identical for both menus. Setting SIZE=1 displays the select list as a popup menu.
<FORM NAME="f1" METHOD="POST" ACTION="/cgi-bin/redirect.cgi" onSubmit="return false"> <SMALL>Pick a subject, any subject:</SMALL><BR> <SELECT NAME="m1" SIZE="3" onChange="jmp(this.form,0)"> <OPTION VALUE="/experts/">Experts <OPTION VALUE="/index2.html">Contents <OPTION VALUE="/services/">Services <OPTION VALUE="/about.html">About </SELECT><INPUT TYPE=SUBMIT VALUE="Go" onClick ="jmp(this.form,0)"> </FORM>
function jmp(form, elt) // The first parameter is a reference to the form. { if (form != null) { // if valid form with (form.elements[elt]) { if (0 <= selectedIndex) // if valid selection location = options[selectedIndex].value; // jump to that option's value } } }
First we check for a valid form name. Then we get which option is selected by looking at the selectedIndex (i= the formnum form and the elementNum element's selected index). If the selectedIndex is >=0 (selectedIndex is -1 for no options selected) then we jump to that option's value, by setting the location property of the current window to the ith option's value, which can be a relative or absolute URL. jmp(this.form,0) jumps to current form's first element's selected option's value, which in this case is a relative URL.
There's no need to hit the submit button, unless you want to go to the currently selected option. Some programmers put a nonfunctional first option with instructions like "select option," but I think this method is more intuitive and elegant. (Bug Note in Netscape 2 nested tables play havoc with events, and the onsubmit event does not trigger, putting the form tag outside nested tables, or just auto-downgrading to the CGI redirect fixes the problem.)
Bug Fix 990722: Netscape 2.02 Mac has a problem with forms embedded in nested tables. The old call to getFormNum() returns a negative value in the MacOS implementation of NS2 (as if the comparison test would never match). Using a named form in jmp() bypasses the problem. Thanks to Michael Guitton
A More Compact Live Popup
Bob Munck ([email protected]) sent in the following tip for those of you with single live popups. This code is more compact, and does not require a function.
<FORM NAME="menu1" METHOD="POST" ACTION="/cgi-bin/redirect.cgi" onSubmit="return false"> <SMALL>Pick a subject, any subject:</SMALL><BR> <SELECT NAME="m" onChange="window.location.href=options[selectedIndex].value"> <OPTION VALUE="/experts/">Experts <OPTION VALUE="/index2.html">Contents <OPTION VALUE="/services/">Services <OPTION VALUE="/about.html">About </SELECT><INPUT TYPE=SUBMIT VALUE="Go" onClick ="window.location.href=this.form.elements[0].options[this.form.elements[0].selectedIndex].value"> </FORM>
990922 - onClick fix Thx to Daniel Kirkdorffer for this one. "The problem with the old onClick (window.location.href=options[selectedIndex].value) is that the onClick code doesn't know how to reference the options and selectedIndex objects unless provided with further information: this.form.elements[0]. Otherwise you get a Javascript error - at least one in Netscape 4.5 on WinNT.
An additional nice thing to have is a conditional statement like this:
if (options[selectedIndex].value != '') window.location.href=options[selectedIndex].value
or
if (this.form.elements[0].options[this.form.elements[0].selectedIndex].value
!= '')
window.location.href=this.form.elements[0].options[this.form.elements[0].selectedIndex].value
To test for blank values. It is sometimes nice to intersperse blank lines in the OPTION lists or include header lines like this:
<OPTION VALUE="">-- Select from the list --
<OPTION VALUE="">
<OPTION VALUE="">Important Links
<OPTION VALUE="">----------------------
<OPTION VALUE="/experts/">Experts
<OPTION VALUE="/index2.html">Contents
<OPTION VALUE="/services/">Services
<OPTION VALUE="/about.html">About
and selecting these from the pulldown should do nothing, and be ignored. Only problem is doing this causes problems with your redirect.cgi process which cannot be intercepted client side and will navigate to the script's $baseurl. Perhaps someone else has a solution for that." Thanks Daniel!
The Ultimate Live Popup
We do indeed have a solution to create the ultimate live popup menu Daniel. On blank separator lines, use a "#" pound character for that OPTION's value. In HTML this means "top of the page" so the menu will not change pages. However, in practice, I've found that the script sometimes jumps to the top of whatever directory I'm in. (see our nav toolbar at top of the page). So I combined the robust check above for non-url values with the "#" for blank lines, and came up with the following solution for universal live popups.
<FORM NAME="WRmenu" METHOD="POST" ACTION="/cgi-bin/redirect.cgi" onSubmit="return false">
<SELECT NAME="WRm" onChange="if(this.form.elements[0].options[this.form.elements[0].selectedIndex].value !='#')
{window.location.href=this.form.elements[0].options[this.form.elements[0].selectedIndex].value};">
<OPTION VALUE="/index2.html" SELECTED">Site Contents
<OPTION VALUE="#"">- - - - -
<OPTION VALUE="/experts/"">Experts
<OPTION VALUE="/3d/"">* 3D Animation
...
<OPTION VALUE="#"">- - - - -
<OPTION VALUE="/services/"">Services
<OPTION VALUE="/interviews/"">* Interviews
<OPTION VALUE="/new/"">* Newsletters
...
</SELECT">
<INPUT TYPE=SUBMIT VALUE="Go" onClick ="if(this.form.elements[0].options[this.form.elements[0].selectedIndex].value !='#')
{window.location.href=this.form.elements[0].options[this.form.elements[0].selectedIndex].value};">
</FORM>
This rather pedantic embedded JavaScript is live in NS 2.02+ and IE4+ on Mac's and PC's and degrades gracefully to the redirect CGI in all non-JavaScript-enabled browsers. It also does nothing for separator lines, as we want. A universal live popup menu! The reason for using "this.form.elements[0].options..." in the if statement instead of "option[selectedIndex]" is we need to specifically reference this form's options array. Without this specificity, IE and NS give options.selectedIndex has no value error for the if statement. This is the code we use in our current nav toolbar include, seen at the top of every page on WebReference.com (except the home page).
Frame Targeting
To target a frame with this menu you need to change two things. For the CGI script you need to include a TARGET="frame_name" in the FORM tag. For the JavaScript you need to change the window.location.href to reference your frame. So in both the onChange and onClick you'd change the code to top.frame_name.location.href.
Let me know if you think of any further improvements.
Comments are welcome
Created: Mar. 10, 1997
Revised: Oct. 30, 2000
URL: https://webreference.com/dev/menus/live.html