[ Index ]

PHP Cross Reference of Mambo 4.6.5

[ Variables ]     [ Functions ]     [ Classes ]     [ Constants ]     [ Statistics ]

title

Body

[close]

/includes/js/ -> JSCookMenu.js (source)

   1  /*

   2      JSCookMenu v2.0.3 (c) Copyright 2002-2006 by Heng Yuan

   3  

   4      http://jscook.sourceforge.net/JSCookMenu/

   5  

   6      Permission is hereby granted, free of charge, to any person obtaining a

   7      copy of this software and associated documentation files (the "Software"),

   8      to deal in the Software without restriction, including without limitation

   9      the rights to use, copy, modify, merge, publish, distribute, sublicense,

  10      and/or sell copies of the Software, and to permit persons to whom the

  11      Software is furnished to do so, subject to the following conditions:

  12  

  13      The above copyright notice and this permission notice shall be included

  14      in all copies or substantial portions of the Software.

  15  

  16      THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS

  17      OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,

  18      ITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE

  19      AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER

  20      LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING

  21      FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER

  22      DEALINGS IN THE SOFTWARE.

  23  */
  24  
  25  // default node properties

  26  var _cmNodeProperties =
  27  {
  28      // theme prefix

  29      prefix:    '',
  30  
  31        // main menu display attributes

  32        //

  33        // Note.  When the menu bar is horizontal,

  34        // mainFolderLeft and mainFolderRight are

  35        // put in <span></span>.  When the menu

  36        // bar is vertical, they would be put in

  37        // a separate TD cell.

  38  
  39        // HTML code to the left of the folder item

  40        mainFolderLeft: '',
  41        // HTML code to the right of the folder item

  42        mainFolderRight: '',
  43      // HTML code to the left of the regular item

  44      mainItemLeft: '',
  45      // HTML code to the right of the regular item

  46      mainItemRight:    '',
  47  
  48      // sub menu display attributes

  49  
  50      // HTML code to the left of the folder item

  51      folderLeft:        '',
  52      // HTML code to the right of the folder item

  53      folderRight:    '',
  54      // HTML code to the left of the regular item

  55      itemLeft:        '',
  56      // HTML code to the right of the regular item

  57      itemRight:        '',
  58      // cell spacing for main menu

  59      mainSpacing:    0,
  60      // cell spacing for sub menus

  61      subSpacing:        0,
  62  
  63      // optional settings

  64      // If not set, use the default

  65  
  66      // auto disappear time for submenus in milli-seconds

  67      delay:            500,
  68  
  69      // 1st layer sub menu starting index

  70      zIndexStart:    1000,
  71      // z-index incremental step for subsequent layers

  72      zIndexInc:        5,
  73  
  74      // sub menu header appears before the sub menu table

  75      subMenuHeader:    null,
  76      // sub menu header appears after the sub menu table

  77      subMenuFooter:    null,
  78  
  79      // submenu location adjustments

  80      //

  81      // offsetHMainAdjust for adjusting the first submenu

  82      //         of a 'hbr' menu.

  83      // offsetVMainAdjust for adjusting the first submenu

  84      //        of a 'vbr' menu.

  85      // offsetSubAdjust for subsequent level of submenus

  86      //

  87      offsetHMainAdjust:    [0, 0],
  88      offsetVMainAdjust:    [0, 0],
  89      offsetSubAdjust:    [0, 0],
  90  
  91      // act on click to open sub menu

  92      // not yet implemented

  93      // 0 : use default behavior

  94      // 1 : hover open in all cases

  95      // 2 : click on main, hover on sub

  96      // 3 : click open in all cases (illegal as of 1.5)

  97      clickOpen:        1,
  98  
  99      // special effects on open/closing a sub menu

 100      effect:            null
 101  };
 102  
 103  // Globals

 104  var _cmIDCount = 0;
 105  var _cmIDName = 'cmSubMenuID';        // for creating submenu id

 106  
 107  var _cmTimeOut = null;                // how long the menu would stay

 108  var _cmCurrentItem = null;            // the current menu item being selected;

 109  
 110  var _cmNoAction = new Object ();    // indicate that the item cannot be hovered.

 111  var _cmNoClick = new Object ();        // similar to _cmNoAction but does not respond to mouseup/mousedown events

 112  var _cmSplit = new Object ();        // indicate that the item is a menu split

 113  
 114  var _cmMenuList = new Array ();        // a list of the current menus

 115  var _cmItemList = new Array ();        // a simple list of items

 116  
 117  var _cmFrameList = new Array ();    // a pool of reusable iframes

 118  var _cmFrameListSize = 0;            // keep track of the actual size

 119  var _cmFrameIDCount = 0;            // keep track of the frame id

 120  var _cmFrameMasking = true;            // use the frame masking

 121  
 122  // disable iframe masking for IE7

 123  /*@cc_on

 124      @if (@_jscript_version >= 5.6)

 125          if (_cmFrameMasking)

 126          {

 127              var v = navigator.appVersion;

 128              var i = v.indexOf ("MSIE ");

 129              if (i >= 0)

 130              {

 131                  if (parseInt (navigator.appVersion.substring (i + 5)) >= 7)

 132                      _cmFrameMasking = false;

 133              }

 134          }

 135      @end

 136  @*/
 137  
 138  var _cmClicked = false;                // for onClick

 139  
 140  // flag for turning on off hiding objects

 141  //

 142  // 0: automatic

 143  // 1: hiding

 144  // 2: no hiding

 145  var _cmHideObjects = 0;
 146  
 147  // Utility function to do a shallow copy a node property

 148  function cmClone (nodeProperties)
 149  {
 150      var returnVal = new Object ();
 151      for (v in nodeProperties)
 152          returnVal[v] = nodeProperties[v];
 153      return returnVal;
 154  }
 155  
 156  //

 157  // store the new menu information into a structure to retrieve it later

 158  //

 159  function cmAllocMenu (id, menu, orient, nodeProperties, prefix)
 160  {
 161      var info = new Object ();
 162      info.div = id;
 163      info.menu = menu;
 164      info.orient = orient;
 165      info.nodeProperties = nodeProperties;
 166      info.prefix = prefix;
 167      var menuID = _cmMenuList.length;
 168      _cmMenuList[menuID] = info;
 169      return menuID;
 170  }
 171  
 172  //

 173  // request a frame

 174  //

 175  function cmAllocFrame ()
 176  {
 177      if (_cmFrameListSize > 0)
 178          return cmGetObject (_cmFrameList[--_cmFrameListSize]);
 179      var frameObj = document.createElement ('iframe');
 180      var id = _cmFrameIDCount++;
 181      frameObj.id = 'cmFrame' + id;
 182      frameObj.frameBorder = '0';
 183      frameObj.style.display = 'none';
 184      frameObj.src = 'javascript:false';
 185      document.body.appendChild (frameObj);
 186      frameObj.style.filter = 'alpha(opacity=0)';
 187      frameObj.style.zIndex = 99;
 188      frameObj.style.position = 'absolute';
 189      frameObj.style.border = '0';
 190      frameObj.scrolling = 'no';
 191      return frameObj;
 192  }
 193  
 194  //

 195  // make a frame resuable later

 196  //

 197  function cmFreeFrame (frameObj)
 198  {
 199      _cmFrameList[_cmFrameListSize++] = frameObj.id;
 200  }
 201  
 202  //////////////////////////////////////////////////////////////////////

 203  //

 204  // Drawing Functions and Utility Functions

 205  //

 206  //////////////////////////////////////////////////////////////////////

 207  
 208  //

 209  // produce a new unique id

 210  //

 211  function cmNewID ()
 212  {
 213      return _cmIDName + (++_cmIDCount);
 214  }
 215  
 216  //

 217  // return the property string for the menu item

 218  //

 219  function cmActionItem (item, isMain, idSub, menuInfo, menuID)
 220  {
 221      _cmItemList[_cmItemList.length] = item;
 222      var index = _cmItemList.length - 1;
 223      idSub = (!idSub) ? 'null' : ('\'' + idSub + '\'');
 224  
 225      var clickOpen = menuInfo.nodeProperties.clickOpen;
 226      var onClick = (clickOpen == 3) || (clickOpen == 2 && isMain);
 227  
 228      var param = 'this,' + isMain + ',' + idSub + ',' + menuID + ',' + index;
 229  
 230      var returnStr;
 231      if (onClick)
 232          returnStr = ' onmouseover="cmItemMouseOver(' + param + ',false)" onmousedown="cmItemMouseDownOpenSub (' + param + ')"';
 233      else
 234          returnStr = ' onmouseover="cmItemMouseOverOpenSub (' + param + ')" onmousedown="cmItemMouseDown (' + param + ')"';
 235      return returnStr + ' onmouseout="cmItemMouseOut (' + param + ')" onmouseup="cmItemMouseUp (' + param + ')"';
 236  }
 237  
 238  //

 239  // this one is used by _cmNoClick to only take care of onmouseover and onmouseout

 240  // events which are associated with menu but not actions associated with menu clicking/closing

 241  //

 242  function cmNoClickItem (item, isMain, idSub, menuInfo, menuID)
 243  {
 244      // var index = _cmItemList.push (item) - 1;

 245      _cmItemList[_cmItemList.length] = item;
 246      var index = _cmItemList.length - 1;
 247      idSub = (!idSub) ? 'null' : ('\'' + idSub + '\'');
 248  
 249      var param = 'this,' + isMain + ',' + idSub + ',' + menuID + ',' + index;
 250  
 251      return ' onmouseover="cmItemMouseOver (' + param + ')" onmouseout="cmItemMouseOut (' + param + ')"';
 252  }
 253  
 254  function cmNoActionItem (item)
 255  {
 256      return item[1];
 257  }
 258  
 259  function cmSplitItem (prefix, isMain, vertical)
 260  {
 261      var classStr = 'cm' + prefix;
 262      if (isMain)
 263      {
 264          classStr += 'Main';
 265          if (vertical)
 266              classStr += 'HSplit';
 267          else
 268              classStr += 'VSplit';
 269      }
 270      else
 271          classStr += 'HSplit';
 272      return eval (classStr);
 273  }
 274  
 275  //

 276  // draw the sub menu recursively

 277  //

 278  function cmDrawSubMenu (subMenu, prefix, id, nodeProperties, zIndexStart, menuInfo, menuID)
 279  {
 280      var str = '<div class="' + prefix + 'SubMenu" id="' + id + '" style="z-index: ' + zIndexStart + ';position: absolute; top: 0px; left: 0px;">';
 281      if (nodeProperties.subMenuHeader)
 282          str += nodeProperties.subMenuHeader;
 283  
 284      str += '<table summary="sub menu" id="' + id + 'Table" cellspacing="' + nodeProperties.subSpacing + '" class="' + prefix + 'SubMenuTable">';
 285  
 286      var strSub = '';
 287  
 288      var item;
 289      var idSub;
 290      var hasChild;
 291  
 292      var i;
 293  
 294      var classStr;
 295  
 296      for (i = 5; i < subMenu.length; ++i)
 297      {
 298          item = subMenu[i];
 299          if (!item)
 300              continue;
 301  
 302          if (item == _cmSplit)
 303              item = cmSplitItem (prefix, 0, true);
 304          item.parentItem = subMenu;
 305          item.subMenuID = id;
 306  
 307          hasChild = (item.length > 5);
 308          idSub = hasChild ? cmNewID () : null;
 309  
 310          str += '<tr class="' + prefix + 'MenuItem"';
 311          if (item[0] != _cmNoClick)
 312              str += cmActionItem (item, 0, idSub, menuInfo, menuID);
 313          else
 314              str += cmNoClickItem (item, 0, idSub, menuInfo, menuID);
 315          str += '>'
 316  
 317          if (item[0] == _cmNoAction || item[0] == _cmNoClick)
 318          {
 319              str += cmNoActionItem (item);
 320              str += '</tr>';
 321              continue;
 322          }
 323  
 324          classStr = prefix + 'Menu';
 325          classStr += hasChild ? 'Folder' : 'Item';
 326  
 327          str += '<td class="' + classStr + 'Left">';
 328  
 329          if (item[0] != null)
 330              str += item[0];
 331          else
 332              str += hasChild ? nodeProperties.folderLeft : nodeProperties.itemLeft;
 333  
 334          str += '</td><td class="' + classStr + 'Text">' + item[1];
 335  
 336          str += '</td><td class="' + classStr + 'Right">';
 337  
 338          if (hasChild)
 339          {
 340              str += nodeProperties.folderRight;
 341              strSub += cmDrawSubMenu (item, prefix, idSub, nodeProperties, zIndexStart + nodeProperties.zIndexInc, menuInfo, menuID);
 342          }
 343          else
 344              str += nodeProperties.itemRight;
 345          str += '</td></tr>';
 346      }
 347  
 348      str += '</table>';
 349  
 350      if (nodeProperties.subMenuFooter)
 351          str += nodeProperties.subMenuFooter;
 352      str += '</div>' + strSub;
 353      return str;
 354  }
 355  
 356  //

 357  // The function that builds the menu inside the specified element id.

 358  //

 359  // id                id of the element

 360  // orient            orientation of the menu in [hv][ub][lr] format

 361  // menu                the menu object to be drawn

 362  // nodeProperties    properties for the theme

 363  // prefix            prefix of the theme

 364  //

 365  function cmDraw (id, menu, orient, nodeProperties, prefix)
 366  {
 367      var obj = cmGetObject (id);
 368  
 369      if (!prefix)
 370          prefix = nodeProperties.prefix;
 371      if (!prefix)
 372          prefix = '';
 373      if (!nodeProperties)
 374          nodeProperties = _cmNodeProperties;
 375      if (!orient)
 376          orient = 'hbr';
 377  
 378      var menuID = cmAllocMenu (id, menu, orient, nodeProperties, prefix);
 379      var menuInfo = _cmMenuList[menuID];
 380  
 381      // setup potentially missing properties

 382      if (!nodeProperties.delay)
 383          nodeProperties.delay = _cmNodeProperties.delay;
 384      if (!nodeProperties.clickOpen)
 385          nodeProperties.clickOpen = _cmNodeProperties.clickOpen;
 386      if (!nodeProperties.zIndexStart)
 387          nodeProperties.zIndexStart = _cmNodeProperties.zIndexStart;
 388      if (!nodeProperties.zIndexInc)
 389          nodeProperties.zIndexInc = _cmNodeProperties.zIndexInc;
 390      if (!nodeProperties.offsetHMainAdjust)
 391          nodeProperties.offsetHMainAdjust = _cmNodeProperties.offsetHMainAdjust;
 392      if (!nodeProperties.offsetVMainAdjust)
 393          nodeProperties.offsetVMainAdjust = _cmNodeProperties.offsetVMainAdjust;
 394      if (!nodeProperties.offsetSubAdjust)
 395          nodeProperties.offsetSubAdjust = _cmNodeProperties.offsetSubAdjust;
 396      // save user setting on frame masking

 397      menuInfo.cmFrameMasking = _cmFrameMasking;
 398  
 399      var str = '<table summary="main menu" class="' + prefix + 'Menu" cellspacing="' + nodeProperties.mainSpacing + '">';
 400      var strSub = '';
 401  
 402      var vertical;
 403  
 404      // draw the main menu items

 405      if (orient.charAt (0) == 'h')
 406      {
 407          str += '<tr>';
 408          vertical = false;
 409      }
 410      else
 411      {
 412          vertical = true;
 413      }
 414  
 415      var i;
 416      var item;
 417      var idSub;
 418      var hasChild;
 419  
 420      var classStr;
 421  
 422      for (i = 0; i < menu.length; ++i)
 423      {
 424          item = menu[i];
 425  
 426          if (!item)
 427              continue;
 428  
 429          item.menu = menu;
 430          item.subMenuID = id;
 431  
 432          str += vertical ? '<tr' : '<td';
 433          str += ' class="' + prefix + 'MainItem"';
 434  
 435          hasChild = (item.length > 5);
 436          idSub = hasChild ? cmNewID () : null;
 437  
 438          str += cmActionItem (item, 1, idSub, menuInfo, menuID) + '>';
 439  
 440          if (item == _cmSplit)
 441              item = cmSplitItem (prefix, 1, vertical);
 442  
 443          if (item[0] == _cmNoAction || item[0] == _cmNoClick)
 444          {
 445              str += cmNoActionItem (item);
 446              str += vertical? '</tr>' : '</td>';
 447              continue;
 448          }
 449  
 450          classStr = prefix + 'Main' + (hasChild ? 'Folder' : 'Item');
 451  
 452          str += vertical ? '<td' : '<span';
 453          str += ' class="' + classStr + 'Left">';
 454  
 455          str += (item[0] == null) ? (hasChild ? nodeProperties.mainFolderLeft : nodeProperties.mainItemLeft)
 456                       : item[0];
 457          str += vertical ? '</td>' : '</span>';
 458  
 459          str += vertical ? '<td' : '<span';
 460          str += ' class="' + classStr + 'Text">';
 461          str += item[1];
 462  
 463          str += vertical ? '</td>' : '</span>';
 464  
 465          str += vertical ? '<td' : '<span';
 466          str += ' class="' + classStr + 'Right">';
 467  
 468          str += hasChild ? nodeProperties.mainFolderRight : nodeProperties.mainItemRight;
 469  
 470          str += vertical ? '</td>' : '</span>';
 471  
 472          str += vertical ? '</tr>' : '</td>';
 473  
 474          if (hasChild)
 475              strSub += cmDrawSubMenu (item, prefix, idSub, nodeProperties, nodeProperties.zIndexStart, menuInfo, menuID);
 476      }
 477      if (!vertical)
 478          str += '</tr>';
 479      str += '</table>' + strSub;
 480      obj.innerHTML = str;
 481  }
 482  
 483  //

 484  // The function builds the menu inside the specified element id.

 485  //

 486  // This function is similar to cmDraw except that menu is taken from HTML node

 487  // rather a javascript tree.  This feature allows links to be scanned by search

 488  // bots.

 489  //

 490  // This function basically converts HTML node to a javascript tree, and then calls

 491  // cmDraw to draw the actual menu, replacing the hidden menu tree.

 492  //

 493  // Format:

 494  //    <div id="menu">

 495  //        <ul style="visibility: hidden">

 496  //            <li><span>icon</span><a href="link" title="description">main menu text</a>

 497  //                <ul>

 498  //                    <li><span>icon</span><a href="link" title="description">submenu item</a>

 499  //                    </li>

 500  //                </ul>

 501  //            </li>

 502  //        </ul>

 503  //    </div>

 504  //

 505  function cmDrawFromText (id, orient, nodeProperties, prefix)
 506  {
 507      var domMenu = cmGetObject (id);
 508      var menu = null;
 509      for (var currentDomItem = domMenu.firstChild; currentDomItem; currentDomItem = currentDomItem.nextSibling)
 510      {
 511          if (!currentDomItem.tagName)
 512              continue;
 513          var tag = currentDomItem.tagName.toLowerCase ();
 514          if (tag != 'ul' && tag != 'ol')
 515              continue;
 516          menu = cmDrawFromTextSubMenu (currentDomItem);
 517          break;
 518      }
 519      if (menu)
 520          cmDraw (id, menu, orient, nodeProperties, prefix);
 521  }
 522  
 523  //

 524  // a recursive function that build menu tree structure

 525  //

 526  function cmDrawFromTextSubMenu (domMenu)
 527  {
 528      var items = new Array ();
 529      for (var currentDomItem = domMenu.firstChild; currentDomItem; currentDomItem = currentDomItem.nextSibling)
 530      {
 531          if (!currentDomItem.tagName || currentDomItem.tagName.toLowerCase () != 'li')
 532              continue;
 533          if (currentDomItem.firstChild == null)
 534          {
 535              items[items.length] = _cmSplit;
 536              continue;
 537          }
 538          var item = new Array ();
 539          var currentItem = currentDomItem.firstChild;
 540          var hasAction = false;
 541          for (; currentItem; currentItem = currentItem.nextSibling)
 542          {
 543              // scan for span or div tag

 544              if (!currentItem.tagName)
 545                  continue;
 546              if (currentItem.className == 'cmNoClick')
 547              {
 548                  item[0] = _cmNoClick;
 549                  item[1] = getActionHTML (currentItem);
 550                  hasAction = true;
 551                  break;
 552              }
 553              if (currentItem.className == 'cmNoAction')
 554              {
 555                  item[0] = _cmNoAction;
 556                  item[1] = getActionHTML (currentItem);
 557                  hasAction = true;
 558                  break;
 559              }
 560              var tag = currentItem.tagName.toLowerCase ();
 561              if (tag != 'span')
 562                  continue;
 563              if (!currentItem.firstChild)
 564                  item[0] = null;
 565              else
 566                  item[0] = currentItem.innerHTML;
 567              currentItem = currentItem.nextSibling;
 568              break;
 569          }
 570          if (hasAction)
 571          {
 572              items[items.length] = item;
 573              continue;
 574          }
 575          if (!currentItem)
 576              continue;
 577          for (; currentItem; currentItem = currentItem.nextSibling)
 578          {
 579              if (!currentItem.tagName)
 580                  continue;
 581              var tag = currentItem.tagName.toLowerCase ();
 582              if (tag == 'a')
 583              {
 584                  item[1] = currentItem.innerHTML;
 585                  item[2] = currentItem.href;
 586                  item[3] = currentItem.target;
 587                  item[4] = currentItem.title;
 588                  if (item[4] == '')
 589                      item[4] = null;
 590              }
 591              else if (tag == 'span' || tag == 'div')
 592              {
 593                  item[1] = currentItem.innerHTML;
 594                  item[2] = null;
 595                  item[3] = null;
 596                  item[4] = null;
 597              }
 598              break;
 599          }
 600  
 601          for (; currentItem; currentItem = currentItem.nextSibling)
 602          {
 603              // scan for span tag

 604              if (!currentItem.tagName)
 605                  continue;
 606              var tag = currentItem.tagName.toLowerCase ();
 607              if (tag != 'ul' && tag != 'ol')
 608                  continue;
 609              var subMenuItems = cmDrawFromTextSubMenu (currentItem);
 610              for (i = 0; i < subMenuItems.length; ++i)
 611                  item[i + 5] = subMenuItems[i];
 612              break;
 613          }
 614          items[items.length] = item;
 615      }
 616      return items;
 617  }
 618  
 619  //

 620  // obtain the actual action item's action, which is inside a

 621  // table.  The first row should be it

 622  //

 623  function getActionHTML (htmlNode)
 624  {
 625      var returnVal = '<td></td><td></td><td></td>';
 626      var currentDomItem;
 627      // find the table first

 628      for (currentDomItem = htmlNode.firstChild; currentDomItem; currentDomItem = currentDomItem.nextSibling)
 629      {
 630          if (currentDomItem.tagName && currentDomItem.tagName.toLowerCase () == 'table')
 631              break;
 632      }
 633      if (!currentDomItem)
 634          return returnVal;
 635      // skip over tbody

 636      for (currentDomItem = currentDomItem.firstChild; currentDomItem; currentDomItem = currentDomItem.nextSibling)
 637      {
 638          if (currentDomItem.tagName && currentDomItem.tagName.toLowerCase () == 'tbody')
 639              break;
 640      }
 641      if (!currentDomItem)
 642          return returnVal;
 643      // get the first tr

 644      for (currentDomItem = currentDomItem.firstChild; currentDomItem; currentDomItem = currentDomItem.nextSibling)
 645      {
 646          if (currentDomItem.tagName && currentDomItem.tagName.toLowerCase () == 'tr')
 647              break;
 648      }
 649      if (!currentDomItem)
 650          return returnVal;
 651      return currentDomItem.innerHTML;
 652  }
 653  
 654  //

 655  // get the DOM object associated with the item

 656  //

 657  function cmGetMenuItem (item)
 658  {
 659      if (!item.subMenuID)
 660          return null;
 661      var subMenu = cmGetObject (item.subMenuID);
 662      // we are dealing with a main menu item

 663      if (item.menu)
 664      {
 665          var menu = item.menu;
 666          // skip over table, tbody, tr, reach td

 667          subMenu = subMenu.firstChild.firstChild.firstChild.firstChild;
 668          var i;
 669          for (i = 0; i < menu.length; ++i)
 670          {
 671              if (menu[i] == item)
 672                  return subMenu;
 673              subMenu = subMenu.nextSibling;
 674          }
 675      }
 676      else if (item.parentItem) // sub menu item
 677      {
 678          var menu = item.parentItem;
 679          var table = cmGetObject (item.subMenuID + 'Table');
 680          if (!table)
 681              return null;
 682          // skip over table, tbody, reach tr

 683          subMenu = table.firstChild.firstChild;
 684          var i;
 685          for (i = 5; i < menu.length; ++i)
 686          {
 687              if (menu[i] == item)
 688                  return subMenu;
 689              subMenu = subMenu.nextSibling;
 690          }
 691      }
 692      return null;
 693  }
 694  
 695  //

 696  // disable a menu item

 697  //

 698  function cmDisableItem (item, prefix)
 699  {
 700      if (!item)
 701          return;
 702      var menuItem = cmGetMenuItem (item);
 703      if (!menuItem)
 704          return;
 705      if (item.menu)
 706          menuItem.className = prefix + 'MainItemDisabled';
 707      else
 708          menuItem.className = prefix + 'MenuItemDisabled';
 709      item.isDisabled = true;
 710  }
 711  
 712  //

 713  // enable a menu item

 714  //

 715  function cmEnableItem (item, prefix)
 716  {
 717      if (!item)
 718          return;
 719      var menuItem = cmGetMenuItem (item);
 720      if (!menuItem)
 721          return;
 722      if (item.menu)
 723          menu.className = prefix + 'MainItem';
 724      else
 725          menu.className = prefix + 'MenuItem';
 726      item.isDisabled = true;
 727  }
 728  
 729  //////////////////////////////////////////////////////////////////////

 730  //

 731  // Mouse Event Handling Functions

 732  //

 733  //////////////////////////////////////////////////////////////////////

 734  
 735  //

 736  // action should be taken for mouse moving in to the menu item

 737  //

 738  // Here we just do things concerning this menu item, w/o opening sub menus.

 739  //

 740  function cmItemMouseOver (obj, isMain, idSub, menuID, index, calledByOpenSub)
 741  {
 742      if (!calledByOpenSub && _cmClicked)
 743      {
 744          cmItemMouseOverOpenSub (obj, isMain, idSub, menuID, index);
 745          return;
 746      }
 747  
 748      clearTimeout (_cmTimeOut);
 749  
 750      if (_cmItemList[index].isDisabled)
 751          return;
 752  
 753      var prefix = _cmMenuList[menuID].prefix;
 754  
 755      if (!obj.cmMenuID)
 756      {
 757          obj.cmMenuID = menuID;
 758          obj.cmIsMain = isMain;
 759      }
 760  
 761      var thisMenu = cmGetThisMenu (obj, prefix);
 762  
 763      // insert obj into cmItems if cmItems doesn't have obj

 764      if (!thisMenu.cmItems)
 765          thisMenu.cmItems = new Array ();
 766      var i;
 767      for (i = 0; i < thisMenu.cmItems.length; ++i)
 768      {
 769          if (thisMenu.cmItems[i] == obj)
 770              break;
 771      }
 772      if (i == thisMenu.cmItems.length)
 773      {
 774          //thisMenu.cmItems.push (obj);

 775          thisMenu.cmItems[i] = obj;
 776      }
 777  
 778      // hide the previous submenu that is not this branch

 779      if (_cmCurrentItem)
 780      {
 781          // occationally, we get this case when user

 782          // move the mouse slowly to the border

 783          if (_cmCurrentItem == obj || _cmCurrentItem == thisMenu)
 784          {
 785              var item = _cmItemList[index];
 786              cmSetStatus (item);
 787              return;
 788          }
 789  
 790          var thatMenuInfo = _cmMenuList[_cmCurrentItem.cmMenuID];
 791          var thatPrefix = thatMenuInfo.prefix;
 792          var thatMenu = cmGetThisMenu (_cmCurrentItem, thatPrefix);
 793  
 794          if (thatMenu != thisMenu.cmParentMenu)
 795          {
 796              if (_cmCurrentItem.cmIsMain)
 797                  _cmCurrentItem.className = thatPrefix + 'MainItem';
 798              else
 799                  _cmCurrentItem.className = thatPrefix + 'MenuItem';
 800              if (thatMenu.id != idSub)
 801                  cmHideMenu (thatMenu, thisMenu, thatMenuInfo);
 802          }
 803      }
 804  
 805      // okay, set the current menu to this obj

 806      _cmCurrentItem = obj;
 807  
 808      // just in case, reset all items in this menu to MenuItem

 809      cmResetMenu (thisMenu, prefix);
 810  
 811      var item = _cmItemList[index];
 812      var isDefaultItem = cmIsDefaultItem (item);
 813  
 814      if (isDefaultItem)
 815      {
 816          if (isMain)
 817              obj.className = prefix + 'MainItemHover';
 818          else
 819              obj.className = prefix + 'MenuItemHover';
 820      }
 821  
 822      cmSetStatus (item);
 823  }
 824  
 825  //

 826  // action should be taken for mouse moving in to the menu item

 827  //

 828  // This function also opens sub menu

 829  //

 830  function cmItemMouseOverOpenSub (obj, isMain, idSub, menuID, index)
 831  {
 832      clearTimeout (_cmTimeOut);
 833  
 834      if (_cmItemList[index].isDisabled)
 835          return;
 836  
 837      cmItemMouseOver (obj, isMain, idSub, menuID, index, true);
 838  
 839      if (idSub)
 840      {
 841          var subMenu = cmGetObject (idSub);
 842          var menuInfo = _cmMenuList[menuID];
 843          var orient = menuInfo.orient;
 844          var prefix = menuInfo.prefix;
 845          cmShowSubMenu (obj, isMain, subMenu, menuInfo);
 846      }
 847  }
 848  
 849  //

 850  // action should be taken for mouse moving out of the menu item

 851  //

 852  function cmItemMouseOut (obj, isMain, idSub, menuID, index)
 853  {
 854      var delayTime = _cmMenuList[menuID].nodeProperties.delay;
 855      _cmTimeOut = window.setTimeout ('cmHideMenuTime ()', delayTime);
 856      window.defaultStatus = '';
 857  }
 858  
 859  //

 860  // action should be taken for mouse button down at a menu item

 861  //

 862  function cmItemMouseDown (obj, isMain, idSub, menuID, index)
 863  {
 864      if (_cmItemList[index].isDisabled)
 865          return;
 866  
 867      if (cmIsDefaultItem (_cmItemList[index]))
 868      {
 869          var prefix = _cmMenuList[menuID].prefix;
 870          if (obj.cmIsMain)
 871              obj.className = prefix + 'MainItemActive';
 872          else
 873              obj.className = prefix + 'MenuItemActive';
 874      }
 875  }
 876  
 877  //

 878  // action should be taken for mouse button down at a menu item

 879  // this is one also opens submenu if needed

 880  //

 881  function cmItemMouseDownOpenSub (obj, isMain, idSub, menuID, index)
 882  {
 883      if (_cmItemList[index].isDisabled)
 884          return;
 885  
 886      _cmClicked = true;
 887      cmItemMouseDown (obj, isMain, idSub, menuID, index);
 888  
 889      if (idSub)
 890      {
 891          var subMenu = cmGetObject (idSub);
 892          var menuInfo = _cmMenuList[menuID];
 893          cmShowSubMenu (obj, isMain, subMenu, menuInfo);
 894      }
 895  }
 896  
 897  //

 898  // action should be taken for mouse button up at a menu item

 899  //

 900  function cmItemMouseUp (obj, isMain, idSub, menuID, index)
 901  {
 902      if (_cmItemList[index].isDisabled)
 903          return;
 904  
 905      var item = _cmItemList[index];
 906  
 907      var link = null, target = '_self';
 908  
 909      if (item.length > 2)
 910          link = item[2];
 911      if (item.length > 3 && item[3])
 912          target = item[3];
 913  
 914      if (link != null)
 915      {
 916          _cmClicked = false;
 917          window.open (link, target);
 918      }
 919  
 920      var menuInfo = _cmMenuList[menuID];
 921      var prefix = menuInfo.prefix;
 922      var thisMenu = cmGetThisMenu (obj, prefix);
 923  
 924      var hasChild = (item.length > 5);
 925      if (!hasChild)
 926      {
 927          if (cmIsDefaultItem (item))
 928          {
 929              if (obj.cmIsMain)
 930                  obj.className = prefix + 'MainItem';
 931              else
 932                  obj.className = prefix + 'MenuItem';
 933          }
 934          cmHideMenu (thisMenu, null, menuInfo);
 935      }
 936      else
 937      {
 938          if (cmIsDefaultItem (item))
 939          {
 940              if (obj.cmIsMain)
 941                  obj.className = prefix + 'MainItemHover';
 942              else
 943                  obj.className = prefix + 'MenuItemHover';
 944          }
 945      }
 946  }
 947  
 948  //////////////////////////////////////////////////////////////////////

 949  //

 950  // Mouse Event Support Utility Functions

 951  //

 952  //////////////////////////////////////////////////////////////////////

 953  
 954  //

 955  // move submenu to the appropriate location

 956  //

 957  function cmMoveSubMenu (obj, isMain, subMenu, menuInfo)
 958  {
 959      var orient = menuInfo.orient;
 960  
 961      var offsetAdjust;
 962  
 963      if (isMain)
 964      {
 965          if (orient.charAt (0) == 'h')
 966              offsetAdjust = menuInfo.nodeProperties.offsetHMainAdjust;
 967          else
 968              offsetAdjust = menuInfo.nodeProperties.offsetVMainAdjust;
 969      }
 970      else
 971          offsetAdjust = menuInfo.nodeProperties.offsetSubAdjust;
 972  
 973      if (!isMain && orient.charAt (0) == 'h')
 974          orient = 'v' + orient.charAt (1) + orient.charAt (2);
 975  
 976      var mode = String (orient);
 977      var p = subMenu.offsetParent;
 978      var subMenuWidth = cmGetWidth (subMenu);
 979      var horiz = cmGetHorizontalAlign (obj, mode, p, subMenuWidth);
 980      if (mode.charAt (0) == 'h')
 981      {
 982          if (mode.charAt (1) == 'b')
 983              subMenu.style.top = (cmGetYAt (obj, p) + cmGetHeight (obj) + offsetAdjust[1]) + 'px';
 984          else
 985              subMenu.style.top = (cmGetYAt (obj, p) - cmGetHeight (subMenu) - offsetAdjust[1]) + 'px';
 986          if (horiz == 'r')
 987              subMenu.style.left = (cmGetXAt (obj, p) + offsetAdjust[0]) + 'px';
 988          else
 989              subMenu.style.left = (cmGetXAt (obj, p) + cmGetWidth (obj) - subMenuWidth - offsetAdjust[0]) + 'px';
 990      }
 991      else
 992      {
 993          if (horiz == 'r')
 994              subMenu.style.left = (cmGetXAt (obj, p) + cmGetWidth (obj) + offsetAdjust[0]) + 'px';
 995          else
 996              subMenu.style.left = (cmGetXAt (obj, p) - subMenuWidth - offsetAdjust[0]) + 'px';
 997          if (mode.charAt (1) == 'b')
 998              subMenu.style.top = (cmGetYAt (obj, p) + offsetAdjust[1]) + 'px';
 999          else
1000              subMenu.style.top = (cmGetYAt (obj, p) + cmGetHeight (obj) - cmGetHeight (subMenu) + offsetAdjust[1]) + 'px';
1001      }
1002  
1003      // IE specific iframe masking method

1004      /*@cc_on

1005          @if (@_jscript_version >= 5.5)

1006              if (menuInfo.cmFrameMasking)

1007              {

1008                  if (!subMenu.cmFrameObj)

1009                  {

1010                      var frameObj = cmAllocFrame ();

1011                      subMenu.cmFrameObj = frameObj;

1012                  }

1013  

1014                  var frameObj = subMenu.cmFrameObj;

1015                  frameObj.style.zIndex = subMenu.style.zIndex - 1;

1016                  frameObj.style.left = (cmGetX (subMenu) - cmGetX (frameObj.offsetParent)) + 'px';

1017                  frameObj.style.top = (cmGetY (subMenu)  - cmGetY (frameObj.offsetParent)) + 'px';

1018                  frameObj.style.width = cmGetWidth (subMenu) + 'px';

1019                  frameObj.style.height = cmGetHeight (subMenu) + 'px';

1020                  frameObj.style.display = 'block';

1021              }

1022          @end

1023      @*/
1024      if (horiz != orient.charAt (2))
1025          orient = orient.charAt (0) + orient.charAt (1) + horiz;
1026      return orient;
1027  }
1028  
1029  //

