The mouse capture methods setCapture and releaseCapture, and the onlosecapture event allow authors to design context menus for Web pages. Capturing mouse events allows a context menu to be created easily without firing mouse events for other objects on the page. In this sample, a context menu is created that opens when a specific object on the Web page is clicked using the right mouse button. The menu itemizes all of the properties for the object and allows the user to click on the property and obtain the value. The oncontextmenu event is cancelled so that the new context menu can be displayed.
If you are not familiar with mouse capture or Dynamic HTML, the Related Topics section provides links to additional information.
The following steps detail the procedure for creating a context menu using mouse capture.
A DIV object is used to enclose the context menu. An onclick event handler on the BODY calls the fnDetermine function. The fnDetermine function verifies that the correct conditions exist before opening the context menu.
<BODY onload = "fnInit()" onclick = "fnDetermine()" > <DIV MENUSTATUS = "false" onmouseover = "fnHighlightOn()" onmouseout = "fnHighlightOff()" ID = oContextMenu CLASS = "menu"> </DIV>
The fnDetermine function controls the functionality of the context menu and mouse capture ability. It determines if the menu is opened, closed, if mouse events are captured or released, and what other mouse events are fired. When the menu opens and begins capturing mouse events, all onclick events are handled with the fnDetermine function.
The fnDetermine function first checks the bContextKey Boolean before processing the click event. The bContextKey Boolean is set when an attempt is made to open the default context menu in Internet Explorer. If no attempt to open the default context menu was made, the function looks for a custom MENUSTATUS attribute that determines the state of the menu. If the MENUSTATUS attribute value is false, then the menu is open. When the menu is open, the setCapture method is set and the menu is populated with a list of properties from the object that was clicked. However, if the menu is already open when an object is clicked, the menu is closed and releaseCapture is invoked to remove mouse capture. If one of the listed properties in the context menu is clicked, then the value of that property is returned before the menu is closed.
function fnDetermine(){ oWorkItem=event.srcElement; if(bContextKey == "true"){ // Continue if the menu is closed. if(oContextMenu.MENUSTATUS == "false"){ // Give the menu mouse capture. oContextMenu.setCapture(); // Move the menu ten pixels right of the mouse. oContextMenu.style.top = event.clientY + 10; // Move the menu ten pixels lower than the mouse. oContextMenu.style.left = event.clientX + 10; // Clear the menu contents. oContextMenu.innerHTML = "Stand By..."; // Display the menu. oContextMenu.style.display = "block"; // Pause for one-tenth of a second so user can see the message. window.setTimeout("fnPopulate(oWorkItem)",100); // Indicate the menu is now open. oContextMenu.MENUSTATUS = "true"; event.returnValue = false; } } else{ // Continue if the menu is open. if(oContextMenu.MENUSTATUS == "true"){ // Continue if a menu item was clicked. if((oWorkItem.parentElement.id == "oContextMenu")&&(oWorkItem.getAttribute("component")=="menuitem")){ // Continue if the title wasn't clicked. if(oWorkItem.innerText.indexOf("Properties for") == -1){ // Display the value of the property. alert("Status For Object: " + oContextObject.tagName + "\nProperty: " + oWorkItem.innerText + "\nValue: " + oContextObject.tagName + "." + oWorkItem.innerText + " = " + eval("oContextObject." + oWorkItem.innerText)); // Turn off highlights. fnHighlightOff(); } } // Hide the menu. oContextMenu.style.display = "none"; // Indicate the menu is closed. oContextMenu.MENUSTATUS = "false"; // Remove mouse capture from the menu. oContextMenu.releaseCapture(); oContextMenu.innerHTML = ""; // Stop processing the event. event.returnValue = false; } } }
When the menu is opened, it is populated with a list of properties from the object that was clicked. The fnPopulate and fnAddItem functions are used to fill the context menu with this information. A second custom attribute, COMPONENT, is used to identify the individual values returned to the context menu. The COMPONENT attribute is mainly used to identify the object when it is highlighted and to obtain the value of the property for the object.
// Return list of properties to the context menu. function fnPopulate(oTarget){ oContextMenu.innerHTML = ""; oContextObject = oTarget; iMenuItems=0; fnAddItem(oContextMenu,"Properties for: <B>" + oTarget.tagName + "</B>"); for(i in oTarget){ if((eval("oTarget." + i) != "[object]") && (eval("oTarget." + i) != "") && (eval("oTarget." + i) != null)){ fnAddItem(oContextMenu,i); } } for(i in oTarget.style){ if((eval("oTarget.style." + i)!= "") && (eval("oTarget.style." + i)!= null)){ fnAddItem(oContextMenu,"style." + i); } } } function fnAddItem(oTargetGroup,sContent){ oTargetGroup.innerHTML += '< SPAN COMPONENT = "menuitem" ID = oMenuItem' + iMenuItems + '>' + sContent + '</SPAN><BR>'; iMenuItems++; }
A menu STYLE is defined so the context menu can be moved anywhere on the Web page. The menu is moved in the fnDetermine function every time it is opened. The style provides both appearance and absolute positioning.
<STYLE> .menu{ cursor: hand; display: none; cursor: hand; position: absolute; top: 0; left: 0; background-color: "#CFCFCF"; border: "1 solid"; border-top-color: "#EFEFEF"; border-left-color: "#EFEFEF"; border-right-color: "#505050"; border-bottom-color: "#505050"; font-size: 8pt; font-family: Arial;} </STYLE>
When the right mouse button is clicked, the default context menu is cancelled and the new context menu opens. A Boolean is set to true when the default menu is opened. The fnDetermine function is called to open the new menu. The Boolean is set back to false and the default context menu is cancelled.
bContextKey = "false"; function fnSuppress(){ bContextKey=true; fnDetermine(); bContextKey=false; return false; }
For a menu to be functional it needs to provide some feedback to the user. Highlighting menu items when the mouse moves over them provides such feedback.
The fnHighLightOn is very specific about remaining within the client area. When mouse capture is enabled on the menu in the fnDetermine function, the srcElement property on the event object returns values for areas within the browser window but not outside the client area. Because these areas aren't exposed to the DHTML Object Model, they are avoided.
function fnHighlightOn(){ // Continue if the mouse is inside the client area. if((event.clientX > 0) && (event.clientY > 0) && (event.clientX < document.body.offsetWidth) && (event.clientY < document.body.offsetHeight)){ oWorkItem=event.srcElement; if(oWorkItem.getAttribute("component") == "menuitem"){ oWorkItem.style.backgroundColor = "#CCCCFF"; oWorkItem.style.color = "#FF0000"; } } }
The methods setCapture and releaseCapture, and the onlosecapture event are invaluable resources for developing dynamic content. Capturing mouse events allows authors to develop menus that better respond to user interaction.
The following links provide additional information about mouse capture and DHTML.Mouse Capture
Dynamic HTML
How To Create a Mouse Capture Drop-down Menu