Menu Bar

Author Message
TNO

  • Total Posts : 2094
  • Scores: 36
  • Reward points : 0
  • Joined: 12/18/2004
  • Location: Earth
  • Status: offline
Menu Bar Tuesday, December 12, 2006 5:54 AM (permalink)
0
One of my many side projects is to create scripting libraries and components so that one doesn't have to rely on ActiveX as much as they do now for functionality. To steal the term from Brendan Eich "DeCOMtamination" is the goal. Heres the first component I'd like to share that was adapted and updated from an old script I found undocumented in the MSDN archive around the year 2000:

A menu bar for your HTA projects:

Your html page is as simple as this:

 <HTML xmlns:TNO>
 <head>
 <title> </title>
 <?IMPORT namespace="TNO" implementation="jsmenu.htc">
 <script type="text/javascript" src="menufunction.js"></script>
 <style>
 body {
 margin:0 0 0 0;
 overflow:hidden
 }
 div{
 background-color:threedface;
 border:1px solid #000000;
 position:relative;
 width:100%;
 top:0
 }
 </style>
 </head>
 
 <body scroll="no" onselectstart="return false" ondragstart="return false" oncontextmenu="return false">
 
 <div id="oContainer">
 
 <TNO:jsmenu id="File" backcolor="threedface" onsubmenu_click="CallMenuFunction();">File
 <TNO:jsmenu id="File1" backcolor="threedface">File1</TNO:jsmenu>
 <TNO:jsmenu id="File2" backcolor="threedface">File2</TNO:jsmenu>
 <TNO:jsmenu id="File3" backcolor="threedface">File3</TNO:jsmenu>
 <TNO:jsmenu id="File4" backcolor="red">File4</TNO:jsmenu>
 </TNO:jsmenu>
 
 <TNO:jsmenu id="Edit" backcolor="threedface" onsubmenu_click="CallMenuFunction();">Edit
 <TNO:jsmenu id="Edit1" backcolor="threedface">Edit1</TNO:jsmenu>
 <TNO:jsmenu id="Edit2" backcolor="green">Edit2</TNO:jsmenu>
 <TNO:jsmenu id="Edit3" backcolor="threedface">Edit3</TNO:jsmenu>
 <TNO:jsmenu id="Edit4" backcolor="threedface">Edit4</TNO:jsmenu>
 </TNO:jsmenu>
 
 <TNO:jsmenu id="View" backcolor="threedface" onsubmenu_click="CallMenuFunction();">View
 <TNO:jsmenu id="View1" backcolor="threedface">View1</TNO:jsmenu>
 <TNO:jsmenu id="View2" backcolor="threedface">View2</TNO:jsmenu>
 <TNO:jsmenu id="View3" backcolor="purple">View3</TNO:jsmenu>
 <TNO:jsmenu id="View4" backcolor="threedface">View4</TNO:jsmenu>
 </TNO:jsmenu>
 
 <TNO:jsmenu id="Favorites" backcolor="threedface" onsubmenu_click="CallMenuFunction();">Favorites
 <TNO:jsmenu id="Favorites1" backcolor="threedface">Favorites1</TNO:jsmenu>
 <TNO:jsmenu id="Favorites2" backcolor="yellow">Favorites2</TNO:jsmenu>
 <TNO:jsmenu id="Favorites3" backcolor="threedface">Favorites3</TNO:jsmenu>
 <TNO:jsmenu id="Favorites4" backcolor="threedface">Favorites4</TNO:jsmenu>
 </TNO:jsmenu>
 
 <TNO:jsmenu id="Tools" backcolor="threedface" onsubmenu_click="CallMenuFunction();">Tools
 <TNO:jsmenu id="Tools1" backcolor="brown">Tools1</TNO:jsmenu>
 <TNO:jsmenu id="Tools2" backcolor="threedface">Tools2</TNO:jsmenu>
 <TNO:jsmenu id="Tools3" backcolor="threedface">Tools3</TNO:jsmenu>
 <TNO:jsmenu id="Tools4" backcolor="threedface">Tools4</TNO:jsmenu>
 </TNO:jsmenu>
 
 <TNO:jsmenu id="Help" backcolor="threedface" onsubmenu_click="CallMenuFunction();">Help
 <TNO:jsmenu id="Help1" backcolor="white">Help1</TNO:jsmenu>
 <TNO:jsmenu id="Help2" backcolor="threedface">Help2</TNO:jsmenu>
 <TNO:jsmenu id="Help3" backcolor="threedface">Help3</TNO:jsmenu>
 <TNO:jsmenu id="Help4" backcolor="threedface">Help4</TNO:jsmenu>
 </TNO:jsmenu>
 
 </div>
 <p>
 <b>Internet Explorer 5+ Only!</b>
 </p>
 </body>
 </html>


