home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / msdn_vcb / msdn / vc6intro / ieref.chm / inet401 / samples / dhtml / dhtmlmenu / msmenu.js < prev    next >
Encoding:
Text File  |  1998-06-12  |  12.0 KB  |  336 lines

  1.  
  2. var menus = new Array()
  3.  
  4. function MenuRegister(item) 
  5. {
  6.   menus[menus.length] = item
  7.   return (menus.length - 1)
  8. }
  9.  
  10. //*****************************************************************************
  11. // Function:   MenuItem
  12. // Arguments:  caption   -- a string to be used for the menu item caption
  13. //             command   -- a url string or a function reference
  14. //             image     -- a url to a 16x16 image.  Pass in null for no image
  15. //             submenu   -- a reference to a Menu object.  It will display the 
  16. //                       -- arrow to the right of the caption and display the
  17. //                       -- submenu. Pass in null for no submenu
  18. //             separator -- (true|false) display this menu item as a line
  19. // Purpose:    For each menu item in a menu, there is one MenuItem object to
  20. //             describe it.
  21. //*****************************************************************************
  22.  
  23. function MenuItem(caption, command, image, submenu, separator) 
  24. {
  25.   this.caption = caption;
  26.   this.command = command;
  27.   this.image = image;
  28.   this.submenu = submenu;
  29.   this.separator = (separator) ? true : false;
  30.   this.id = MenuRegister(this);
  31. }
  32.  
  33. //*****************************************************************************
  34. // Function:   MenuItemOnClick()
  35. // Arguments:  obj  -- This is always a reference to the table row for the menu
  36. //                     item.
  37. // Purpose:    When the user clicks on a menu item, the table row will call 
  38. //             this function.  If the MenuItem.command is a function, it gets
  39. //             run, and if it is a string (url), the window.location gets set
  40. //             to it.
  41. //*****************************************************************************
  42.  
  43. function MenuItemOnClick(obj) {
  44.   var item = menus[obj.menuid]
  45.   var menub1 = document.all['MENU' + item.parent + 'B1']
  46.  
  47.   window.event.cancelBubble = true
  48.  
  49.   if (item == null) return
  50.  
  51.   if ((typeof item.command) == 'function') item.command()
  52.   if ((typeof item.command) == 'string') window.location = item.command
  53. }
  54.  
  55. //*****************************************************************************
  56. // Function:   MenuItemOnMouseOver()
  57. // Arguments:  obj  -- This is always a reference to the table row for the menu
  58. //                     item.
  59. // Purpose:    This is the onMouseOver event for the menu table rows.  It will
  60. //             highligh the row and display the submenu if there is one.
  61. //*****************************************************************************
  62.  
  63. function MenuItemOnMouseOver(obj) {
  64.   var item = menus[obj.menuid]
  65.   var parent = menus[item.parent]
  66.   var menub1 = document.all['MENU' + item.parent + 'B1']
  67.   var fromElement = window.event.fromElement
  68.   var toElement = window.event.toElement
  69.  
  70.   window.event.cancelBubble = true
  71.  
  72.   // If just moving around within the row, then return
  73.   // This improves performance and avoids a flicker
  74.   if ((fromElement != null) && (toElement != null))
  75.   {
  76.     if (fromElement.menuid == toElement.menuid) return;
  77.   }
  78.  
  79.   obj.style.backgroundColor = '#000084'  // Change background to dark blue
  80.   obj.style.color = 'white'              // Change text to white
  81.  
  82.  
  83.   // If a submenu is open that is not for this menu item, close it
  84.   if ((parent.submenu != null) && (parent.submenu != item.submenu))
  85.   {
  86.     parent.submenu.hide()
  87.     parent.submenu = null
  88.   }
  89.  
  90.   // If this item has a submenu, open it
  91.   if ((item.submenu != null) && (parent.submenu != item.submenu)) 
  92.   {
  93.     item.submenu.top = menub1.offsetTop + obj.offsetTop;
  94.     item.submenu.left = menub1.offsetLeft + obj.offsetWidth;
  95.     item.submenu.show()
  96.     parent.submenu = item.submenu
  97.     return;
  98.   }
  99.  
  100. }
  101.  
  102. //*****************************************************************************
  103. // Function:   MenuItemOnMouseOut()
  104. // Arguments:  obj  -- This is always a reference to the table row for the menu
  105. //                     item.
  106. // Purpose:    This is the onMouseOut event for the menu table rows.  It will
  107. //             return the row to a non-highlighted state and will close the
  108. //             close the submenu unless the mouse was moved over to the submenu
  109. //*****************************************************************************
  110.  
  111. function MenuItemOnMouseOut(obj) {
  112.   var item = menus[obj.menuid]
  113.   var parent = menus[item.parent]
  114.   var toElement = window.event.toElement
  115.  
  116.   window.event.cancelBubble = true
  117.  
  118.   if ((toElement != null) && (toElement.menuid == parent.id)) { 
  119.     if ((parent.submenu != null) && (parent.submenu != item))
  120.     {
  121.       parent.submenu.hide()
  122.       parent.submenu = null
  123.     }
  124.   }
  125.  
  126.   if ((window.event.fromElement != null) && (window.event.toElement != null))
  127.   {
  128.     if (window.event.fromElement.menuid == window.event.toElement.menuid) return;
  129.  
  130.   }
  131.  
  132.   obj.style.backgroundColor = "transparent"
  133.   obj.style.color = 'black'
  134. }
  135.  
  136. //*****************************************************************************
  137. // Function:   MenuItemToString()
  138. // Arguments:  none
  139. // Purpose:    This is used by the Menu object when creating each row of the 
  140. //             menu table.
  141. //*****************************************************************************
  142.  
  143. function MenuItemToString() 
  144. {
  145.   if (this.separator)
  146.     return "<tr style='height:5px'><td colspan=3><hr></td></tr>\n"
  147.  
  148.   return "  <tr class=menuRow \n" +
  149.          "      onMouseOver='MenuItemOnMouseOver(this)'\n" +
  150.          "      onMouseOut='MenuItemOnMouseOut(this)'\n" +
  151.          "      onClick='MenuItemOnClick(this)'\n" +
  152.          "      menuid=" + this.id +
  153.          "      >\n" +
  154.          "    <td class=menuImageCell noWrap=noWrap menuid=" + this.id + ">" + 
  155.                  ((this.image != null) ? "  <img class=menuImage menuid=" + this.id + " src='" + this.image + "'>  " : "  " ) + "</td>\n" +
  156.          "    <td class=menuCaptionCell noWrap=noWrap menuid=" + this.id + ">" + this.caption + "</td>\n" +
  157.          "    <td class=menuArrowCell noWrap=noWrap menuid=" + this.id + " " + 
  158.            ((this.submenu != null) ? "style='font-family:Webdings'>4" : "style='font-family:times'>   ") + "</td>\n" +
  159.          "  </tr>\n";
  160. }
  161.  
  162. MenuItem.prototype.toString = MenuItemToString;
  163.  
  164. //*****************************************************************************
  165. // Function:   Menu
  166. // Arguments:  top   -- The top coordinate for the menu
  167. //             left  -- The left coordinate for the menu
  168. // Purpose:    This is used to create a menu
  169. //*****************************************************************************
  170.  
  171. function Menu(top, left)
  172. {
  173.   this.items = new Array()
  174.   this.top = top
  175.   this.left = left
  176.   this.id = MenuRegister(this)
  177.   this.update = true;
  178.  
  179.   MENUINSERT.insertAdjacentHTML('BeforeEnd', this.borders())
  180. }
  181.  
  182. //*****************************************************************************
  183. // Function:   MenuAddItem
  184. // Arguments:  item -- a menu item to add to the end of the menu.
  185. // Purpose:    Used to add a new menu item to the end of the menu.
  186. //*****************************************************************************
  187.  
  188. function MenuAddItem(item)
  189. {
  190.   this.items[this.items.length] = item
  191.   item.parent = this.id
  192. }
  193.  
  194. //*****************************************************************************
  195. // Function:   MenuShow
  196. // Arguments:  noDisplay  -- use true when the menu is created to initialize
  197. //                        -- the menu
  198. // Purpose:    Menu.show() is called from code to show the menu when needed and
  199. //             Menu.show(true) should be called to initialize the menu.
  200. //*****************************************************************************
  201.  
  202. function MenuShow(noDisplay)
  203. {
  204.   var menub1 = document.all['MENU' + this.id + 'B1']
  205.   var menub2 = document.all['MENU' + this.id + 'B2']
  206.  
  207.   if (this.update)
  208.   {
  209.     menub2.innerHTML = this.getTable()
  210.     this.update = false
  211.   }
  212.  
  213.   var menu = document.all['MENU' + this.id]
  214.  
  215.   menub1.style.top = this.top
  216.   menub1.style.left = this.left
  217.  
  218.   menub2.style.width = menu.offsetWidth + 2
  219.   menub2.style.height = menu.offsetHeight + 2
  220.   menub1.style.width = menu.offsetWidth + 4
  221.   menub1.style.height = menu.offsetHeight + 12
  222.  
  223.  
  224.   // BUG: some offset factors are used here to compensate for scroll bars and 
  225.   //      differences between large and small fonts
  226.   
  227.   // If the menu goes past the bottom of the body, move it up
  228.   if ((menub1.offsetTop + menub1.offsetHeight) > (MenuBodyRef.offsetHeight - 4))
  229.     menub1.style.top = MenuBodyRef.offsetHeight - menub1.offsetHeight - 4
  230.  
  231.   // If the menu goes past the right of the body, move it left
  232.   if ((menub1.offsetLeft + menub1.offsetWidth) > (MenuBodyRef.offsetWidth - 24))
  233.     menub1.style.left = MenuBodyRef.offsetWidth - menub1.offsetWidth - 24
  234.  
  235.   // If the menu is too far up, make the top at 0
  236.   if (menub1.offsetTop < 0)
  237.     menub1.style.top = 0
  238.  
  239.   // If the menu is too far left, make the left at 0
  240.   if (menub1.offsetLeft < 0)
  241.     menub1.style.left = 0
  242.  
  243.   // BUG: Removing this causes the highlight to be broken up between cells
  244.   MENUINSERT.insertAdjacentHTML('BeforeEnd', "")
  245.  
  246.   if (noDisplay) 
  247.   {
  248.     menub1.style.top = -1000
  249.     menub1.style.left = -1000
  250.   } else {
  251.     menub1.style.visibility = 'visible'
  252.   }
  253. }
  254.  
  255. //*****************************************************************************
  256. // Function:   MenuHide
  257. // Arguments:  none
  258. // Purpose:    Menu.hide() is called from code to make the menu disappear.
  259. //*****************************************************************************
  260.  
  261. function MenuHide()
  262.   var menub1 = document.all['MENU' + this.id + 'B1']
  263.   if (this.submenu != null) this.submenu.hide()
  264.  
  265.   // BUG: the use of style.display='none' causes the menu to turn into a 
  266.   //      little 5x20px gray block that never again displays correctly 
  267.  
  268.   menub1.style.visibility = 'hidden'
  269.   menub1.style.top = -1000
  270.   menub1.style.left = -1000
  271. }
  272.  
  273. //*****************************************************************************
  274. // Function:   MenuBorders()
  275. // Arguments:  none
  276. // Purpose:    The borders create the 3D effect and serve as a container for
  277. //             the menu table.
  278. //*****************************************************************************
  279.  
  280. function MenuBorders() {
  281.   return  "<div id=MENU" + this.id +"B1 style='position: absolute' class=menuBorder1 menuid=" + this.id + 
  282.                 " onClick='window.event.cancelBubble = true'>\n" +
  283.           "  <div id=MENU" + this.id +"B2 class=menuBorder2 menuid=" + this.id + ">\n" +
  284.           "  </div>\n" +
  285.           "</div>\n";
  286. }
  287.  
  288. //*****************************************************************************
  289. // Function:   MenuTable()
  290. // Arguments:  none
  291. // Purpose:    This creates the HTML table used to represent the menu.
  292. //*****************************************************************************
  293.  
  294. function MenuTable()
  295. {
  296.   var str
  297.  
  298.   str = "<table id=MENU" + this.id + "\n" +
  299.         "       cellpadding=0 cellspacing=0 border=0 class=menuTable>\n"
  300.  
  301.   for (var i=0; i < this.items.length; i++)
  302.     str += this.items[i];
  303.  
  304.   str += "</table>\n"
  305.  
  306.   return str
  307. }
  308.  
  309. Menu.prototype.addItem = MenuAddItem;
  310. Menu.prototype.borders = MenuBorders;
  311. Menu.prototype.getTable = MenuTable;
  312. Menu.prototype.show = MenuShow;
  313. Menu.prototype.hide = MenuHide;
  314.  
  315. //*****************************************************************************
  316. // Function:   MenuInit()
  317. // Arguments:  none
  318. // Purpose:    This creates the object used to insert the HTML menu objects 
  319. //             into at runtime.  It should be called only once, probably during
  320. //             The window's onLoad event and it must be called before Menu()
  321. //             objects are created.
  322. //*****************************************************************************
  323.  
  324. var MenuBodyRef;
  325. function MenuInit() {
  326.   for(var i in document.all){
  327.     if (document.all[i].tagName == 'BODY')
  328.     {
  329.       MenuBodyRef = document.all[i]
  330.    //   MenuBodyRef.insertAdjacentHTML('AfterBegin', '<div id=MENUINSERT></div>')
  331.       MenuBodyRef.insertAdjacentHTML('BeforeEnd', '<div id=MENUINSERT></div>')
  332.       break
  333.     }
  334.   }
  335. }