1030  // automatically re-adjust the menu position based on available screen size.

1031  //

1032  function cmGetHorizontalAlign (obj, mode, p, subMenuWidth)
1033  {
1034      var horiz = mode.charAt (2);
1035      if (!(document.body))
1036          return horiz;
1037      var body = document.body;
1038      var browserLeft;
1039      var browserRight;
1040      if (window.innerWidth)
1041      {
1042          // DOM window attributes

1043          browserLeft = window.pageXOffset;
1044          browserRight = window.innerWidth + browserLeft;
1045      }
1046      else if (body.clientWidth)
1047      {
1048          // IE attributes

1049          browserLeft = body.clientLeft;
1050          browserRight = body.clientWidth + browserLeft;
1051      }
1052      else
1053          return horiz;
1054      if (mode.charAt (0) == 'h')
1055      {
1056          if (horiz == 'r' && (cmGetXAt (obj) + subMenuWidth) > browserRight)
1057              horiz = 'l';
1058          if (horiz == 'l' && (cmGetXAt (obj) + cmGetWidth (obj) - subMenuWidth) < browserLeft)
1059              horiz = 'r';
1060          return horiz;
1061      }
1062      else
1063      {
1064          if (horiz == 'r' && (cmGetXAt (obj, p) + cmGetWidth (obj) + subMenuWidth) > browserRight)
1065              horiz = 'l';
1066          if (horiz == 'l' && (cmGetXAt (obj, p) - subMenuWidth) < browserLeft)
1067              horiz = 'r';
1068          return horiz;
1069      }
1070  }
1071  
1072  //