What I've done is create a custom HTML tag called (obviously) <TNO:jsmenu>.By looking at this code you can see how easy it is to add and take away menu items.  At the top of the document you'll notice three things: First, <HTML xmlns:TNO> which defines the name of my custom Tag. Second,<?IMPORT namespace="TNO" implementation="jsmenu.htc"> which defines what code is going to make that tag work. Third, <script type="text/javascript" src="menufunction.js"></script> which tells the menu what functions to use when I click on a menu item.

The js file is simple menufunction.js:

 //this function is used to call other functions when the user clicks on a menu item.
 
 function CallMenuFunction(){
 
 var menuChoice = event.result;
 
 switch(menuChoice){
    case "File1":
        alert("Foo1");
    break;
    case "File2":
        alert("Foo2");
    break;
    case "File3":
        alert("Foo3");
    break;
    case "File4":
        alert("Foo4");
    break;
    case "Edit1":
        alert("Foo1");
    break;
    case "Edit2":
        alert("Foo2");
    break;
    case "Edit3":
        alert("Foo3");
    break;
    case "Edit4":
        alert("Foo4");
    break;
    case "View1":
        alert("Foo1");
    break;
    case "View2":
        alert("Foo2");
    break;
    case "View3":
        alert("Foo3");
    break;
    case "View4":
        alert("Foo4");
    break;
    case "Favorites1":
        alert("Foo1");
    break;
    case "Favorites2":
        alert("Foo2");
    break;
    case "Favorites3":
        alert("Foo3");
    break;
    case "Favorites4":
        alert("Foo4");
    break;
    case "Tools1":
        alert("Foo1");
    break;
    case "Tools2":
        alert("Foo2");
    break;
    case "Tools3":
        alert("Foo3");
    break;
    case "Tools4":
        alert("Foo4");
    break;
    case "Help1":
        alert("Foo1");
    break;
    case "Help2":
        alert("Foo2");
    break;
    case "Help3":
        alert("Foo3");
    break;
    case "Help4":
        alert("Foo4");
    break;
    default:
        break;
 }
 }
 


All this does is call the functions I really want to use for each menu item.

