Click here to Skip to main content
11,412,111 members (66,745 online)
Click here to Skip to main content

XP Style JavaScript Start Menu

, 15 Sep 2011 CPOL
Rate this:
Please Sign up or sign in to vote.
Multi-level, scrollable, browser compatible, XP Style JavaScript Start Menu and Context Menu

Introduction

As the title depicts, this article is about the multi-level, scrollable, browser compatible, XP Style JavaScript Start Menu as well as context menu.

Background

The need of Start Menu started with a project requirement where there were tonnes of application links to be displayed in an organised manner. Then the solution was identified to implement the Start Menu like feature in the project, which can handle all the application links with ease.

So, I started searching for JavaScript menu API which could be moulded into the XP style start menu. I found out multiple options viz - List based menu, Tree based menu, CSS based menu etc., but none of them were suitable for my requirements. Most of the freely available menus fulfilled the requirements of multi-level menu, but none of them were scrollable.

Finally, I decided to prepare my own start menu API, and here is the result.

startmenu_screenshot.png

Using the Code

To start with, you are supposed to carry out the following steps:

  1. Include the following CSS and JS files in your HTML page HEAD section:
    <LINK REL="stylesheet" TYPE="text/css" HREF="base.css" />
    <LINK REL="stylesheet" TYPE="text/css" HREF="theme.css" />
    <SCRIPT TYPE="text/javascript" SRC="Utility.js"></SCRIPT>
    <SCRIPT TYPE="text/javascript" SRC="StartMenu.js"></SCRIPT>

    The Utility.js file is a multi-purposed file, which contains common functions which are needed for manipulating the DOM objects.

    The StartMenu.js is the key file which contains the overall functionality.

    The two CSS files viz - base.css and theme.css are for styling the menu.

  2. In the body section, create one container with a unique ID to hold all the menu items to be created.
    <DIV ID='menuContainer'></DIV>
  3. For creating menu items, you can either add a JavaScript file or you can place your code directly within the <script> open/close tag. For code readability, I have added a JavaScript file in the samples provided. Either way, you need to add the following code in your file:
    //Define a unique global variable name that depicts the StartMenu object.
    var menu = null;
    
    // Define a function that will be invoked at the time of body onload
    function bindOnLoad(e) {
    	 // function to calculate the dimensions of the screen
    	_screenDimensions();
    	 // re-calculating the dimensions on window resize
    	_addEvent(window, function(e) { _screenDimensions(); }, "resize");
    	 // disabling the text selection 
    	// (you can remove this line as per requirement)
    	_disableSelection(document.body);
    	// function which will create the menuitems as required
    	createStartMenuItems(e);
    }
    
    function createStartMenuItems(e) {
    	// Create StartMenu object with passing the unique ID 
    	// for the container created in step-2 
    	menu = new StartMenu('menuContainer'); 
    	
    	//Example API -1 for adding the menu item
    
    	//startmenuObject.add(isSeparator, menuBarId, menuId, menuText, 
    	//menuOnClick, menuTooltip, subMenuBarId, menuBarCSS, meta)
    	menu.add(false,'MenuBar01','MenuItem01','Menu Item 01',function(evt) 
    		{alert('Hi ! \n' + this.toString()); } ,
    		'Description of Menu Item 01','MenuBar02','MainMenu',
    		'any extra information about the menu item goes here. 
    		You can access this information directly in your binded function');
    	menu.add(false,'MenuBar01','MenuItem02','Menu Item 02');
    	menu.add(true,'MenuBar01'); // adding a separator between the menu items
    	menu.add(false,'MenuBar01','MenuItem03','Menu Item 03');
    
    	menu.add(false,'MenuBar02','MenuItem04','Menu Item 04 Javascript call',
    		'javascript:alert("you can call function this way also")');
    	menu.add(false,'MenuBar02','MenuItem05',
    	'Menu Item 05 Open codeproject.com','url:http://www.codeproject.com/');
    
    	menu.add(false,'MenuBar02','MenuItem06','Menu Item 06');
    	menu.add(false,'MenuBar02','MenuItem07','Menu Item 07');
    
    	// -------------------------------------------
    	//        More menuitems goes here
    	// -------------------------------------------
    
    	//Example API -2 for adding the menu item
    	var item = new MenuItemHashmap();
    	item.menuBarId = 'MenuBar02';
    	item.menuText = 'Menu item created using map';
    	item.menuOnClick = function(e) { alert('called from map.\n\n' + 
    				this.toString());}
    	item.meta = 'extra information on this item goes here';
    
    	menu.addMap(item);
    	item.clear();
    
    	item.menuBarId = 'MenuBar02';
    	item.menuText = 'SubMenu item created using map';
    	item.menuOnClick = function(e) { alert('called from next map.\n\n' + 
    				this.toString());}
    	item.meta = 'extra information on this sub item goes here';
    	menu.addMap(item);
    
    	//startmenuObject.init(menuBarId, eventObject[, isContextMenu])
    	menu.init("MenuBar01", e, false); // menuBarId is the first menuBar 
    				// to be displayed on click of start button
    }
  4. Add the onload event to the body section. Also add the start menu button or a link. Add the onclick event with the start menu button using the global StartMenu object created in step 3:
    <BODY onload="bindOnLoad(event)">
    
    <DIV ID="MenuButton" CLASS="MenuButton" ONCLICK="menu.show(null, event)">
    Start</DIV>

That's it. The Start Menu is ready.

Creating a Context Menu

Repeat step-2 and step-3 shown above for creating a context menu. The only differentiator between the Start Menu and a Context Menu lies in the API call - menuObj.init(). The value of the third parameter in this method determines whether it's a Context Menu or not. Please refer to the below API description as well as the code in the sample3.htm as well as sample3.js files attached for further details.

Understanding the API

Create a StartMenu object using the following code:

var menuObj = new StartMenu(containerDivId); 

Adding the menu items can be done in two ways:

(A) Add

menuObj.add(isSeparator, menuBarId, menuId, menuText, menuOnClick, 
	menuTooltip, subMenuBarId, menuBarCSS, meta); 

Meaning of the Parameters

  • isSeparator: (Type boolean) When set to true, the menu item is treated as a separator with no action permitted. Default is false.
  • menuBarId: The group or menu bar to which this particular menu item belongs. It is a mandatory parameter.
  • menuId: The unique Id to identify the current menu item. You can keep it blank if you don't require.
  • menuText: The text to be displayed on the start menu.
  • menuOnClick: This can be either a JavaScript function object or any string with a prefix as "javascript:" or "url:".
  • menuTooltip: The mouse over text or tooltip to be displayed on the menu item.
  • subMenuBarId: Provide the id of the menu bar which will be shown as the child of this menu item.
  • menuBarCSS:Optional menu bar CSS for formatting any particular menu bar (and not the menu item). For demonstration, please refer to the Sample2.htm file provided in the source.
  • meta: Any optional details specific to the menu item required to be stored, so as to use it while processing item click event.

When the JavaScript function binds to the menu item, you can access all this attributes using the this object. Example, this.meta, this.id, etc.

(B) MenuItemHashmap

First, create an object of MenuItemHashmap as shown below:

var itemObj = new MenuItemHashmap();

Then, set the properties of the item. These properties are the same as the parameters in above method (as shown in section (A) ). You can choose what to add and what to exclude, rest of the things will be set to default values, as shown below:

itemObj.menuBarId = 'MenuBar02';
itemObj.menuText = 'Menu item created using map';
itemObj.menuOnClick = function(e) 
	{ alert('called from map.\n\n' + this.toString());}

The next step is to add this map into the StartMenu object created previously, as shown below:

menuObj.addMap(itemObj); 

You can reuse the same item object for adding more menu items by resetting this object to default value using the following API:

itemObj.clear();

Once all the menu items are added using any of the APIs, the next thing you need to do is to initialize the StartMenu object as shown below:

menuObj.init(menuBarId, eventObject, isContextMenu);

Meaning of the Parameters

  • menuBarId: As the name depicts, the ID of the menu bar created using above API. This ID should be the first menu bar to be displayed when the start menu button is clicked.
  • eventObject: It is the event object.
  • isContextMenu: It determines whether the associated menu object will be used for creating a Start Menu or a Context Menu. If set to true, the associated menu object will be considered as a Context Menu. Default is false or null. When set to true, the value in menuBarId will be the ID of the first menu bar to be displayed when the context menu is activated.

After completing all these steps, the final step is to bind the menu with any link or button or image or text. This can be done by calling the following API on click or on mouseover of the DOM object as shown in step-4 above.

menuObj.show(null, event); 

Points of Interest

The basic concept that I applied for designing this piece of code was using the DIV and SPAN tags. There is a main DIV tag used for handling the scrolling of menu items. The next DIV tag is used to combine all the menu items, which are build using SPAN tag. So, the overall structure will look like:

  • DIV
    • DIV
      • SPAN

So, you can manipulate the outer DIV tag and apply any desired formatting. While the Sample1.htm is a simple start menu, the Sample2.htm file shows how the user defined formatting can be applied.

The other thing that I designed along with this is a Utility.js file having various commonly needed functions for handling the DOM objects. Below are the set of functions available for use:

  • function _gs(obj): Short form of Get Style
    • Get the current style of specified object. It returns a map with current height, width, top, left position, border width as well as the padding.
  • function _gol(obj): Short form of Get Offset Left
    • Get the distance of specified object in pixel from left side of the screen.
  • function _got(obj): Short form of Get Offset Top
    • Get the distance of specified object in pixel from top side of the screen.
  • function _ge(id): Short form of Get Element by Id
    • Get the DOM object for the specified id.
  • function _addEvent(target, functionref, eventType)
    • Bind any event to the specified target and invoke the referred function when the event occurs.
  • function _getEvent(type, e)
    • Get either the Source or Destination of the occurred event, based on the type specified. If type is "Src", it will return the source DOM object which generated the event. If type is "Dest", it will return the Destination DOM object where this event will end.
  • function _processStyle(el, tc, action)
    • Check, Add, or Remove the specified CSS class for a particular DOM object. Here, "el" is the DOM object, "tc" is the css class name, and "action" can be either of - "check", "add" or "remove".
  • function _screenDimensions()
    • Calculates the current screen dimensions (height and width) and stores the value in two global variables - _dh and _dw (meaning document height and document width).
  • function _disableSelection(target)
    • Disables the text selection of the specified DOM object.

NOTE

There is one more JavaScript file included in the package - MessageBox.js. This is one more utility designed by me. It has been used in the Sample2.htm file. More details on this utility and its usage can be found here.

Upgrade Notes

The code upgrade (Version 2.0) is backward compatible. If anyone has already integrated Version 1.0 in their code, they can upgrade to Version 2.0 simply by replacing the StartMenu.js file.

Features in Version 2.0:

  • Added a multi level, scrollable, cross browser context menu
  • Backward compatible with the previous version
  • Use of the same API for creating a context menu

Conclusion

Hope all of you will find this article very useful.

History

  • 19th August, 2011: Initial post
  • 23rd August, 2011: Added a note
  • 15th September, 2011: Version 2.0 with a Multi-level, scrollable context menu added

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Niral Soni
Business Analyst Tata Consultancy Services Ltd.
India India
I started my career as Java Developer. But now more inclined towards web designing, JavaScript, HTML and CSS.I have good level of expertise on Java, Oracle and JavaScript. Designing Generic components is my main expertise.
Follow on   Twitter   Google+

Comments and Discussions

 
Questionpicture? Pinmemberessco@execpc.com25-Oct-13 7:16 
GeneralMy vote of 5 PinmemberAbinash Bishoyi28-Jul-13 5:37 
GeneralFeedback required PinmemberNIRAL SONI3-Apr-12 19:45 
NewsVersion 2.0 Released !!! PinmemberNIRAL SONI15-Sep-11 5:05 
NewsComing Soon !!! PinmemberNIRAL SONI14-Sep-11 14:10 
GeneralMy vote of 5 PinmemberMember 82210367-Sep-11 21:16 
GeneralRe: My vote of 5 PinmemberNIRAL SONI8-Sep-11 11:09 
QuestionPerfect programming. Pinmembervicky.ritesh31-Aug-11 5:13 
AnswerRe: Perfect programming. PinmemberNIRAL SONI1-Sep-11 15:13 
GeneralRe: Perfect programming. Pinmembervicky.ritesh1-Sep-11 22:18 
GeneralExcellent PinmemberSunasara Imdadhusen24-Aug-11 19:55 
GeneralRe: Excellent PinmemberNIRAL SONI25-Aug-11 1:32 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web03 | 2.8.150414.5 | Last Updated 15 Sep 2011
Article Copyright 2011 by Niral Soni
Everything else Copyright © CodeProject, 1999-2015
Layout: fixed | fluid