1073  // show the subMenu w/ specified orientation

1074  // also move it to the correct coordinates

1075  //

1076  function cmShowSubMenu (obj, isMain, subMenu, menuInfo)
1077  {
1078      var prefix = menuInfo.prefix;
1079  
1080      if (!subMenu.cmParentMenu)
1081      {
1082          // establish the tree w/ back edge

1083          var thisMenu = cmGetThisMenu (obj, prefix);
1084          subMenu.cmParentMenu = thisMenu;
1085          if (!thisMenu.cmSubMenu)
1086              thisMenu.cmSubMenu = new Array ();
1087          thisMenu.cmSubMenu[thisMenu.cmSubMenu.length] = subMenu;
1088      }
1089  
1090      var effectInstance = subMenu.cmEffect;
1091      if (effectInstance)
1092          effectInstance.showEffect (true);
1093      else
1094      {
1095          // position the sub menu only if we are not already showing the submenu

1096          var orient = cmMoveSubMenu (obj, isMain, subMenu, menuInfo);
1097          subMenu.cmOrient = orient;
1098  
1099          var forceShow = false;
1100          if (subMenu.style.visibility != 'visible' && menuInfo.nodeProperties.effect)
1101          {
1102              try
1103              {
1104                  effectInstance = menuInfo.nodeProperties.effect.getInstance (subMenu, orient);
1105                  effectInstance.showEffect (false);
1106              }
1107              catch (e)
1108              {
1109                  forceShow = true;
1110                  subMenu.cmEffect = null;
1111              }
1112          }
1113          else
1114              forceShow = true;
1115  
1116          if (forceShow)
1117          {
1118              subMenu.style.visibility = 'visible';
1119              /*@cc_on

1120                  @if (@_jscript_version >= 5.5)

1121                      if (subMenu.cmFrameObj)

1122                          subMenu.cmFrameObj.style.display = 'block';

1123                  @end

1124              @*/
1125          }
1126      }
1127  
1128      if (!_cmHideObjects)
1129      {
1130          _cmHideObjects = 2;    // default = not hide, may change behavior later

1131          try
1132          {
1133              if (window.opera)
1134              {
1135                  if (parseInt (navigator.appVersion) < 9)
1136                      _cmHideObjects = 1;
1137              }
1138          }
1139          catch (e)
1140          {
1141          }
1142      }
1143  
1144      if (_cmHideObjects == 1)
1145      {
1146          if (!subMenu.cmOverlap)
1147              subMenu.cmOverlap = new Array ();
1148          cmHideControl ("IFRAME", subMenu);
1149          cmHideControl ("OBJECT", subMenu);
1150      }
1151  }
1152  
1153  //