And finally the back-end engine that does all the work, The HTML Component file (jsmenu.htc):

 <PUBLIC:COMPONENT TAGNAME="jsmenu" LIGHTWEIGHT>
 <PUBLIC:ATTACH EVENT="oncontentready" ONEVENT="cReady();"/>
 <PUBLIC:ATTACH EVENT="onclick" ONEVENT="menuClick();"/>
 <PUBLIC:ATTACH EVENT="onmouseover" ONEVENT="menuItemOver();"/>
 <PUBLIC:ATTACH EVENT="onmouseout" ONEVENT="menuItemOut();"/>
 <PUBLIC:EVENT NAME="onsubmenu_click" ID="propId"/>
 <PUBLIC:DEFAULTS style="cursor:default"/>
 <PUBLIC:PROPERTY NAME="backColor" VALUE="menu"/>
 </PUBLIC:COMPONENT>
 <script type="text/javascript">
 
 /* Global Variables*/
 var minMenuWidth = 50;    // Minumum width for the children of the popUp
 var mColor = "menu";    // Default color used for the backgroundColor
 var menuHeight = 23;    // Menu height
 var defaultWidth;        // Variable to store the width of the text for an element
 var srcElem = null;        // Object to the source element which generated the click event
 var ix = "";            // Left position of the pop-up window
 var iy = "";            // Top position of the pop-up window
 var iHeight = "";        // Height of the pop-up window
 var iWidth = "";        // Width of the pop-up window
 var popUp;            // The pop-up window object
 var menuWidth = 0;        // Temporary variable to store the width of each menu item
 var maxMenuWidth = 0;        // Variable to store the maximum menuWidth
 /*
 Function : cReady
 Executed : Executes when oncontentready fires on the HTC document.
 Usage : Oncontentready is used to set initial values and styles once the content of the HTC is parsed.
 */
 function cReady(){
 // Define the style for the current element.
 if(backColor == null || backColor == ""){
    element.style.backgroundColor = mColor;
 }else{
    mColor = backColor;
    element.style.backgroundColor = mColor;
 }
 element.style.fontFamily = "Verdana";
 element.style.height = menuHeight;
 element.style.padding = 4;
 element.style.fontSize = "10px";
 element.style.border = "1px solid";
 element.style.borderColor = mColor;
 // Hide all the first-level children for the Behavior.
 if(element.children.length > 0){
    for(var i = 0; i < element.children.length; i++){
        element.children.style.fontSize = "10px";
        element.children.style.display = "none";
        element.children.style.visibility = "hidden";
        element.children.style.height = menuHeight;
    }
 }
 }
 /*
 Function : menuClick
 Executed: When the onclick event fires on the custom Element.
 Usage : Creates the pop-up window with the first-level children of the current
 element and displays the pop-up window with the first-level elements.
 Each child element will have its own events attached to it using the attach method.
 */
 function menuClick(){
 ix = 0;
 iy = 0;
 iHeight = 0;
 iWidth = 0;
 // Retrieve the source element which fired the event.
 srcElem = event.srcElement;
 srcElem.style.borderRight = "1px inset white";
 srcElem.style.borderTop = "1px inset black";
 srcElem.style.borderLeft = "1px inset black";
 srcElem.style.borderBottom = "1px inset white";
 // Hide the popup.
 hidePopup();
 // Create the popup for the current parent menu item.
 popUp = window.createPopup();
 var oPopBody = popUp.document.body;
 // Does the custom element have any children?
 if(srcElem.children.length > 0){
        ix = 0;
        iy = srcElem.offsetHeight;
    // Get pop-up window Height and Width
    iHeight = 23 * srcElem.children.length + 4;
    iWidth = defaultWidth;
    // Empty string to store the innerText of the current element's child.
    var sz = "";
    for(var j = 0; j < element.children.length; j++){
        // Store the innerText of the current element.
        sz = InnerText(element.children[j].innerHTML);
        // Set the menuWidth variable to the length of the sz string.
        menuWidth = sz.length;
        if(menuWidth > maxMenuWidth)
            maxMenuWidth = menuWidth;
        }
        iWidth = maxMenuWidth * 10;
        if(iWidth < minMenuWidth)
            iWidth = 60;
 
        // Create an opening string of a SPAN Tag.
        var popupHTML = "<SPAN style='position:absolute;" + "top:0px;" + "left:0px; height:" + iHeight + "px; width:" + iWidth + "px'>";
        // Go through all the first-level children elements and get their outerHTML and append it to the DIV Element as children. 
        for(j = 0; j < element.children.length; j++){
            // Assign the ID of the current child element to its innerText. 
            element.children[j].id = element.children[j].id;
            popupHTML += element.children[j].outerHTML + "\n";
            element.children[j].style.width = iWidth + "px";
        }
        // Add the closing SPAN Tag to the popupHTML string variable.
        popupHTML += "</" + "SPAN>";
        // Assign the HTML from above into the body of the pop-up window.
        oPopBody.innerHTML = popupHTML;
        // Assign events to each of the children in the pop-up, then show the custom elements in the pop-up.
        for(j = 0; j < oPopBody.children[0].children.length; j++){
            // Attach events to the children of the menu.
            oPopBody.children[0].children[j].onmouseover = menuChildmouseOver;
            oPopBody.children[0].children[j].onclick = menuChildClick;
            // Define the current child's style to display.
            oPopBody.children[0].children[j].style.display = "block";
            oPopBody.children[0].children[j].style.visibility = "visible";
        }
        // Define the popUp's style.
        oPopBody.style.borderLeft = "2 outset white";
        oPopBody.style.borderTop = "2 outset white";
        oPopBody.style.borderRight = "1 outset black";
        oPopBody.style.borderBottom = "1 outset black";
        oPopBody.style.position = "absolute";
        oPopBody.style.backgroundColor = mColor;
        oPopBody.style.fontFamily = "Verdana";
        // Call the hidePop function upon onmouseleave firing.
        popUp.document.body.onmouseleave = hidePopup;
 
        // Show the popUp using the show method.
        popUp.show( ix , iy , iWidth , iHeight, srcElem);
 }
 }
 
 function menuChildmouseOver(){
 // Cancel the event so that it does not bubble up to its parent.
 popUp.document.parentWindow.event.cancelBubble = true;
 // Retrieve the source element from the pop-up which fired the event.
 srcElem = popUp.document.parentWindow.event.srcElement;
 // Define the current element's style.
 srcElem.style.color = "white";
 srcElem.style.background = "highlight";
 window.status = srcElem.innerHTML;
 }
 
 var oEvent;
 function menuChildClick(){
 // Cancel the event so that it does not bubble up to its parent.
 popUp.document.parentWindow.event.cancelBubble = true;
 // Retrieve the source element from the pop-up which fired the event.
 srcElem = popUp.document.parentWindow.event.srcElement;
 // Create a new event object.
 oEvent = createEventObject();
 // Assign the event object's result property to the ID of the custom element's ID which fired this event.
 oEvent.result = srcElem.id;
 // Fire the custom element's event.
 propId.fire (oEvent);
 // Hide the pop-up.
 hidePopup();
 }
 /*
 Function : HidePopup
 Executed : When the onmouseleave event fires on the custom Element
 Usage : Hides the pop-up window for the menu.
 */
 function hidePopup(){
 if(popUp)
    if(popUp.isOpen)
        popUp.hide();
 }
 /*
 Function : menuItemOver
 Executed : When the onmouseover event fires on the custom Element
 Usage : Changes the background color & font color of the Element
 */
 function menuItemOver(){
 // Retrieve the source element.
 srcElem = event.srcElement;
 window.status = srcElem.id;
 // Set the element's style.
 srcElem.style.borderRight = "1px outset black";
 srcElem.style.borderTop = "1px outset white";
 srcElem.style.borderLeft = "1px outset white";
 srcElem.style.borderBottom = "1px outset black";
 }
 /*
 Function : menuItemOut
 Executed : When the onmouseout event fires on the custom Element
 Usage : Restores the background color & font color of the Element
 to the defaults.
 */
 function menuItemOut(){
 // Retrieve the source element.
 srcElem = event.srcElement;
 // Set the element's style.
 srcElem.style.backgroundColor = mColor;
 srcElem.style.color = "black";
 srcElem.style.border = "1px solid";
 srcElem.style.borderColor = mColor;
 }
 /*
 Function : InnerText
 Parameter : string
 Executed : Called from the mouseClick function.
 Usage : InnerText function gets the innerHTML of the custom element, which can
 contain Text + HTML; example, innerHTML of the first custom element looks like
 Start <ie:menu>Run</ie:menu> The function strips out the text until the
 first instance of "<" and returns the string.
 */
 function InnerText(szText){
 var startTag = szText.indexOf("<");
 if(szText.substr(0, startTag) == "")
    return szText;
 else
    return szText.substr(0,startTag);
 }
 </script>
 <body>
 </body>
 </html>
 


