xMenu4 Horizontal - Cascading menus from nested ULs

Intro

This is still experimental. ;-)

Also have a look at the xMenu4 Vertical demo.

This code will turn a set of nested ULs into a cascading dhtml menu. It is completely downgradeable. Disable javascript and reload the page - you'll see the nested ULs with my downgrade css applied.

Revisions

2 Mar 04
No changes to xMenu4.js, but I moved the menu to a page with a different layout and experimented with a few things - so it may be a little less cross-browser right now. There's plenty of tweaking that could still be done - but I'm tired of foolin with it for now ;-)

v0.07, 15 Jan 04
Now supports vertical positioning of main labels. Special thanks to Chris for helping with this.

v0.06, 3 Nov 03
Many improvements this time - rewrote the css and changed some menu code; found an Opera7 bug (130324); IE6's css-support gave me headaches.

v0.05, 27 Oct 03
Separated css and js into two files each. Tweaked css. The menu code now applies the styles on load, so the inline class names can be for downgrade mode. Improved downgrade styles - disable js and reload page to see it. Much remains to be done.

v0.04, 25 Oct 03
More tweaks. As a test I moved the UL to several different places in the html. It is now in one of the content DIVs.

v0.03, 24 Oct 03
Improved event handling and tweaked over-all design.

v0.02, 23 Oct 03
I rewrote the event handling and added A elements in each label element.

Javascript

The js is in two files. One is for page-related js - the loader and onload listener, the other is the menu system code.

xmenu4.js - the menu system, don't rename this file.

xmenu4_1.js - your page onload code, rename this to 'myPage.js'. The contents of this file follow.

////--- Loader

if (!xIE4 && !xNN4) {
  document.write("<"+"link rel='stylesheet' type='text/css' href='xmenu4_1_dhtml.css'>");
  window.onload = xOnload;
}

////--- Load Event Listener

function xOnload()
{
  var me = xGetElementById('myMenu1');
  if (!xDef(me.nodeName, me.firstChild, me.nextSibling)) {
    return;
  }
  
  var mo = new xMenu4(
    me,                       // id str or ele obj of outermost UL
    true,                     // outer UL position: true=absolute, false=static
    true,                     // main label positioning: true=horizontal, false=vertical
    0, 1,                     // box horizontal and vertical offsets
    [-3, -10, -6, -10],       // lbl focus clip array
    [-30, null, null, null],  // box focus clip array
    // css class names:
    'xmBar', 'xmBox',
    'xmBarLbl', 'xmBarLblHvr',
    'xmBarItm', 'xmBarItmHvr',
    'xmBoxLbl', 'xmBoxLblHvr',
    'xmBoxItm', 'xmBoxItmHvr'
  );

  xMnuMgr.add(mo);
  xMnuMgr.load();
  xmWinOnResize();
  xAddEventListener(window, 'resize', xmWinOnResize, false);
}

////--- Window Resize Event Listener

function xmWinOnResize()
{
  // !!!
  var me = xMnuMgr.activeMenu.ele;
  var rc = xGetElementById('rightColumn');
  var mm = xGetElementById('menuMarker');
  var mmp = xParent(mm);
  xMoveTo(me, xPageX(mmp)-xPageX(rc), xPageY(mmp)-xPageY(rc));
  xMnuMgr.paint();
}

CSS

The css is in two files. One supplies default and downgrade mode styles, the other supplies dhtml-related style rules.

xmenu4_1.css - default and downgrade styles, rename this to 'myPage.css'.

xmenu4_1_dhtml.css - dhtml-related styles, rename this to 'myPage_dhtml.css'.

XHTML

No IDs are required, except for the outermost UL. The inline class names are for downgrade mode. Non-downgrade mode class names are passed to the menu object constructor. When Javascript and/or CSS are disabled the menu downgrades to standard nested ULs.

<ul id='myMenu1' class='myBar'> <!-- Begin myMenu1 -->

  <!-- Bar Label 1 -->

  <li><a class='myBarLblA' href=''>lbl-1</a>
    <ul class='myBox'>

      <li><a href=''>item 1-1</a></li>
      <li><a href=''>item 1-2</a></li>

      <li><a class='myBoxLblA' href=''>lbl-1-1</a>
        <ul class='myBox'>
          <li><a href=''>item 1-1-1</a></li>
          <li><a href=''>item 1-1-2</a></li>
        </ul> <!-- end box-1-1 -->
      </li> <!-- end lbl-1-1 -->

      <li><a class='myBoxLblA' href=''>lbl-1-2</a>
        <ul class='myBox'>
          <li><a href=''>item 1-2-1</a></li>
          <li><a href=''>item 1-2-2</a></li>

          <li><a class='myBoxLblA' href=''>lbl-1-2-1</a>
            <ul class='myBox'>
              <li><a href=''>item 1-2-1-1</a></li>
              <li><a href=''>item 1-2-1-2</a></li>
            </ul> <!-- end box-1-2-1 -->
          </li> <!-- end lbl-1-2-1 -->

        </ul> <!-- end box-1-2 -->
      </li> <!-- end lbl-1-2 -->

    </ul> <!-- end box-1 -->
  </li> <!-- end lbl-1 -->

  <!-- Bar Label 2 -->

  <li><a class='myBarLblA' href=''>lbl-2</a>
    <ul class='myBox'>

      <li><a href=''>item 2-1</a></li>
      <li><a href=''>item 2-2</a></li>

      <li><a class='myBoxLblA' href=''>lbl-2-1</a>
        <ul class='myBox'>
          <li><a href=''>item 2-1-1</a></li>
          <li><a href=''>item 2-1-2</a></li>

          <li><a class='myBoxLblA' href=''>lbl-2-1-1</a>
            <ul class='myBox'>
              <li><a href=''>item 2-1-1-1</a></li>
              <li><a href=''>item 2-1-1-2</a></li>
            </ul> <!-- end box-2-1-1 -->
          </li> <!-- end lbl-2-1-1 -->

        </ul> <!-- end box-2-1 -->
      </li> <!-- end lbl-2-1 -->

      <li><a class='myBoxLblA' href=''>lbl-2-2</a>
        <ul class='myBox'>
          <li><a href=''>item 2-2-1</a></li>
          <li><a href=''>item 2-2-2</a></li>
        </ul> <!-- end lbl-2-2 -->
      </li> <!-- end box-2-2 -->

    </ul> <!-- end box-2 -->
  </li> <!-- end lbl-2 -->

  <!-- Bar Item 1 -->

  <li><a class='myBarItmA' href=''>item-1</a></li>

</ul> <!-- end myMenu1 -->