1154  // reset all the menu items to class MenuItem in thisMenu

1155  //

1156  function cmResetMenu (thisMenu, prefix)
1157  {
1158      if (thisMenu.cmItems)
1159      {
1160          var i;
1161          var str;
1162          var items = thisMenu.cmItems;
1163          for (i = 0; i < items.length; ++i)
1164          {
1165              if (items[i].cmIsMain)
1166              {
1167                  if (items[i].className == (prefix + 'MainItemDisabled'))
1168                      continue;
1169              }
1170              else
1171              {
1172                  if (items[i].className == (prefix + 'MenuItemDisabled'))
1173                      continue;
1174              }
1175              if (items[i].cmIsMain)
1176                  str = prefix + 'MainItem';
1177              else
1178                  str = prefix + 'MenuItem';
1179              if (items[i].className != str)
1180                  items[i].className = str;
1181          }
1182      }
1183  }
1184  
1185  //

1186  // called by the timer to hide the menu

1187  //

1188  function cmHideMenuTime ()
1189  {
1190      _cmClicked = false;
1191      if (_cmCurrentItem)
1192      {
1193          var menuInfo = _cmMenuList[_cmCurrentItem.cmMenuID];
1194          var prefix = menuInfo.prefix;
1195          cmHideMenu (cmGetThisMenu (_cmCurrentItem, prefix), null, menuInfo);
1196          _cmCurrentItem = null;
1197      }
1198  }
1199  
1200  //

