Linked comboboxes
<HTML>
<HEAD>
<TITLE>Universal Related Popup Menus / Two, Three, or More! Related Menus - WebReference.com</TITLE>
<!-- Begin: URPM API -->
<SCRIPT LANGUAGE="JavaScript" TYPE="text/javascript">
<!--
// Universal Related Select Menus - v2.02 19991104
// (Dynamically-sized related menus using JS 1.1's new Option cmd)
// by Andrew King aking@internet.com & Michael Guitton saramaca@mail.dotcom.fr
// Copyright (c) 1999 internet.com Corp. All Rights Reserved.
// Originally published and documented at http://www.webreference.com
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
// Change History
//
// see http://www.webreference.com/dev/menus/ for prev code
//
// ---- TOTAL REWRITE ENSUES HERE -----
// NB: The current script is inspired by the above work.
// Yet the related menus aren't created the same way and
// a couple of bugs have been squashed.
// I would advise you to refer to the original program
// to get an idea of what is going on below. ;)
//
// Michael Guitton
// saramaca@mail.dotcom.fr
//
// Change History
//
// 27-Oct-1999 :: added support for frames -mg
// 08-Oct-1999 :: comments added, updated docs - abk
// 05-Oct-1999 :: ref() & relate() renamed, respectively, relate() & update()
// for consistency w/ their respective behaviors - mg
// 04-Oct-1999 :: ref() is all you need (the icing on the cake ;)
// relate() don't rely on get() anymore.
// The current form index is fetched only once
// See onChange handlers in HTML - mg
// 30-Sep-1999 :: printItems() mod so won't stumble on null 1st lvl items - mg
// 29-Sep-1999 :: Added more comments - removed ie5 fix - abk
// 16-Sep-1999 :: relate() changed to be live with end branch
// 14-Sep-1999 :: ref() code rewritten from scratch. Tx Andy!
// 13-Sep-1999 :: New sindex() call checks for unselected parent menu option
// 09-Sep-1999 :: Technique extended to allow 2,3 or more levels with only
// one relate() function (a feature requested by Andy ;)
// 20-Jul-1999 :: IE4+ bug fix (Thanks Peter!)
// 23-Apr-1999 :: Use an entirely different method for menu setup
// Array name isn't hardcoded in the relate() function,
// so several URPMs can be embedded in the same page
// Fixed a couple of bugs
<!-- Begin: URPM Setup -->
var v = false;
var m = null;
var i = null;
// Set all menu trees to null to avoid any error in JavaScript 1.0 browsers -->
var urpm = self; // frame work-around
// urpm = parent.dummy; // Set the target to the relevant frame
// Comment out the above if you don't intend to use frames
function get(form)
{
// loop thru document.forms property and exit w/ current form index
var num = -1;
for (var i = 0; i < document.forms.length; i++) {
if (document.forms[i] == form) {
num = i; // save form index
break;
}
}
return num; // returns current form index
}
function sindex(num, offset, elt)
{
// sel finds selected index of num + offset's form elt's element
// in this case elt is always 0, or first select menu in each form
var sel = document.forms[ num + offset ].elements[elt].selectedIndex;
if (sel < 0) sel = 0;
return sel;
}
function jmp(form, elt)
{ // urpm.location added for optional navigation to named frames
if (form != null) {
with (form.elements[elt]) {
if (0 <= selectedIndex)
urpm.location = options[selectedIndex].value; // jump to selected option's value
}
}
}
function update(num, elt, m)
{ // updates submenus - form(num)'s menu options, and all submenus
// if refd form exists
if (num != -1) {
num++; // reference next form, assume it follows in HTML
with (document.forms[num].elements[elt]) {
for (var i = options.length - 1; 0 < i; i--)
options[i] = null; // null out options in reverse order (bug work-around)
for (var i = 0; i < m.length; i++) {
options[i] = new Option(m[i].text, m[i].value); // fill up next menu's items
}
options[0].selected = true; // default to 1st menu item, windows bug kludge
}
if (m[0].length != 0) {
update(num, elt, m[0]); // update subsequent form if any grandchild menu exists
}
}
}
function relate(form, elt, tree, depth)
{ // relate submenus based on sel of form - calls update to redef submenus
if (v) {
var num = get(form); // fetch the current form index
var a = tree; // set a to be the tree array
while (a != null && --depth != -1)
// traverse menu tree until we reach the corresponding option record
a = a[sindex(num, -depth, elt)];
// at depth 3, should end up w/ something like a[i][j][k]
// where each index holds the value of s(elected )index in related form select elts
if (a != null && a.length) {
// if a array exists and it has elements,
// feed update() w/ this record reference
update(num, elt, a);
return;
}
}
// if a hasn't any array elements or new Option unsupported then end up here ;)
jmp(form, elt); // make like a live popup
}
// Internet Explorer 4+ bug fix:
// IE4+ remembers the index of each SELECT but NOT the CONTENTS of each SELECT,
// so it gets it wrong.
//
// Thanks to Peter Belesis (pbel@internet.com) for pointing this out.
function resetIE() {
for (var i = 0; i < document.forms.length; i++) {
document.forms[i].reset();
}
}
if (document.all)
window.onload = resetIE;
//-->
</SCRIPT>
<SCRIPT LANGUAGE="JavaScript1.1" TYPE="text/javascript">
<!-- This script can also be referenced externally...
// Check if Option constructor is supported
if ((typeof(Option) + "") != "undefined") v = true;
// This constructor works equally well for 2D,3D and over
function O(text, value, submenu)
{
this.text = text;
this.value = value;
this.length = 0;
if (submenu != null) {
// submenu is an array of options...
for (var i = 0; i < submenu.length; ) {
this[i] = submenu[i];
this.length = ++i;
}
}
}
//-->
</SCRIPT>
<!-- End: URPM API -->
<SCRIPT LANGUAGE="JavaScript1.1" TYPE="text/javascript">
if (v) {
m = new Array(
new Array(
new O("3-D Animation","/3d/", new Array(
new O("Lesson56","/3d/lesson56/", new Array(
new O("56.1","/3d/lesson56/", null),
new O("56.2","/3d/lesson56/part2.html",null),
new O("56.3","/3d/lesson56/part3.html",null))
),
new O("Lesson57","/3d/lesson57/", new Array(
new O("57.1","/3d/lesson57/", null),
new O("57.2","/3d/lesson57/part2.html",null),
new O("57.3","/3d/lesson57/part3.html",null))
),
new O("Lesson58","/3d/lesson58/", new Array(
new O("58.1","/3d/lesson58/", null),
new O("58.2","/3d/lesson58/part2.html",null),
new O("58.3","/3d/lesson58/part3.html",null))
),
new O("Lesson59","/3d/lesson59/", new Array(
new O("59.1","/3d/lesson59/", null),
new O("59.2","/3d/lesson59/part2.html",null),
new O("59.3","/3d/lesson59/part3.html",null))
))
),
new O("Design","/dlab/", new Array(
new O("About","/dlab/about.html", new Array(
new O("About.1","/3d/lesson56/", null),
new O("About.2","/3d/lesson56/part2.html",null),
new O("About.3","/3d/lesson56/part3.html",null))
),
new O("Books","/dlab/books/", new Array(
new O("Books.1","/3d/lesson56/", null),
new O("Books.2","/3d/lesson56/part2.html",null),
new O("Books.3","/3d/lesson56/part3.html",null))
),
new O("Dessert Links","/dlab/dessert.html", new Array(
new O("Dessert Links.1","/3d/lesson56/", null),
new O("Dessert Links.2","/3d/lesson56/part2.html",null),
new O("Dessert Links.3","/3d/lesson56/part3.html",null))
),
new O("People Say","/dlab/peoplesay.html", new Array(
new O("People Say.1","/3d/lesson56/", null),
new O("People Say.2","/3d/lesson56/part2.html",null),
new O("People Say.3","/3d/lesson56/part3.html",null))
))
),
new O("DHTML","/dhtml/", new Array(
new O("Dynomat","/dhtml/dynomat/", new Array(
new O("Dynomat.1","/3d/lesson56/", null),
new O("Dynomat.2","/3d/lesson56/part2.html",null),
new O("Dynomat.3","/3d/lesson56/part3.html",null))
),
new O("Diner","/dhtml/diner/", null /*new Array(
new O("Diner.1","/3d/lesson56/", null),
new O("Diner.2","/3d/lesson56/part2.html",null),
new O("Diner.3","/3d/lesson56/part3.html",null))*/
),
new O("Hiermenus","/dhtml/hiermenus/", new Array(
new O("Hiermenus.1","/3d/lesson56/", null),
new O("Hiermenus.2","/3d/lesson56/part2.html",null),
new O("Hiermenus.3","/3d/lesson56/part3.html",null))
),
new O("About","/dhtml/about.html", new Array(
new O("About.1","/3d/lesson56/", null),
new O("About.2","/3d/lesson56/part2.html",null),
new O("About.3","/3d/lesson56/part3.html",null))
))
),
// You can null out the above subarray as shown below:
//
// new O("DHTML","/dhtml/", null /*new Array(
// new O("Dynomat","/dhtml/dynomat/", null),
// new O("Diner","/dhtml/diner/", null),
// new O("Hiermenus","/dhtml/hiermenus/", null),
// new O("About","/dhtml/about.html", null))*/
// ),
new O("Graphics","/graphics/", new Array(
new O("Bio","/graphics/bio.html", new Array(
new O("Bio.1","/3d/lesson56/", null),
new O("Bio.2","/3d/lesson56/part2.html",null),
new O("Bio.3","/3d/lesson56/part3.html",null))
),
new O("Column1","/graphics/column1/", new Array(
new O("Column1.1","/3d/lesson56/", null),
new O("Column1.2","/3d/lesson56/part2.html",null),
new O("Column1.3","/3d/lesson56/part3.html",null))
),
new O("Column2","/graphics/column2/", new Array(
new O("Column2.1","/3d/lesson56/", null),
new O("Column2.2","/3d/lesson56/part2.html",null),
new O("Column2.3","/3d/lesson56/part3.html",null))
),
new O("Column3","/graphics/column3/", new Array(
new O("Column3.1","/3d/lesson56/", null),
new O("Column3.2","/3d/lesson56/part2.html",null),
new O("Column3.3","/3d/lesson56/part3.html",null))
))
),
new O("HTML","/html/", new Array(
new O("About","/html/about/", new Array(
new O("About.1","/3d/lesson56/", null),
new O("About.2","/3d/lesson56/part2.html",null),
new O("About.3","/3d/lesson56/part3.html",null))
),
new O("What's New","/html/new/", new Array(
new O("What's New.1","/3d/lesson56/", null),
new O("What's New.2","/3d/lesson56/part2.html",null),
new O("What's New.3","/3d/lesson56/part3.html",null))
),
new O("Tutorials","/html/tutorials/", new Array(
new O("Tutorials.1","/3d/lesson56/", null),
new O("Tutorials.2","/3d/lesson56/part2.html",null),
new O("Tutorials.3","/3d/lesson56/part3.html",null))
),
new O("Style Watch","/html/watch/", new Array(
new O("Style Watch.1","/3d/lesson56/", null),
new O("Style Watch.2","/3d/lesson56/part2.html",null),
new O("Style Watch.3","/3d/lesson56/part3.html",null))
))
),
new O("JavaScript","/js/", new Array(
new O("About","/js/about.html", new Array(
new O("About.1","/3d/lesson56/", null),
new O("About.2","/3d/lesson56/part2.html",null),
new O("About.3","/3d/lesson56/part3.html",null))
),
new O("Jx Pharmacy","/js/pharmacy/", new Array(
new O("Jx Pharmacy.1","/3d/lesson56/", null),
new O("Jx Pharmacy.2","/3d/lesson56/part2.html",null),
new O("Jx Pharmacy.3","/3d/lesson56/part3.html",null))
),
new O("Column1","/js/column1/", new Array(
new O("Column1.1","/3d/lesson56/", null),
new O("Column1.2","/3d/lesson56/part2.html",null),
new O("Column1.3","/3d/lesson56/part3.html",null))
),
new O("Column2","/js/column2/", new Array(
new O("Column2.1","/3d/lesson56/", null),
new O("Column2.2","/3d/lesson56/part2.html",null),
new O("Column2.3","/3d/lesson56/part3.html",null))
),
new O("Column3","/js/column3/", new Array(
new O("Column3.1","/3d/lesson56/", null),
new O("Column3.2","/3d/lesson56/part2.html",null),
new O("Column3.3","/3d/lesson56/part3.html",null))
))
)
),
new Array(
new O("Authoring","/authoring/", new Array(
new O("Collections","/authoring/collections.html", new Array(
new O("Collections.1","/3d/lesson56/", null),
new O("Collections.2","/3d/lesson56/part2.html",null),
new O("Collections.3","/3d/lesson56/part3.html",null))
),
new O("Design","/authoring/design/", new Array(
new O("Design.1","/3d/lesson56/", null),
new O("Design.2","/3d/lesson56/part2.html",null),
new O("Design.3","/3d/lesson56/part3.html",null))
))
),
new O("Internet","/internet/", new Array(
new O("Collections","/internet/collections.html", new Array(
new O("Collections.1","/3d/lesson56/", null),
new O("Collections.2","/3d/lesson56/part2.html",null),
new O("Collections.3","/3d/lesson56/part3.html",null))
),
new O("Conferences","/internet/conferences.html", new Array(
new O("Conferences.1","/3d/lesson56/", null),
new O("Conferences.2","/3d/lesson56/part2.html",null),
new O("Conferences.3","/3d/lesson56/part3.html",null))
),
new O("Discussion","/internet/discussion.html", new Array(
new O("Discussion.1","/3d/lesson56/", null),
new O("Discussion.2","/3d/lesson56/part2.html",null),
new O("Discussion.3","/3d/lesson56/part3.html",null))
))
)
)
);
i = new Array(
new Array( // internet.com news channels
new O("InternetNews.com","http://www.InternetNews.com",null),
new O("InternetNews Radio","http://stream.internet.com/",null),
new O("atNewYork","http://www.atnewyork.com/",null),
new O("NewsLinx","http://www.newslinx.com",null)
),
new Array( // internet.com web dev channels
new O("WebDeveloper.com","http://www.WebDeveloper.com",null),
new O("WDVL.com","http://WDVL.com/",null),
new O("WebReference.com","http://www.WebReference.com/",null)
)
);
}
</SCRIPT>
<!--
// Initialize above menu trees if Option constructor is supported -->
</SCRIPT>
</HEAD>
<BODY BGCOLOR="#FFFFFF" TEXT="#000000" ALINK="#666666" LINK="#0000CC" VLINK="#CC0099">
<H1 ALIGN=CENTER>Two, Three or More (!) Related Menus</H1>
<H2 ALIGN=CENTER><EM>Universal Related Popup Menus</EM></H2>
<P><A NAME="bi"> </A>
<CENTER>
<TABLE BGCOLOR="#DDCCFF" BORDER="0" CELLPADDING="8" CELLSPACING="0">
<TR VALIGN=BOTTOM>
<TD>Pick an Internet.com Channel:<BR><FORM NAME="fi1" METHOD="POST"
ACTION="/cgi-bin/redirect.cgi" onSubmit="return false;">
<SELECT NAME="i1" ID="i1" CLASS=saveHistory
onChange="relate(this.form, 0, i, 1)">
<OPTION VALUE="news.html">Internet News
<OPTION VALUE="webdev.html">Web Developer
<OPTION VALUE="marketing.html">Internet Marketing
</SELECT><INPUT TYPE=SUBMIT VALUE="Go"
onClick="jmp(this.form,0);">
</FORM></TD>
<TD BGCOLOR="#FFFFFF" VALIGN=MIDDLE><B>-></B></TD>
<TD>Pick a Web Site:<BR><FORM NAME="fi2" METHOD="POST"
ACTION="/cgi-bin/redirect.cgi" onSubmit="return false;">
<SELECT NAME="i2" ID="i2" CLASS=saveHistory onChange="jmp(this.form,0);">
<OPTION VALUE="">InternetNews.com
<OPTION VALUE="">InternetNews Radio
<OPTION VALUE="">AtNewYork
<OPTION VALUE="">NewsLinx
</SELECT><INPUT TYPE=SUBMIT VALUE="Go"
onClick="jmp(this.form,0);">
</FORM></TD>
</TR>
</TABLE>
</CENTER>
<CENTER>
<TABLE BGCOLOR="#DDCCFF" BORDER="0" CELLPADDING="8" CELLSPACING="0">
<TR VALIGN="TOP"><TD>Choose a subject:<BR><FORM NAME="f1" METHOD="POST"
ACTION="/cgi-bin/redirect.cgi" onSubmit="return false;">
<SELECT NAME="m1" ID="m1" CLASS=saveHistory
onChange="relate(this.form, 0, m, 1)">
<OPTION VALUE="/experts/">Experts<OPTION
VALUE="/index2.html">Contents</SELECT>
<INPUT TYPE=SUBMIT VALUE="Go" onClick="jmp(this.form,0);">
<INPUT TYPE="hidden" NAME="baseurl" VALUE="http://www.webreference.com">
</FORM></TD>
<TD BGCOLOR="#FFFFFF" VALIGN=MIDDLE><B>-></B></TD>
<TD>Choose a topic:<BR><FORM NAME="f2" METHOD="POST"
ACTION="/cgi-bin/redirect.cgi" onSubmit="return false;">
<SELECT NAME="m2" ID="m2" CLASS=saveHistory
onChange="relate(this.form, 0, m, 2)">
<!-- ^^^^^^^^^^^^^^^^^^^^^^^^^^
This is where it gets tricky : we have to know the current selection of the
previous menu. I assume the forms follow each other
Michael Guitton
09-Sep-1999
-->
<OPTION VALUE="/3d/">3-D Animation
<OPTION VALUE="/dlab/">Design
<OPTION VALUE="/dhtml/">Dynamic HTML
<OPTION VALUE="/graphics/">Graphics
<OPTION VALUE="/html/">HTML
<OPTION VALUE="/js/">JavaScript</SELECT>
<INPUT TYPE=SUBMIT VALUE="Go" onClick="jmp(this.form,0);">
<INPUT TYPE="hidden" NAME="baseurl" VALUE="http://www.java2s.com">
</FORM></TD>
<TD BGCOLOR="#FFFFFF" VALIGN=MIDDLE><B>-></B></TD>
<TD>Choose a subtopic:<BR><FORM NAME="f3" METHOD="POST"
ACTION="/cgi-bin/redirect.cgi" onSubmit="return false;">
<SELECT NAME="m3" ID="m3" CLASS=saveHistory
onChange="relate(this.form, 0, m, 3)">
<OPTION VALUE="/3d/lesson56/">Lesson56
<OPTION VALUE="/3d/lesson57/">Lesson57
<OPTION VALUE="/3d/lesson58/">Lesson58
<OPTION VALUE="/3d/lesson59/">Lesson59
</SELECT>
<INPUT TYPE=SUBMIT VALUE="Go" onClick="jmp(this.form,0);">
<INPUT TYPE="hidden" NAME="baseurl" VALUE="http://www.webreference.com">
</FORM></TD>
<TD BGCOLOR="#FFFFFF" VALIGN=MIDDLE><B>-></B></TD>
<TD>Choose a sub-subtopic:<BR><FORM NAME="f4" METHOD="POST"
ACTION="/cgi-bin/redirect.cgi" onSubmit="return false;">
<SELECT NAME="m4" ID="m4" CLASS=saveHistory
onChange="jmp(this.form,0)">
<OPTION VALUE="/3d/lesson56/">PAGE1
<OPTION VALUE="/3d/lesson56/part2.html">PAGE2
<OPTION VALUE="/3d/lesson56/part3.html">PAGE3
</SELECT>
<INPUT TYPE=SUBMIT VALUE="Go" onClick="jmp(this.form,0);">
<INPUT TYPE="hidden" NAME="baseurl" VALUE="">
</FORM></TD>
</TR>
</TABLE>
</CENTER>
<PRE><SCRIPT TYPE="text/javascript" LANGUAGE="JavaScript1.1">
<!--
var count;
function printItems(m, shift, level)
{
if (m != null) {
var label = 'Item ' + ((m.text) ? m.text : count);
document.writeln(shift + '// Begin ' + label);
for (var i = 0; i < m.length; i++) {
document.writeln(shift + level + ": " + m[i].text, " => ", m[i].value);
if (m[i].length) {
printItems(m[i], shift + ' ', level + 1);
}
}
document.writeln(shift + '// End ' + label);
}
else
document.writeln(shift + '// Null item ' + count);
}
for (count = 0; count < m.length; count++) {
printItems(m[count], '', 0);
}
document.writeln("");
//-->
</SCRIPT></PRE>
</BODY>
</HTML>
Related examples in the same category