I'll let the inline comments explain themselves.

To see a live example of this in action, you can see it here:

http://thenewobjective.com/website/development/JavaScript/Components/Menubar/

I've been working on a vbscript equivalent, but haven't had any success yet. Event Listeners are causing me headaches. Perhaps one of you master vbscripters can come up with a translation. If so I would gladly host it for the indefinate future. (All credit due of course).

Stay tuned, in the works:
Context menu for your mouse.
Cross Platform File browser that relies only on WSH and an HTA
A Combo Box (Just like the address bar of the browser)
A Splash Screen (For that professional look)
A Table with a frozen header and left column just like EXCEL
<message edited by TNO on Thursday, January 17, 2008 5:28 AM>
To iterate is human, to recurse divine. -- L. Peter Deutsch
 
#1
    ginolard

    • Total Posts : 1347
    • Scores: 23
    • Reward points : 0
    • Joined: 8/11/2005
    • Status: offline
    RE: DeCOMtamination: Menu Bar Wednesday, December 13, 2006 4:57 AM (permalink)
    0
    Ahhhhhhh....HTA menus.  Bring back memories of the early ManagePC days.

    I used the Milonic menu system which is written in Jscript and is incredibly customisable.  I stumbled across the same problem with event handlers as you though.  Just couldn't get them to work
    Author of ManagePC - http://managepc.net

     
    #2

      Online Bookmarks Sharing: Share/Bookmark

      Jump to:

      Current active users

      There are 0 members and 1 guests.

      Icon Legend and Permission

      • New Messages
      • No New Messages
      • Hot Topic w/ New Messages
      • Hot Topic w/o New Messages
      • Locked w/ New Messages
      • Locked w/o New Messages
      • Read Message
      • Post New Thread
      • Reply to message
      • Post New Poll
      • Submit Vote
      • Post reward post
      • Delete my own posts
      • Delete my own threads
      • Rate post

      2000-2012 ASPPlayground.NET Forum Version 3.9