1201  // Only hides this menu

1202  //

1203  function cmHideThisMenu (thisMenu, menuInfo)
1204  {
1205      var effectInstance = thisMenu.cmEffect;
1206      if (effectInstance)
1207          effectInstance.hideEffect (true);
1208      else
1209      {
1210          thisMenu.style.visibility = 'hidden';
1211          thisMenu.style.top = '0px';
1212          thisMenu.style.left = '0px';
1213          thisMenu.cmOrient = null;
1214          /*@cc_on

1215              @if (@_jscript_version >= 5.5)

1216                  if (thisMenu.cmFrameObj)

1217                  {

1218                      var frameObj = thisMenu.cmFrameObj;

1219                      frameObj.style.display = 'none';

1220                      frameObj.style.width = '1px';

1221                      frameObj.style.height = '1px';

1222                      thisMenu.cmFrameObj = null;

1223                      cmFreeFrame (frameObj);

1224                  }

1225              @end

1226          @*/
1227      }
1228  
1229      cmShowControl (thisMenu);
1230      thisMenu.cmItems = null;
1231  }
1232  
1233  //

1234  // hide thisMenu, children of thisMenu, as well as the ancestor

1235  // of thisMenu until currentMenu is encountered.  currentMenu

1236  // will not be hidden

1237  //

