HierMenus CENTRAL: HierMenus In Progress. HierMenus 5.0.1 Release Notes (1/3)
[next] |
HierMenus 5.0.1: Release Notes
D.M Ragle, May 29, 2003
Following a few weeks of real-world use, we're pleased to introduce the first maintenance release for HM5. In this release, we correct a few Netscape 4 specific problems, a scrolling menu bug in Internet Explorer, and a minor Opera 7 glitch with the initial display of permanently displayed menus. In addition, we're introducing two parameters with this version that provide you with new choices in regards to scrolling menus.
As a reminder, though our release articles can be appreciated and may be useful to all DHTML developers and HierMenus fans, the HierMenus script itself is a licensed product and its use on your site requires a paid license agreement. Contact John Maher at [email protected] or call him at (203) 662-2889 for further information (be sure to let him know how you plan to use HierMenus and tell him a bit about your organization, as well).
Sample Pages
Our sample pages demonstrate both frames and non-frames HierMenus displays. Each sample page opens in a new window.
HM samples without frames |
IE Scrolling Bug
An HM bug was uncovered such that if you began scrolling a tall menu and then moved the mouse over another menu (which itself was not scrollable) while continuing to hold the mouse button down, (i.e., while dragging the mouse) an error would occur. IE allows the mouseovers of the menus to be fired even while the user is dragging the mouse. In HM, we've previously not correctly accounted for this possibility, and assumed in our main scrolling routines that the menu to be scrolled was the last one the mouse had rolled over--that's the global variable HM_CurrentMenu within the actual HM code. HM_CurrentMenu is set automatically whenever the mouseover handler of a menu is fired, so when the mouse rolled off a scrolling menu and onto another menu an error was triggered as HM attempted to scroll the newly rolled over menu, even though that menu may not even be scroll-capable!
In HM 5.0.1 we've corrected this bug by removing the scrolling
behavior's reliance on HM_CurrentMenu as the menu to be scrolled. Instead,
upon each entry to the main scrolling routines, a new variable, HM_ScrollMenu
is set to be the menu currently being scrolled:
// 5.01 function HM_f_StartScrollUp() { HM_ScrollMenu=this.menu; return this.menu.startScroll(true); }
For later IE browsers, we also adjusted the DoWheelScroll handler thus:
function HM_f_DoWheelScroll(){ if(!this.scrollbarsCreated) return; var ScrollUp = (HM_MenusTarget.event.wheelDelta == 120); // 5.01 HM_ScrollMenu = this; ...
Then, within the crucial DoScroll routine, we rely not on HM_CurrentMenu but instead on our new HM_ScrollMenu:
// 5.01 // var ScrollEl = HM_CurrentMenu.scrollParent; var ScrollEl = HM_ScrollMenu.scrollParent; if(up){ ScrollEl.top += incr; } else{ ScrollEl.top -= incr; } // 5.01 // HM_CurrentMenu.checkScroll(); HM_ScrollMenu.checkScroll();
Finally, as an added safety measure, we automatically stop any menu from scrolling when we roll over a menu other than the currently scrolling menu:
// 5.01 if(HM_ScrollEnabled&&(HM_CurrentMenu!=HM_ScrollMenu)) HM_f_StopScroll();
Separate Scrolling Functions
The eagle-eyed among you may have noticed the new HM_f_StartScrollUp function displayed above. We've decided to remove most of the function literals of our code, including the handlers assigned to the scrollbars themselves as demonstrated by this (line-wrapped) example:
// 5.01 // this.scrollbarTop.onmousedown = function(){ HM_CurrentMenu=this.menu; return this.menu.startScroll(true)};
Why we've decided to remove these relates to memory management within the browser. In a nutshell, when defining a handler via a function literal in this manner, the JavaScript interpreter must allocate memory to maintain the state of the local variables put in place by the function in which the literals occur. Or in other words, as our JavaScript text books remind us, nested JavaScript functions (and function literals, when they appear within other functions, are treated as nested functions in this regard) are scoped lexically, the variables that they access contain the same values as they did when the function was originally defined. If you need in depth information on this topic, you might want to read through Timothée Groleau's great article on the subject (hat tip: WebReference Update). Though written specifically for ActionScript and Flash MX use, we found it to be informative from a JavaScript perspective as well.
For a more immediate example, consider this code:
<script language="JavaScript1.2"> <!-- x=10; y=20; function someFunction(x,y) { this.firstFunction= function() { var j=prompt("Enter x Variable Name:"); alert("inside x: "+eval(j));}; this.secondFunction= function() { var j=prompt("Enter y Variable Name:"); alert("inside y: "+eval(j));}; } var newObj = new Object; newObj.f=someFunction; newObj.f(30,40); var newObj2 = new Object; newObj2.f=someFunction; newObj2.f(50,60); alert("outside x: "+x); // 10 alert("outside y: "+y); // 20 newObj.firstFunction(); // x=30 newObj.secondFunction(); // y=40 newObj2.firstFunction(); // x=50 newObj2.secondFunction(); // y=60 alert("outside x: "+x); // 10 alert("outside y: "+y); // 20 // --> </script>
which is duplicated on this test page for your review (opens in a new window, requires JavaScript1.2 or later capable browsers). At first you will see the global variables x and y reported as 10 and 20, respectively. You will then be prompted to enter the variable name that you wish to display from within the newObj.firstFunction function call. Entering a value of x in the first prompt displays the value 30, and entering y on the second displays 40, corresponding to the values passed to the function when the function literals were assigned to firstFunction within the f function. Again, entering x and y in the next two prompts results in displayed values of 50 and 60, respectively.
Since the variable name is interpreted via an eval statement, there is no way the JavaScript compiler could have known in advance that the local variables x and y would be required of the inner functions; therefore, the interpreter must be saving the values of all local variables in case they are needed by the function. These local variables are saved each time the function literal is assigned to a new object.
Nested functions can be an elegant solution in many contexts, especially if you need to refer to the "frozen" state of local variables at the point the functions are actually defined. But in the case of HM, we've previously used our function literals purely from a convenience standpoint and we didn't require them to actually refer to the local variables. To avoid the additional memory consumption required by such circumstances, we've moved each of our function literals into regular function definitions and then assigned them to handlers in the more traditional manner.
In addition to the minor memory gains this tweak provides, we also save a few bites of code; since the new HM_ScrollOver parameter (described on the next page) requires that the scrolling handlers themselves be conditionally assigned within a series of several statements. Using traditionally defined functions for this task prevents us from having to reinsert the function literals in each of these statements. While we've not encountered any problems in regards to our use of function literals in HM, it seems prudent and safe to make this minor tweak.
While we're on the scrolling topic, let's now take a look at the new menu scrolling parameters available in version 5.0.1.
Created: May 29, 2003
Revised: May 29, 2003
URL: https://www.webreference.com/dhtml/hiermenus/inprogress/3/