Polymorphic Javascript?!?!?! Well kind of…

Published 23 April 07 07:35 PM

(originally posted to Absolute Opinion on October 6, 2005)

This is a really cool Javascript trick that you can use to extend existing script libraries that do not have built in extensibility hooks. That said, I must also warn against overuse of this technique as it can make your code more brittle (especially when using it for extending 3rd party server controls) and can easily turn your pages into spaghetti code. Now that the housekeeping notes are out of the way, here’s the context.

As you know, ASP.NET 2.0 has many new built in server controls. One of these that is long overdue is the Menu control. From a design perspective, I wanted to create a menu that looked and felt like the Windows XP basic menu. After dragging a new menu control onto my web form and configuring it, I was pretty close to what I wanted.

However, there is one big problem here. When I mouse over the “New” menu item and then begin hover over the items contained within the submenu, the actual “New” item should remain highlighted to preserve context. In the case of this little menu, it’s not that big of a deal. However, suppose the user was 2 or 3 levels into a menu hierarchy – being able to trace back up the menu is essential.

So after looking through the basic control properties, I concluded that I was going to need to extend the control to allow the parent menu item to retain the “hovered” look when its sub-menu was being traversed. This is when I ran into the second problem. Unless I’ve completely missed it, the menu control does not have a client side object model which allows extensibility on the DHTML side of things. So just when I was thinking about posting a whiny message on a newsgroup somewhere, the words of a good friend entered my mind – “Dude, the DHTML object model is just a big freaking hash table”. Ah ha! Interception to the rescue!

So here’s the basic idea behind the solution. In the Javascript interpreter, basically everything, from objects to functions is an entry in a globally scoped dictionary. Because of that structure, and because Javascript is loosely typed, you can substitute anything for anything else. Therefore, in order to extend the functionality in the DHTML portion of the Menu control, I will store some of the built-in Javascript functions into variables and will set those function entries with my own functions. I will then call the built-in functions from within my functions (where I can also do other stuff).

So first off, I need to see what functions I can override. This is a little more difficult in ASP.NET 2.0 because of the change in the way that stylesheet and Javascript files are stored and sent to the browser. I now have to open the source of my page and get the reference to a WebResources.axd file. By copying and pasting this reference into my browser window, I can download the stylesheet or Javascript file that is referenced.

After downloading the Javascript file that is associated with the Menu control, I see the 2 functions that I want to intercept.

  • Menu_HoverDynamic – this is the function called when a “dynamic” (popup) menu is moved over with the mouse.
  • Menu_Unhover – this is the function called whenever the user moves the mouse off of a menu item.

The algorithm for ensuring that the parent menu item retains the hover-look is straightforward and takes advantage of another built-in Javascript function owned by the Menu control. It says simply that when hovering over a menu item, find that item’s parent and fire the “onmouseover” event on that element as well. Conversely, when the user moves the mouse off of a menu item, find the item’s parent and fire the “onmouseout” event on that element. There is no need for any sort of recursive processing thanks to the event bubbling mechanism provided by the DHTML DOM.

The final code follows.

 
   1:  <script type="text/javascript" language="javascript">
   2:   
   3:  var fw_Menu_Unhover;
   4:  var fw_Menu_HoverDynamic;
   5:   
   6:  function SetupInterceptors(){   // called by onload event
   7:    fw_Menu_HoverDynamic = Menu_HoverDynamic;
   8:    Menu_HoverDynamic = my_Menu_HoverDynamic;
   9:    fw_Menu_Unhover = Menu_Unhover;
  10:    Menu_Unhover = my_Menu_Unhover;
  11:  }
  12:   
  13:  function my_Menu_HoverDynamic(item) {
  14:    fw_Menu_HoverDynamic(item);
  15:    var x = Menu_FindParentItem(item);
  16:    if(x && x.tagName.toLowerCase() != "body")
  17:      x.fireEvent("onmouseover");
  18:  }
  19:   
  20:  function my_Menu_Unhover(item) {
  21:    fw_Menu_Unhover(item);
  22:    var x = Menu_FindParentItem(item);
  23:    if(x && x.tagName.toLowerCase() != "body")
  24:      x.fireEvent("onmouseout");
  25:  }
  26:   
  27:  </script>

And there you have it. My custom functions replace the Menu control’s default functions, and are therefore called by the control’s HTML, yielding the desired result.

Comment Notification

If you would like to receive an email when updates are made to this post, please register here

Subscribe to this post's comments using RSS

Comments

# Mark said on August 30, 2007 10:35 AM:

Absolutely brillant ...

# Nidia Castro said on September 20, 2007 11:55 AM:

You are a genius!! I've been trying to figure out how to accomplish this for months!!

Thank you very much!

# nalaka said on November 7, 2007 6:44 AM:

hi,

working fine with IE but this is not working in firefox and opera. it would be better if you can make it to work at least firefox and opera browsers too.

# yupinggang said on April 25, 2008 4:06 AM:

Hi.

I have been looking for the solution for a long time.

Your code is very useful.

Could you tell me where can I find source code of the functions Menu_FindParentItem(), Menu_RootItem(), etc?

Thank you.

Leave a Comment

(required) 
(optional)
(required) 

  
Enter Code Here: Required

About hdierking

I am currently the Editor-in-Chief for MSDN Magazine. I joined Microsoft in 2006 as a product planner with the certification team at Microsoft Learning. Prior to that, I spent my career as a developer and later as an architect. My main technology passions include pretty much anything on language theory, agile development, and service-oriented architecture.
Page view tracker