1238  function cmHideMenu (thisMenu, currentMenu, menuInfo)
1239  {
1240      var prefix = menuInfo.prefix;
1241      var str = prefix + 'SubMenu';
1242  
1243      // hide the down stream menus

1244      if (thisMenu.cmSubMenu)
1245      {
1246          var i;
1247          for (i = 0; i < thisMenu.cmSubMenu.length; ++i)
1248          {
1249              cmHideSubMenu (thisMenu.cmSubMenu[i], menuInfo);
1250          }
1251      }
1252  
1253      // hide the upstream menus

1254      while (thisMenu && thisMenu != currentMenu)
1255      {
1256          cmResetMenu (thisMenu, prefix);
1257          if (thisMenu.className == str)
1258          {
1259              cmHideThisMenu (thisMenu, menuInfo);
1260          }
1261          else
1262              break;
1263          thisMenu = cmGetThisMenu (thisMenu.cmParentMenu, prefix);
1264      }
1265  }
1266  
1267  //

1268  // hide thisMenu as well as its sub menus if thisMenu is not

1269  // already hidden

1270  //

1271  function cmHideSubMenu (thisMenu, menuInfo)
1272  {
1273      if (thisMenu.style.visibility == 'hidden')
1274          return;
1275      if (thisMenu.cmSubMenu)
1276      {
1277          var i;
1278          for (i = 0; i < thisMenu.cmSubMenu.length; ++i)
1279          {
1280              cmHideSubMenu (thisMenu.cmSubMenu[i], menuInfo);
1281          }
1282      }
1283      var prefix = menuInfo.prefix;
1284      cmResetMenu (thisMenu, prefix);
1285      cmHideThisMenu (thisMenu, menuInfo);
1286  }
1287  
1288  //

1289  // hide a control such as IFRAME

1290  //

1291  function cmHideControl (tagName, subMenu)
1292  {
1293      var x = cmGetX (subMenu);
1294      var y = cmGetY (subMenu);
1295      var w = subMenu.offsetWidth;
1296      var h = subMenu.offsetHeight;
1297  
1298      var i;
1299      for (i = 0; i < document.all.tags(tagName).length; ++i)
1300      {
1301          var obj = document.all.tags(tagName)[i];
1302          if (!obj || !obj.offsetParent)
1303              continue;
1304  
1305          // check if the object and the subMenu overlap

1306  
1307          var ox = cmGetX (obj);
1308          var oy = cmGetY (obj);
1309          var ow = obj.offsetWidth;
1310          var oh = obj.offsetHeight;
1311  
1312          if (ox > (x + w) || (ox + ow) < x)
1313              continue;
1314          if (oy > (y + h) || (oy + oh) < y)
1315              continue;
1316  
1317          // if object is already made hidden by a different

1318          // submenu then we dont want to put it on overlap list of

1319          // of a submenu a second time.

1320          // - bug fixed by Felix Zaslavskiy

1321          if(obj.style.visibility == 'hidden')
1322              continue;
1323  
1324          //subMenu.cmOverlap.push (obj);

1325          subMenu.cmOverlap[subMenu.cmOverlap.length] = obj;
1326          obj.style.visibility = 'hidden';
1327      }
1328  }
1329  
1330  //

1331  // show the control hidden by the subMenu

1332  //

1333  function cmShowControl (subMenu)
1334  {
1335      if (subMenu.cmOverlap)
1336      {
1337          var i;
1338          for (i = 0; i < subMenu.cmOverlap.length; ++i)
1339              subMenu.cmOverlap[i].style.visibility = "";
1340      }
1341      subMenu.cmOverlap = null;
1342  }
1343  
1344  //

1345  // returns the main menu or the submenu table where this obj (menu item)

1346  // is in

1347  //

1348  function cmGetThisMenu (obj, prefix)
1349  {
1350      var str1 = prefix + 'SubMenu';
1351      var str2 = prefix + 'Menu';
1352      while (obj)
1353      {
1354          if (obj.className == str1 || obj.className == str2)
1355              return obj;
1356          obj = obj.parentNode;
1357      }
1358      return null;
1359  }
1360  
1361  //

1362  // A special effect function to hook the menu which contains

1363  // special effect object to the timer.

1364  //

1365  function cmTimeEffect (menuID, show, delayTime)
1366  {
1367      window.setTimeout ('cmCallEffect("' + menuID + '",' + show + ')', delayTime);
1368  }
1369  
1370  //

1371  // A special effect function.  Called by timer.

1372  //

1373  function cmCallEffect (menuID, show)
1374  {
1375      var menu = cmGetObject (menuID);
1376      if (!menu || !menu.cmEffect)
1377          return;
1378      try
1379      {
1380          if (show)
1381              menu.cmEffect.showEffect (false);
1382          else
1383              menu.cmEffect.hideEffect (false);
1384      }
1385      catch (e)
1386      {
1387      }
1388  }
1389  
1390  //

1391  // return true if this item is handled using default handlers

1392  //

1393  function cmIsDefaultItem (item)
1394  {
1395      if (item == _cmSplit || item[0] == _cmNoAction || item[0] == _cmNoClick)
1396          return false;
1397      return true;
1398  }
1399  
1400  //

1401  // returns the object baring the id

1402  //

1403  function cmGetObject (id)
1404  {
1405      if (document.all)
1406          return document.all[id];
1407      return document.getElementById (id);
1408  }
1409  
1410  //

1411  // functions that obtain the width of an HTML element.

1412  //

1413  function cmGetWidth (obj)
1414  {
1415      var width = obj.offsetWidth;
1416      if (width > 0 || !cmIsTRNode (obj))
1417          return width;
1418      if (!obj.firstChild)
1419          return 0;
1420      // use TABLE's length can cause an extra pixel gap

1421      //return obj.parentNode.parentNode.offsetWidth;

1422  
1423      // use the left and right child instead

1424      return obj.lastChild.offsetLeft - obj.firstChild.offsetLeft + cmGetWidth (obj.lastChild);
1425  }
1426  
1427  //

1428  // functions that obtain the height of an HTML element.

1429  //

1430  function cmGetHeight (obj)
1431  {
1432      var height = obj.offsetHeight;
1433      if (height > 0 || !cmIsTRNode (obj))
1434          return height;
1435      if (!obj.firstChild)
1436          return 0;
1437      // use the first child's height

1438      return obj.firstChild.offsetHeight;
1439  }
1440  
1441  //

1442  // functions that obtain the coordinates of an HTML element

1443  //

1444  function cmGetX (obj)
1445  {
1446      if (!obj)
1447          return 0;
1448      var x = 0;
1449  
1450      do
1451      {
1452          x += obj.offsetLeft;
1453          obj = obj.offsetParent;
1454      }
1455      while (obj);
1456      return x;
1457  }
1458  
1459  function cmGetXAt (obj, elm)
1460  {
1461      var x = 0;
1462  
1463      while (obj && obj != elm)
1464      {
1465          x += obj.offsetLeft;
1466          obj = obj.offsetParent;
1467      }
1468      if (obj == elm)
1469          return x;
1470      return x - cmGetX (elm);
1471  }
1472  
1473  function cmGetY (obj)
1474  {
1475      if (!obj)
1476          return 0;
1477      var y = 0;
1478      do
1479      {
1480          y += obj.offsetTop;
1481          obj = obj.offsetParent;
1482      }
1483      while (obj);
1484      return y;
1485  }
1486  
1487  function cmIsTRNode (obj)
1488  {
1489      var tagName = obj.tagName;
1490      return tagName == "TR" || tagName == "tr" || tagName == "Tr" || tagName == "tR";
1491  }
1492  
1493  //

1494  // get the Y position of the object.  In case of TR element though,

1495  // we attempt to adjust the value.

1496  //

1497  function cmGetYAt (obj, elm)
1498  {
1499      var y = 0;
1500  
1501      if (!obj.offsetHeight && cmIsTRNode (obj))
1502      {
1503          var firstTR = obj.parentNode.firstChild;
1504          obj = obj.firstChild;
1505          y -= firstTR.firstChild.offsetTop;
1506      }
1507  
1508      while (obj && obj != elm)
1509      {
1510          y += obj.offsetTop;
1511          obj = obj.offsetParent;
1512      }
1513  
1514      if (obj == elm)
1515          return y;
1516      return y - cmGetY (elm);
1517  }
1518  
1519  //

1520  // extract description from the menu item and set the status text

1521  //

1522  function cmSetStatus (item)
1523  {
1524      var descript = '';
1525      if (item.length > 4)
1526          descript = (item[4] != null) ? item[4] : (item[2] ? item[2] : descript);
1527      else if (item.length > 2)
1528          descript = (item[2] ? item[2] : descript);
1529  
1530      window.defaultStatus = descript;
1531  }
1532  
1533  //

1534  // debug function, ignore :)

1535  //

1536  function cmGetProperties (obj)
1537  {
1538      if (obj == undefined)
1539          return 'undefined';
1540      if (obj == null)
1541          return 'null';
1542  
1543      var msg = obj + ':\n';
1544      var i;
1545      for (i in obj)
1546          msg += i + ' = ' + obj[i] + '; ';
1547      return msg;
1548  }
1549  
1550  /* v2.0.3            1. Fix an issue with IE6 displaying menu over HTTPS connection.

1551                          Thanks to Paul Horton for reporting the bug and testing

1552                          possible solutions. */
1553  /* v2.0.2            1. Minor clean up and some attempts to reduce memory leak in IE. */

1554  /* v2.0.1            1. Disable iframe masking for IE7 since it is no longer necessary. */

1555  /* v2.0                1. improves the way handling flash/iframe/select boxes in IE

1556                          and firefox and Opera 9.  Hiding these elements is no

1557                          longer necessary.  For older versions of Opera, flash/iframe

1558                          still need to be hidden.

1559                      2. Improves cmDrawFromText ().  Also allows custom actions.

1560                      3. Improves clickOpen behavior.  Now once a submenu is opened,

1561                          opening other sub menus no longer requires clicking.

1562                      4. Special Effects.  This version has hooks that allow people

1563                          to install special effects to various themes.

1564                      5. For a given menu item, cmGetMenuitem(item) provides the ability

1565                          to find the corresponding DOM element.

1566                      6. Disable API.  If you know which item to disable, you can call

1567                          cmDisableItem(item, themePrefix) and cmEnableItem(item, themePrefix).

1568                          However, you will have to provide your own CSS for the item.

1569                          For purposes other than to disable an item, cmGetMenuItem (item)

1570                          is provided for locating HTML DOM element of the menu item in concern.

1571                      7. Better z-index.  Now you can specify in the theme property the

1572                          starting z-index and incremental step for submenus.

1573                      8. Allow themes to insert additional elements before and after

1574                          the sub menu table.

1575                      9. Improved themes.  More organized and easier to customize.

1576                      10. Add a flag to control hiding/nohiding objects/iframes.  By default,

1577                          only Opera before 9 hides objects.

1578                      11. Add new property options to control submenu positions to fine tune

1579                          the look.

1580                      12. It is no longer necessary to specify the theme name while calling

1581                          cmDraw and cmDrawFromText.  Currently it still accepts it, but it

1582                          will not in the future.

1583  */
1584  /* v1.4.4            1. a quick fix for a bug for _cmSplit checking.  reported by

1585                          Son Nguyen.

1586  */
1587  /* v1.4.3            1. changed how _cmSplit is handled a bit so that _cmNoClick can work

1588                          properly.  All splits in predefined themes are changed to use

1589                          _cmNoClick instead of _cmNoAction.

1590  */
1591  /* v1.4.2            1. fixed _cmNoClick mouse hoover bug.

1592                      2. fixed a statusbar text problem that cause text to disappear when

1593                          hoovering mouse within the same menu item.

1594                      3. changed the behavior of cmDrawFromText s.t. if the title of the

1595                          of a link is empty, the actual url is used as text.  To clear

1596                          this link information, title needs to be ' '.

1597  */
1598  /* v1.4.1            1. fixed a problem introduced in 1.4 where re-entering a main menu

1599                          item which doesn't have a child can disable its hover setting.

1600                          Apparently I deleted an extra line of code when I was doing

1601                          cleaning up.  Reported by David Maliachi and a few others.

1602  */
1603  /* JSCookMenu v1.4    1. fixed a minor td cell closure problem.  Thanks to Georg Lorenz

1604                         <georg@lonux.de> for discovering that.

1605                      2. added clickOpen to nodeProperties.  See _cmNodeProperties for

1606                          description.  Basically menus can be opened on click only.

1607                      3. added an ability to draw menu from an html node instead of a javascript

1608                          tree, making this script search bot friendly (I hope?).

1609  */
1610  /* JSCookMenu v1.31 1. fix a bug on IE with causes submenus to display at the top

1611                         left corner due to doctype.  The fix was provided by

1612                         Burton Strauss <Burton@ntopsupport.com>.

1613  */
1614  /* JSCookMenu v1.3    1. automatically realign (left and right) the submenu when

1615                         client space is not enough.

1616                      2. add _cmNoClick to get rid of menu closing behavior

1617                         on the particular menu item, to make it possible for things

1618                         such as search box to be inside the menu.

1619  */
1620  /* JSCookMenu v1.25    1. fix Safari positioning issue.  The problem is that all TR elements are located

1621                         at the top left corner.  Thus, need to obtain the "virtual"

1622                         position of these element could be at.

1623  */
1624  /* JSCookMenu v1.24    1. fix window based control hiding bug

1625                         thanks to Felix Zaslavskiy <felix@bebinary.com> for the fix.

1626  */
1627  /* JSCookMenu v1.23    1. correct a position bug when the container is positioned.

1628                        thanks to Andre <anders@netspace.net.au> for narrowing down

1629                        the problem.

1630  */
1631  /* JSCookMenu v1.22    1. change Array.push (obj) call to Array[length] = obj.

1632                         Suggestion from Dick van der Kaaden <dick@netrex.nl> to

1633                         make the script compatible with IE 5.0

1634                      2. Changed theme files a little to add z-index: 100 for sub

1635                         menus.  This change is necessary for Netscape to avoid

1636                         a display problem.

1637                      3. some changes to the DOM structure to make this menu working

1638                         on Netscape 6.0 (tested).  The main reason is that NN6 does

1639                         not do absolute positioning with tables.  Therefore an extra

1640                         div layer must be put around the table.

1641  */
1642  /* JSCookMenu v1.21    1. fixed a bug that didn't add 'px' as part of coordinates.

1643                         JSCookMenu should be XHTML validator friendly now.

1644                      2. removed unnecessary display attribute and corresponding

1645                         theme entry to fix a problem that Netscape sometimes

1646                         render Office theme incorrectly

1647  */
1648  /* JSCookMenu v1.2.    1. fix the problem of showing status in Netscape

1649                      2. changed the handler parameters a bit to allow

1650                         string literals to be passed to javascript based

1651                         links

1652                      3. having null in target field would cause the link

1653                         to be opened in the current window, but this behavior

1654                         could change in the future releases

1655  */
1656  /* JSCookMenu v1.1.        added ability to hide controls in IE to show submenus properly */

1657  /* JSCookMenu v1.01.    cmDraw generates XHTML code */

1658  /* JSCookMenu v1.0.        (c) Copyright 2002 by Heng Yuan */